如何在Win32中从函数指针获取模块句柄?

11
我正在为一个虚拟机编写本地调用绑定,其中一个特性是能够在运行时通过名称查找标准libc函数。在Windows上这有点麻烦,因为我需要获取到当前进程中已加载的msvcrt模块的句柄。通常这是msvcrt.dll,但也可能是其他变体(如msvcr100.dll等),如果使用不同名称的变体,则对GetModuleHandle("msvcrt")的调用可能会失败。
我想要做的是反向查找,从libc中获取一个函数指针(我有很多),并获取提供它的模块的句柄。基本上就像这样:
HANDLE hlibc = ReverseGetModuleHandle(fprintf); // Any func from libc should do the trick
void *vfunc = GetProcAddress(hlibc);

在win32 API中有这样一种东西吗,而不需要降到手动遍历进程句柄和符号表的级别?相反地,如果我过于考虑问题,有没有更简单的方法在win32上按名称查找libc函数?

3个回答

23

获取模块句柄的文档方式是使用GetModuleHandleEx函数。

HMODULE hModule = NULL;

if(GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
       GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, // behave like GetModuleHandle
       (LPCTSTR)address, &hModule))
{
    // hModule should now refer to the module containing the target address.
}

12
MEMORY_BASIC_INFORMATION mbi;
HMODULE mod;
if (VirtualQuery( vfunc, &mbi, sizeof(mbi) ))
{
    mod = (HMODULE)mbi.AllocationBase;
}

1
这是一种常用的快速查找代码地址对应模块句柄的方法。模块句柄可以追溯到Windows 16位版本,而在32位和64位的Windows版本中,模块句柄只是内存分配的基址。我从未见过这种方法失效,并且在我的代码中也使用了相同的技巧。 - Hans Passant
这种方法确实有效,至少在我尝试过的几个Windows变体上是如此。我不喜欢它没有很好的文档记录,但我已经在我的代码中填满了描述它所做的注释,并且我只能希望一切顺利。谢谢! - Whiteknight
2
已经有文档记录的方法存在。请查看我的回答。 - Arty

-1

不幸的是,你必须像你担心的那样逐个模块地进行。但这并不太糟糕。这里有一个在记事本中编写的代码的想法:

MODULEENTRY32 me = {0};
HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, 0 );

me.dwSize = sizeof me;
Module32First( hSnapshot, &me );
  if( me.modBaseAddr <= funcPtr &&
      ( me.modBaseAddr + me.modBaseSize ) > funcPtr ) {
    ...
    break;
  }
do {
} while( Module32Next( hSnapshot, &me ) );

CloseHandle( hSnapshot );

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接