获取进程基地址时GetModuleHandle只返回进程的,如果想获取当前库的需使用GetModuleHandleEx
今天本想获取加载的dll的基地址,调用GetModuleHandle()时总是得不到正确的结果,细看了下<<windows核心编程>>,里面说如果在DLL中执行GetModuleHandle (NULL),返回的是可执行文件基地址。获取DLL自身基地址需用GetModuleHandleEx (…);实测了下,果然…
注意:exe项目和dll项目均为Unicode字符集,和wprintf相关
dll项目代码
头文件声明
API_DECLSPEC void printLibraryModule();
源文件函数实体
void API_DECLSPEC printLibraryModule()
{
HMODULE hModEx = NULL;
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (PCTSTR)printLibraryModule, &hModEx); //获一个函数地址
wprintf(TEXT("Library With GetModuleHandleEx =0x%x\r\n"), hModEx);
FreeLibrary(hModEx);
HMODULE hMod = GetModuleHandle(NULL);
if (!hMod)
{
DWORD dw = GetLastError();
}
else
wprintf(TEXT("With GetModuleHandle(NULL)=0x%x\r\n"), hMod);
FreeLibrary(hMod);
}
然后建个控制台程序,部分借用网友代码
#include "../printModule/printLibraryModule.h"
void printModule()
{
HMODULE hMod = NULL;
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (PCTSTR)printModule, &hMod); //获一个函数地址
wprintf(TEXT("With GetModuleHandleEx =0x%x\r\n"), hMod);
FreeLibrary(hMod);
}
int main(int argc, char* argv[])
{
HMODULE hMod = GetModuleHandle(NULL);
if (!hMod)
{
DWORD dw = GetLastError();
}
else
wprintf(TEXT("With GetModuleHandle(NULL)=0x%x\r\n"), hMod);
FreeLibrary(hMod);
printModule();
printLibraryModule();
return 0;
}
然后得出的结果:
所以调用GetModuleHandle还是GetModuleHandleEx自已心里要清楚,特别是dll注入等场合。
另外,网友还整理了几条相关规律:
1、HMODULE 和 HINSTANCE 只有在16运行环境上才有区别,其它环境相同,均为线程基地址。遇到了直接转换
2、GetModuleHandle (NULL) 多次调用引用次数不增加,无论调多少次一次FreeLibrary()就行。
3、GetModuleHandleEx(dwFlags, lpModuleName, phModule)
dwFlags:
如果是0,则当调用该函数时,模块的引用计数自动增加,调用者在使用完模块句柄后,必须调用一次FreeLibrary
如果是GET_MODULE_HANDLE_EX_FLAG_PIN,则模块一直映射在调用该函数的进程中,直到该进程结束,不管调用多少次FreeLibrary
如果是GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,则同GetModuleHandle相同,不增加引用计数
如果是GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,则lpModuleName是模块中的一个地址