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

时间:2015-04-26 17:21:26

标签: c++ windows debugging winapi

在我的应用程序中,我通过修补PE Import Access表来挂钩一些Windows API调用。 我使用此工具帮助API(Module32First,Module32Next)枚举流程中的所有模块。

我挂钩的一个功能是LoadLibrary。在其中,我通过调用原始LoadLibrary来加载模块,然后我再次枚举所有已加载的模块以检测我尚未挂接的新加载模块(因为LoadLibrary可以加载指定的模块以及它所依赖的所有模块)。

大部分时间都可以正常工作。

但是最近我遇到了一个崩溃转储,其中app崩溃试图修补转储中不存在的模块的IAT表。在LoadLibrary调用之前有56个模块,在它之后有58个模块(根据Tool Help API)。但在我的崩溃转储中只有57个模块。

会发生什么? Can Tool Help API可以返回当前正在加载但尚未完全初始化的模块吗?在调用堆栈中,我看到HMODULE值,该值不属于转储中任何模块的地址。

JFYI:我使用的是Visual C ++ 2013。

一些代码:

枚举模块:

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);
}

然后,对于每个新模块,我都会调用此代码:

bool ReplaceIATfunc (HMODULE hTarget, /*other args here*/)
{
    PIMAGE_DOS_HEADER pDosHeader = PIMAGE_DOS_HEADER (hTarget);
    PIMAGE_NT_HEADERS pNTHeaders = RvaToAddr (PIMAGE_NT_HEADERS, hTarget, pDosHeader->e_lfanew);

    // crash is here
    IMAGE_DATA_DIRECTORY &impDir = pNTHeaders->OptionalHeader.DataDirectory [IMAGE_DIRECTORY_ENTRY_IMPORT];

    if (impDir.VirtualAddress == NULL || impDir.Size == 0)
            return false;

    /* ... */
}

RvaToAddr定义:

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

1 个答案:

答案 0 :(得分:0)

我创建了一个100%重现问题的测试项目。现在,它已确认Tool Help 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;
}

我在崩溃后继续执行(使用特殊技术),稍后我获得了模块的正常列表。见截图。

enter image description here

现在所需要的只是检测这种情况,稍后尝试尝试。

相关问题