如何检测使用 LoadLibraryEx 加载的模块
Posted
技术标签:
【中文标题】如何检测使用 LoadLibraryEx 加载的模块【英文标题】:How do I detect a module loaded using LoadLibraryEx 【发布时间】:2019-07-05 15:54:50 【问题描述】:我需要使用诸如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 标志,那么:
如果使用此值,系统会将文件映射到调用 进程的虚拟地址空间,就好像它是一个数据文件一样。没有什么是 done 执行或准备执行映射文件。因此,你 不能调用 GetModuleFileName、GetModuleHandle 或 GetProcAddress 与此 DLL。
也许这是我的问题,但不管是什么原因 - 有没有人知道在使用本机/c++ 代码的进程中找到托管 DotNet dll 的方法?
谢谢!
编辑: 根据来自 Castorix 在 cmets 中的建议,我尝试使用 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);
这段代码找到了很多模块,但没有找到 System.Windows.Forms.dll
【问题讨论】:
向我们展示您的代码。 使用我的 DLL 注入器,我在目标进程中使用 EnumProcessModules (+ GetModuleInformation) @JesperJuhl 'if (GetModuleHandle(L"System.Windows.Forms.dll") != 0) ..." 但即使存在该 dll 也会返回 0 @PaulMacGuiheen 请不要在评论中发布代码。 编辑您的问题并在其中包含代码。 请将其设为minimal reproducible example。 @Castorix 我读到了这个函数,但是文档说它是用于其他进程的,而我对我的代码正在执行的同一个进程感兴趣 【参考方案1】:好的,这是一个回答的尝试(或者真的只是一个太长的评论,抱歉)。
就我个人而言,我从未在“进程资源管理器”窗格中看到托管的 .NET DLL,但可能没有仔细/经常查看。但是,我可以(并且总是可以)看到的是 NGENed 图像 (*.ni.dll
)。
还要注意这里存在System.Data.dll
,它不是 NGENed,而是混合模式程序集,包含本机代码和托管代码。
因此可以得出结论,您在这里只能看到 NGEN 和混合模式“程序集”,因为它们仍然由 LoadLibrary
或 LoadLibraryEx
加载。
还请注意我的评论,我将其复制在这里以便于访问:
我认为 CLR 不使用 LoadLibrary,这可以解释为什么你 使用您描述的 API 无法“看到”它们。实际上, CLR 4 Does Not Use LoadLibrary to Load Assemblies 是相关的博客条目。您可以随时查看来源 (CoreCLR,但不重要),特别是关于它是如何完成的。一世 没有真正好的地方,但你可以开始 here 然后离开它。请改用 ICorDebug 接口。
以下是上面链接的博客条目中的一些相关引述:
您可能会问自己:……谁在乎?好吧,首先它很好 要知道。我没有注意到上面的公共服务公告。 然而,这是一个实现细节——CLR 程序集甚至不是 保证用文件实现,更不用说里面的DLL文件了 使用 LoadLibrary Win32 API 加载的特定格式。
但是,有几个工具和场景已经开始依赖 事实上,CLR 使用 LoadLibrary 加载程序集。例如, 直到 CLR 4,如果您想知道加载了哪些 .NET 程序集 在您的过程中,一个相当可靠的启发式方法是启动 Sysinternals Process Explorer 并查看给定的 DLLs 视图 过程。这不适用于 CLR 4,您可以在此处看到:
坦率地说,我不知道 Process Explorer 如何在您的情况下设法显示程序集(不是 NGENed 和非混合模式) - 您正在观看 CLR2 进程。但是,请注意 PE 不仅使用 Win32 API。它还使用 WMI,并且可能还直接使用 CLR 来获取更多信息。例如,“进程属性/.NET 程序集”和“进程属性/.NET 性能”选项卡很可能分别使用 ICorDebug
/ICorProfile
和性能计数器/ETW。
您可能还需要使用这些接口中的一个,或者一般来自unmanaged Debugging API 或unmanaged API 的其他接口。
不管是什么,我不认为EnumProcessModules
等会因为上述原因让你到达那里。
【讨论】:
有趣的是你应该提到原生图像 :) 我需要检测 DotNet 程序集的原因是 ngen.exe 没有运行(因为我不会进入),所以原生图像是不在过程中。我在使用您提到的本机 CLR 接口方面取得了很大进展,并将很快使用相关代码进行更新。感谢您的帮助!【参考方案2】:补充上述答案并提供相关代码;无法使用像 EnumProcessModules
这样的本机函数来检测非 ngen 的 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 接口的信息:
ICLRMetaHost ICLRRuntimeInfo ICorRuntimeHost _AppDomain _Assembly【讨论】:
以上是关于如何检测使用 LoadLibraryEx 加载的模块的主要内容,如果未能解决你的问题,请参考以下文章
win32ctypes.pywin32.pywintypes.error: (2, ‘LoadLibraryEx‘, ‘系统找不到指定的文件。‘)
LoadLibraryEx() 中更改的搜索路径 (LOAD_WITH_ALTERED_SEARCH_PATH) 是啥
IIS7.5 HTTP 错误 500 调用loadlibraryex失败的解决方法
加载C:\Program Files\Common Files\\RunTime\0701\Intel32\ctor.dll时出错找不到指定的模