Skip to content

Instantly share code, notes, and snippets.

@odzhan
Last active February 2, 2024 08:05
Show Gist options
  • Save odzhan/594bd0ff1c7a90baf61dd5189982d8b6 to your computer and use it in GitHub Desktop.
Save odzhan/594bd0ff1c7a90baf61dd5189982d8b6 to your computer and use it in GitHub Desktop.
Resolve dynamic address of Process.Environment.Exit in CLR host process using C++
//
// Resolve dynamic address of Process.Environment.Exit in CLR host process using C++
//
// Based on :
// https://www.mdsec.co.uk/2020/08/massaging-your-clr-preventing-environment-exit-in-in-process-net-assemblies/
// https://github.com/yamakadi/clroxide/blob/214222d578bf62b4c7fc860125268f4eecb9f331/examples/patch_exit.rs
// https://github.com/kyleavery/inject-assembly/blob/8db977c0fd1da039df920f9dd4840d4a3ec2aa2c/src/scmain.c
// https://github.com/TheWover/donut/blob/master/loader/test/rdt.cpp ;)
#include <windows.h>
#include <oleauto.h>
#include <mscoree.h>
#include <comdef.h>
#include <propvarutil.h>
#include <metahost.h>
#include <cstdio>
#include <cstdint>
#include <cstring>
#include <cstdlib>
#include <sys/stat.h>
#import "mscorlib.tlb" raw_interfaces_only
#import "shdocvw.dll"
#pragma comment(lib, "mscoree")
#define FREE_BSTR(str) if (str) SysFreeString(str);
#define FREE_COM(iface) if (iface) iface->Release();
void
resolve_proc_exit(mscorlib::_AppDomainPtr appPtr) {
BSTR strAssembly = NULL, strEnvironment = NULL, strExit = NULL;
BSTR strMethodInfo = NULL, strProperty = NULL, strRuntimeHandle = NULL;
BSTR strGetFunctionPointer = NULL;
mscorlib::_MethodInfoPtr exitMeth = NULL, getPtrMeth = NULL;
mscorlib::_AssemblyPtr asmPtr = NULL;
mscorlib::_TypePtr envPtr = NULL, runtime_method_handle = NULL, method_info = NULL;
mscorlib::_PropertyInfoPtr method_handle = NULL;
SAFEARRAY *sav = NULL;
do {
strAssembly = SysAllocString(L"mscorlib");
HRESULT hr = appPtr->Load_2(strAssembly, &asmPtr);
if (FAILED(hr)) {
printf("Load_2(mscorlib) failed : %08lX\n", hr);
break;
}
strEnvironment = SysAllocString(L"System.Environment");
hr = asmPtr->GetType_2(strEnvironment, &envPtr);
if (FAILED(hr)) {
printf("GetType_2(System.Environment) failed : %08lX\n", hr);
break;
}
strExit = SysAllocString(L"Exit");
hr = envPtr->GetMethod_6(
strExit,
&exitMeth);
if (FAILED(hr)) {
printf("GetMethod_6(Exit) failed : %08lX\n", hr);
break;
}
strMethodInfo = SysAllocString(L"System.Reflection.MethodInfo");
hr = asmPtr->GetType_2(strMethodInfo, &method_info);
if (FAILED(hr)) {
printf("GetType_2(System.Reflection.MethodInfo) failed.\n");
break;
}
strProperty = SysAllocString(L"MethodHandle");
hr = method_info->GetProperty_7(strProperty, &method_handle);
if (FAILED(hr)) {
printf("GetProperty_7(MethodHandle) failed : %08lX\n", hr);
break;
}
VARIANT vtExit;
V_VT(&vtExit) = VT_UNKNOWN;
V_UNKNOWN(&vtExit) = (IUnknown*)exitMeth;
_variant_t method_handle_value;
sav = SafeArrayCreateVector(VT_EMPTY, 0, 0);
hr = method_handle->GetValue(vtExit, sav, &method_handle_value);
if (FAILED(hr)) {
printf("GetValue(MethodHandle) failed : %08lX\n", hr);
break;
}
strRuntimeHandle = SysAllocString(L"System.RuntimeMethodHandle");
hr = asmPtr->GetType_2(strRuntimeHandle, &runtime_method_handle);
if (FAILED(hr)) {
printf("GetType_2(System.RuntimeMethodHandle) failed : %08lX\n", hr);
break;
}
strGetFunctionPointer = SysAllocString(L"GetFunctionPointer");
hr = runtime_method_handle->GetMethod_6(
strGetFunctionPointer,
&getPtrMeth);
if (FAILED(hr)) {
printf("GetMethod_6(GetFunctionPointer) failed.\n");
break;
}
sav = SafeArrayCreateVector(VT_VARIANT, 0, 0);
VARIANT vtFuncPtr={0};
hr = getPtrMeth->Invoke_3(method_handle_value, sav, &vtFuncPtr);
if (FAILED(hr)) {
printf("GetMethod_6(GetFunctionPointer) failed.\n");
break;
}
void* pFunction = vtFuncPtr.byref;
printf("Process.Environment.Exit : %p\n", pFunction);
} while (false);
if (sav) SafeArrayDestroy(sav);
FREE_BSTR(strAssembly);
FREE_BSTR(strEnvironment);
FREE_BSTR(strExit);
FREE_BSTR(strMethodInfo);
FREE_BSTR(strProperty);
FREE_BSTR(strRuntimeHandle);
FREE_BSTR(strGetFunctionPointer);
FREE_COM(exitMeth);
FREE_COM(getPtrMeth);
FREE_COM(asmPtr);
FREE_COM(envPtr);
FREE_COM(runtime_method_handle);
FREE_COM(method_handle);
FREE_COM(method_info);
}
void
get_proc_env_exit(void) {
HRESULT hr;
ICLRMetaHost *icmh = NULL;
ICLRRuntimeInfo *icri = NULL;
ICorRuntimeHost *icrh = NULL;
IUnknown *iu = NULL;
mscorlib::_AppDomainPtr ad = NULL;
do {
hr = CLRCreateInstance(
CLSID_CLRMetaHost,
IID_ICLRMetaHost,
(LPVOID*)&icmh);
if (FAILED(hr)) {
printf("CLRCreateInstance() failed : %08lX\n", hr);
break;
}
hr = icmh->GetRuntime(
L"v4.0.30319",
IID_ICLRRuntimeInfo,
(LPVOID*)&icri);
if (FAILED(hr)) {
printf("GetRuntime() failed : %08lX\n", hr);
break;
}
BOOL loadable;
hr = icri->IsLoadable(&loadable);
if (FAILED(hr) || !loadable) {
printf("IsLoadable() failed : %08lX\n", hr);
break;
}
hr = icri->GetInterface(
CLSID_CorRuntimeHost,
IID_ICorRuntimeHost,
(LPVOID*)&icrh);
if (FAILED(hr)) {
printf("ICLRRuntimeInfo::GetInterface() failed : %08lX\n", hr);
break;
}
hr = icrh->Start();
if (FAILED(hr)) {
printf("ICorRuntimeHost::Start() failed : %08lX\n", hr);
break;
}
hr = icrh->GetDefaultDomain(&iu);
if (FAILED(hr)) {
printf("ICorRuntimeHost::GetDefaultDomain() failed : %08lX\n", hr);
break;
}
hr = iu->QueryInterface(IID_PPV_ARGS(&ad));
if (FAILED(hr)) {
printf("IUnknown::QueryInterface(AppDomain) failed : %08lX\n", hr);
break;
}
resolve_proc_exit(ad);
} while (false);
if (ad) ad->Release();
if (iu) iu->Release();
if (icrh) { icrh->Stop(); icrh->Release(); }
if (icri) icri->Release();
if (icmh) icmh->Release();
}
int main(int argc, char *argv[]) {
get_proc_env_exit();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment