-
-
Save xpn/e95a62c6afcf06ede52568fcd8187cc2 to your computer and use it in GitHub Desktop.
#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; | |
} |
pabloko
commented
Apr 12, 2018
BTW @pabloko the code you have shared is taken from this web page and it is C++ not C!
https://codingvision.net/calling-a-c-method-from-c-c-native-process
I have compiled and run it without problem.
But I need a similar solution in C.
@blue-devil if you need c compilant code, you can resort to use the CINTERFACE+COBJMACROS from winapi
ICLRMetaHost *metaHost = NULL;
ICLRRuntimeInfo *runtimeInfo = NULL;
ICLRRuntimeHost *runtimeHost = NULL;
if (CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID *)&metaHost) == S_OK)
if (ICLRMetaHost_GetRuntime(metaHost, L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID *)&runtimeInfo) == S_OK)
if (ICLRRuntimeInfo_GetInterface(runtimeInfo, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID *)&runtimeHost) == S_OK)
if (ICLRRuntimeHost_Start(runtimeHost) == S_OK)
{
DWORD pReturnValue;
ICLRRuntimeHost_ExecuteInDefaultAppDomain(runtimeHost, L"C:\\random.dll", L"dllNamespace.dllClass", L"ShowMsg", L"It works!!", &pReturnValue);
IUnknown_Release(runtimeInfo);
IUnknown_Release(metaHost);
IUnknown_Release(runtimeHost);
}
@pabloko You made my day, thank you!
#pragma comment(lib, "mscoree.lib")
#include <stdio.h>
#define CINTERFACE
#define COBJMACROS
#include <metahost.h>
#include <Unknwnbase.h>
int main()
{
ICLRMetaHost* metaHost = NULL;
ICLRRuntimeInfo* runtimeInfo = NULL;
ICLRRuntimeHost* runtimeHost = NULL;
if (CLRCreateInstance(&CLSID_CLRMetaHost, &IID_ICLRMetaHost, (LPVOID*)&metaHost) == S_OK)
if (ICLRMetaHost_GetRuntime(metaHost,L"v4.0.30319", &IID_ICLRRuntimeInfo, (LPVOID*)&runtimeInfo) == S_OK)
if (ICLRRuntimeInfo_GetInterface(runtimeInfo, &CLSID_CLRRuntimeHost, &IID_ICLRRuntimeHost, (LPVOID*)&runtimeHost) == S_OK)
if (ICLRRuntimeHost_Start(runtimeHost) == S_OK)
{
DWORD pReturnValue;
ICLRRuntimeHost_ExecuteInDefaultAppDomain(
runtimeHost,
L"random.dll",
L"dllNamespace.dllClass",
L"ShowMsg",
L"It works!!",
&pReturnValue);
printf("GetFlag returned: %016X\n", pReturnValue);
IUnknown_Release(runtimeInfo);
IUnknown_Release(metaHost);
IUnknown_Release(runtimeHost);
}
return 0;
}
I am using Visual Studio 2022.
@pabloko one more question. "ShowMsg" is returning int and the code above works fine. What if it returns string? I have tried several things but i could not get any solution?
@blue-devil if you check the documentation for ICLRRuntimeHost::ExecuteInDefaultAppDomain:
The invoked method must have the following signature:
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.