在实际加载DLL之前,我在自己的延迟加载钩子中使用dliNotePreLoadLibrary
来验证要加载的DLL的代码签名。为了避免它执行任何代码,我使用LoadLibraryExA(...,...,LOAD_LIBRARY_AS_DATAFILE)
加载它(钩子只提供ANSI名称,所以没关系),并在验证后卸载它,这样它就可以作为一个带有代码的DLL加载。
通过调试器中的代码,我可以看到我收到了一个句柄,并且这个句柄是<baseaddress>+1
,正如“数据模块”所期望的那样。但是,一旦我试图在库函数中将这个句柄传递给GetModuleFileName
(这也是为什么我不能传递名称,只传递模块句柄的原因),该函数将返回0
,GetLastError给我ERROR_MOD_NOT_FOUND
。但是,模块被加载了,所以肯定被找到了。而且,这是在当前的过程中,所以访问“目标进程”在这里没有问题。
因此,我想为什么不使用VirtualQuery
来检索我刚刚加载的DLL的实际基址(MEMORY_BASIC_INFORMATION::BaseAddress
) (以防<baseaddress>+1
出现问题),但结果仍然是一样的:ERROR_MOD_NOT_FOUND
。
我没有主意了。有人知道这是怎么回事吗?
测试平台: Windows 7 SP1,x64 (最新补丁)
下面是代码:
FARPROC WINAPI MyDliHook(unsigned dliNotify, PDelayLoadInfo pdli)
{
switch(dliNotify)
{
case dliNotePreLoadLibrary:
if(0 == lstrcmpiA(pdli->szDll, "DLLNAME.dll"))
{
HMODULE hVerifiedDll = LoadLibraryExA(pdli->szDll, NULL, LOAD_LIBRARY_AS_DATAFILE);
if(hVerifiedDll)
{
MEMORY_BASIC_INFORMATION mbi;
if(0 != VirtualQuery(hVerifiedDll, &mbi, sizeof(mbi)));
{
VerifyModuleSignature((HMODULE)mbi.BaseAddress, pdli->szDll);
}
FreeLibrary(hVerifiedDll);
}
}
break;
default:
break;
}
return NULL;
}
PfnDliHook __pfnDliNotifyHook2 = MyDliHook;
函数VerifyModuleSignature
首先调用GetModuleFileName
来检索文件名,然后在该步骤中失败。我验证了使用创建流程的.exe
,代码签名验证工作正常。
侧注:我已经验证了ERROR_MOD_NOT_FOUND
错误来自于GetModuleFileName
,而不是,例如,来自对LoadLibraryExA
的早期调用。为了确保没有得到“受污染的”最后一个错误代码,我在调用SetLastError(ERROR_SUCCESS)
之前调用了GetModuleFileName
。
发布于 2012-08-21 06:56:37
正如在MSDN中所解释的,当使用GetModuleHandle时,不能使用LOAD_LIBRARY_AS_DATAFILE检索模块:
如果使用此值,则系统将该文件映射到调用进程的虚拟地址空间,就好像它是数据文件一样。对执行或准备执行映射的文件不做任何操作。因此,不能用这个DLL调用像GetModuleFileName、GetModuleHandle或GetProcAddress这样的函数。
编辑:实际上比这个答案更接近原因。虽然这个答案重申了MS的观点,但它并没有给出理由。但是,原因是GetModuleFileName
基本上遍历了PEB
的LDR_MODULE
列表,并且只有在“加载代码”时才会填充详细信息。
https://stackoverflow.com/questions/12044691
复制相似问题