我需要使用GetModuleHandle或GetModuleFileName之类的Windows函数来确定是否在执行代码的同一进程中加载了特定的dll。
我正在寻找的一个模块是System.Windows.Forms.dll,但是即使将其加载到进程中……(在这里您可以使用Process Explorer看到它)
GetModuleHandle仍然找不到它!
HMODULE modHandle = GetModuleHandle(L"System.Windows.Forms.dll");
GetLastError()返回ERROR_MOD_NOT_FOUND
如果函数成功,则返回值是指定模块的句柄。 如果函数失败,则返回值为NULL。
我认为这可能与CLR如何加载这些dll有关。我在LoadLibraryEx上看到一条注释,如果使用LOAD_LIBRARY_AS_DATAFILE标志,则:
如果使用此值,则系统会将文件映射到调用中 进程的虚拟地址空间,就好像它是数据文件一样。没有什么是 完成执行或准备执行映射文件。因此,你 无法调用诸如GetModuleFileName,GetModuleHandle或 带有此DLL的GetProcAddress。
也许这是我的问题,但无论原因如何,有人知道使用本机/ c ++代码在进程中查找托管DotNet dll的方法吗?
谢谢!
编辑: 根据Castorix在评论中的建议,我尝试使用EnumProcessModules:
HMODULE modules[100];
void* hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, GetCurrentProcessId());
if (hProcess)
{
DWORD bytesNeeded;
BOOL rc = EnumProcessModules(hProcess, modules, sizeof(modules), &bytesNeeded);
if (rc)
{
int count = (int)(bytesNeeded / sizeof(HMODULE));
for (int i = 0; i < count; i++)
{
wchar_t moduleName[260];
GetModuleFileName(modules[i], moduleName, 260);
}
}
}
CloseHandle(hProcess);
答案 0 :(得分:1)
好的,这是一个答案的尝试(或者实际上只是太长的评论,对不起)。
就个人而言,我从未在Process Explorer窗格中看到托管的.NET DLL,但可能看起来不够辛苦/不够频繁。但是,我可以(并且始终可以看到)是NGENed图像(*.ni.dll
)。
请注意这里还存在System.Data.dll
,它不是NGENed的,而是混合模式的程序集,其中包含本机代码和托管代码。
因此可以得出一个结论,您在这里只能看到NGENed模式和混合模式“程序集”,因为它们仍然是由LoadLibrary
或LoadLibraryEx
加载的。
也请注意我的评论,为了便于访问,我在这里复制了它:
我认为CLR不使用LoadLibrary,这可以解释为什么 无法使用您描述的API“查看”它们。事实上, CLR 4 Does Not Use LoadLibrary to Load Assemblies 是相关的博客条目。您可以随时检查来源 (CoreCLR,但不重要),特别是关于它是如何完成的。一世 没有真正好的地方,但是你可以开始 here 然后从中去。请改用ICorDebug接口。
以下是上面链接的博客条目中的一些相关引语:
您可能会问自己:…谁在乎?好,首先很好 要知道。我还没有注意到上述公共服务公告。 这是实现细节,但是,CLR程序集甚至没有 保证使用文件实现,更不用说DLL文件了 使用LoadLibrary Win32 API加载的特定格式。
但是,有几种工具和方案需要依赖 CLR使用LoadLibrary加载程序集。例如, 如果您想知道加载了哪些.NET程序集,则最高为CLR 4 在您的过程中,相当可靠的启发式方法是 Sysinternals Process Explorer并查看给定的DLLs视图 处理。如您在此处看到的那样,这不适用于CLR 4:
坦率地说,我不知道Process Explorer如何在您的情况下显示程序集(不是NGENed和非混合模式)-您看到的 appart正在查看CLR2进程。但是,请记住,PE不仅使用Win32 API。它还使用WMI,可能还直接使用CLR获取更多信息。例如,“进程属性/.NET程序集”和“进程属性/.NET性能”选项卡最有可能分别使用ICorDebug
/ ICorProfile
和性能计数器/ ETW。
您可能还需要使用这些接口中的一个,或通常使用unmanaged Debugging API或unmanaged API中的其他接口。
无论是什么原因,我都不认为EnumProcessModules
等会因为上述原因而使您到达那里。
答案 1 :(得分:0)
要添加到上述答案中并提供相关代码;无法使用EnumProcessModules
之类的本机函数来检测非ngeneded的DotNet dll,而不得不使用C ++接口连接CLR。
这里有更多信息:https://blogs.msdn.microsoft.com/calvin_hsia/2013/12/05/use-reflection-from-native-c-code-to-run-managed-code/与该特定问题最相关的代码是:
HRESULT GetAssemblyFromAppDomain(_AppDomain* pAppDomain, LPCWSTR wszAssemblyName, _Deref_out_opt_ _Assembly **ppAssembly)
{
*ppAssembly = NULL;
// get the assemblies into a safearray
SAFEARRAY *pAssemblyArray = NULL;
HRESULT hr = pAppDomain->GetAssemblies(&pAssemblyArray);
if (FAILED(hr))
{
return hr;
}
// put the safearray into a smart ptr, so it gets released
CComSafeArray<IUnknown*> csaAssemblies;
csaAssemblies.Attach(pAssemblyArray);
size_t cchAssemblyName = wcslen(wszAssemblyName);
long cAssemblies = csaAssemblies.GetCount();
for (long i=0; i<cAssemblies; i++)
{
CComPtr<_Assembly> spAssembly;
spAssembly = csaAssemblies[i];
if (spAssembly == NULL)
continue;
CComBSTR cbstrAssemblyFullName;
hr = spAssembly->get_FullName(&cbstrAssemblyFullName);
if (FAILED(hr))
continue;
// is it the one we want?
if (cbstrAssemblyFullName != NULL &&
_wcsnicmp(cbstrAssemblyFullName,
wszAssemblyName,
cchAssemblyName) == 0)
{
*ppAssembly = spAssembly.Detach();
hr = S_OK;
break;
}
}
if (*ppAssembly == 0)
{
hr = E_FAIL;
}
return hr;
}
这里有一些有关CLR接口的信息: