Last active
June 12, 2024 05:01
-
-
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++
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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