问题
In my app, I hook some Windows API calls by patching PE Import Access table. I enumerate all modules in a process using this Tool Help API (Module32First,Module32Next).
One of the functions I hook is LoadLibrary. In it, I load module by calling the original LoadLibrary and then I enumerate again all the loaded modules to detect new loaded modules I have not hooked yet (because LoadLibrary can load the specified module plus all the modules it depends on).
It works fine most of the time.
But recently I got a crash dump in which app crashes attempting to patch IAT table of the module that does not exist in the dump. There were 56 modules before LoadLibrary call and 58 modules after it (according to Tool Help API). But in my crash dump there are 57 modules only.
What happens? Can Tool Help API return modules which are loading currently and not initialized completely yet? In the call stack I see HMODULE value and this value does not belong to any module's address in the dump.
JFYI: I use Visual C++ 2013.
Some code:
Enum modules:
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);
}
Then for the each new module I call this code:
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 definition:
#define RvaToAddr(type, base, offset) ((type)(DWORD_PTR(base) + DWORD_PTR(offset)))
回答1:
I've created a test project which 100% reproduces the problem. Now it's confirmed that Tool Help API returns modules which are not completely initialized yet.
Source from the project:
::CreateThread (0, 0, _threadStuff, 0, 0, 0);
Sleep (100);
for (;;)
{
auto m = LoadLibrary (L"mshtml.dll");
assert (m);
FreeLibrary (m);
}
2nd thread:
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;
}
I continued execution after the crash (using a special technique) and a bit time later I get a normal list with the modules. See screenshot.
Now all it's required is to detect such a situation and just try the attempt a bit later.
来源:https://stackoverflow.com/questions/29880869/tool-help-api-returns-invalid-hmodule