C++ 工具帮助API返回无效的HMODULE?

C++ 工具帮助API返回无效的HMODULE?,c++,windows,debugging,winapi,C++,Windows,Debugging,Winapi,在我的应用程序中,我通过修补PE导入访问表来钩住一些Windows API调用。 我使用这个工具帮助API Module32First、Module32Next枚举流程中的所有模块 我钩住的函数之一是LoadLibrary。在其中,我通过调用原始LoadLibrary来加载模块,然后再次枚举所有加载的模块,以检测尚未连接的新加载的模块,因为LoadLibrary可以加载指定的模块以及它所依赖的所有模块 它大部分时间都很好用 但最近我得到了一个崩溃转储,其中应用程序在尝试修补转储中不存在的模块的I

在我的应用程序中,我通过修补PE导入访问表来钩住一些Windows API调用。 我使用这个工具帮助API Module32First、Module32Next枚举流程中的所有模块

我钩住的函数之一是LoadLibrary。在其中,我通过调用原始LoadLibrary来加载模块,然后再次枚举所有加载的模块,以检测尚未连接的新加载的模块,因为LoadLibrary可以加载指定的模块以及它所依赖的所有模块

它大部分时间都很好用

但最近我得到了一个崩溃转储,其中应用程序在尝试修补转储中不存在的模块的IAT表时崩溃。根据工具帮助API,LoadLibrary调用前有56个模块,调用后有58个模块。但在我的垃圾堆里只有57个模块

会发生什么?该工具能否帮助API返回当前正在加载但尚未完全初始化的模块?在调用堆栈中,我看到HMODULE值,该值不属于转储中的任何模块地址

我使用Visual C++ 2013。< /P> 一些代码:

枚举模块:

typedef std::set <HMODULE> my_loaded_modules_data_t;
void my_get_loaded_modules_data (my_loaded_modules_data_t &data)
{
    data.clear ();
    CToolhelp th (TH32CS_SNAPMODULE, GetCurrentProcessId ());
    MODULEENTRY32 me = { sizeof (me) };
    for (BOOL bOk = th.ModuleFirst (&me); bOk; bOk = th.ModuleNext (&me))
        data.insert (me.hModule);
}
RvaToAddr定义:

#define RvaToAddr(type, base, offset) ((type)(DWORD_PTR(base) + DWORD_PTR(offset)))

我创建了一个测试项目,它100%地再现了这个问题。现在已经确认,工具帮助API返回的模块尚未完全初始化

项目来源:

::CreateThread (0, 0, _threadStuff, 0, 0, 0);

Sleep (100);

for (;;)
{
    auto m = LoadLibrary (L"mshtml.dll");
    assert (m);
    FreeLibrary (m);
}
第二个线程:

DWORD WINAPI _threadStuff (LPVOID)
{
    for (;;)
    {
        my_loaded_modules_data_t modules;
        my_get_loaded_modules_data (modules);

        for (const auto module : modules)
        {
            PIMAGE_DOS_HEADER pDosHeader = PIMAGE_DOS_HEADER (module);
            // crash is here
            assert (pDosHeader->e_magic == IMAGE_DOS_SIGNATURE);
        }
   }
   return 0;
}
崩溃后,我使用一种特殊的技术继续执行,过了一段时间,我得到了模块的正常列表。见截图


现在只需检测到这种情况,稍后再试。

您有代码吗?你的代码可能有缺陷吗?我不知道。似乎没有。。它经过了很好的测试,并在另一个流行项目上使用了好几年。GetModuleInformation API函数可用于验证模块的句柄是否有效。这就是答案。我询问了工具帮助API的模块枚举行为。答案是这样一个无效的HMODULE实际上并不是无效的,而是指向一个当前正在加载的模块,因此还不能完全访问。需要等待它完全加载。为什么这不是答案?那就提供你的吧!不幸的是,GetModuleInformation不能保证在所有情况下模块都已完全初始化。您找到更好的解决方案了吗?
DWORD WINAPI _threadStuff (LPVOID)
{
    for (;;)
    {
        my_loaded_modules_data_t modules;
        my_get_loaded_modules_data (modules);

        for (const auto module : modules)
        {
            PIMAGE_DOS_HEADER pDosHeader = PIMAGE_DOS_HEADER (module);
            // crash is here
            assert (pDosHeader->e_magic == IMAGE_DOS_SIGNATURE);
        }
   }
   return 0;
}