Created
April 11, 2018 21:34
-
-
Save xpn/e95a62c6afcf06ede52568fcd8187cc2 to your computer and use it in GitHub Desktop.
A quick example showing loading CLR via native code
This file contains hidden or 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
#include "stdafx.h" | |
int main() | |
{ | |
ICLRMetaHost *metaHost = NULL; | |
IEnumUnknown *runtime = NULL; | |
ICLRRuntimeInfo *runtimeInfo = NULL; | |
ICLRRuntimeHost *runtimeHost = NULL; | |
IUnknown *enumRuntime = NULL; | |
LPWSTR frameworkName = NULL; | |
DWORD bytes = 2048, result = 0; | |
HRESULT hr; | |
printf("CLR via native code.... @_xpn_\n\n"); | |
if (CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&metaHost) != S_OK) { | |
printf("[x] Error: CLRCreateInstance(..)\n"); | |
return 2; | |
} | |
if (metaHost->EnumerateInstalledRuntimes(&runtime) != S_OK) { | |
printf("[x] Error: EnumerateInstalledRuntimes(..)\n"); | |
return 2; | |
} | |
frameworkName = (LPWSTR)LocalAlloc(LPTR, 2048); | |
if (frameworkName == NULL) { | |
printf("[x] Error: malloc could not allocate\n"); | |
return 2; | |
} | |
// Enumerate through runtimes and show supported frameworks | |
while (runtime->Next(1, &enumRuntime, 0) == S_OK) { | |
if (enumRuntime->QueryInterface<ICLRRuntimeInfo>(&runtimeInfo) == S_OK) { | |
if (runtimeInfo != NULL) { | |
runtimeInfo->GetVersionString(frameworkName, &bytes); | |
wprintf(L"[*] Supported Framework: %s\n", frameworkName); | |
} | |
} | |
} | |
// For demo, we just use the last supported runtime | |
if (runtimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&runtimeHost) != S_OK) { | |
printf("[x] ..GetInterface(CLSID_CLRRuntimeHost...) failed\n"); | |
return 2; | |
} | |
if (runtimeHost == NULL || bytes == 0) { | |
wprintf(L"[*] Using runtime: %s\n", frameworkName); | |
} | |
// Start runtime, and load our assembly | |
runtimeHost->Start(); | |
printf("[*] ======= Calling .NET Code =======\n\n"); | |
if (runtimeHost->ExecuteInDefaultAppDomain( | |
L"myassembly.dll", | |
L"myassembly.Program", | |
L"test", | |
L"argtest", | |
&result | |
) != S_OK) { | |
printf("[x] Error: ExecuteInDefaultAppDomain(..) failed\n"); | |
return 2; | |
} | |
printf("[*] ======= Done =======\n"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@blue-devil if you check the documentation for ICLRRuntimeHost::ExecuteInDefaultAppDomain:
static int pwzMethodName (String pwzArgument)
So this method is a convenient helper to launch a typical main entry point.
If you want to be able to bind both languages you should use ICLRRuntimeHost::SetHostControl and create your own implementation of IHostControl that exposes an interface that can be used in managed code, create a managed AppDomainManager that also implements such interface, then obtain the ICLRControl and set the AppDomainManager managed to back your unmanaged interface. Theres a tutorial you can follow here:
https://www.mode19.net/posts/clrhostingright/
This may sound a bit complicated but it works. If youre just looking to comunicate between managed and unmanaged code, check out UnamanagedExports nuget package, wich allows you to generate native dll libraries from managed code, wich lowers the complexity of this process by a magnitude.