我试图在将dll注入到远程进程后卸载它,我使用CreateRemoteThread在该远程进程中调用“LoadLibraryA”,这意味着线程函数是“LoadLibraryA”。现在,我使用“GetExitCodeThread”来获取线程的退出代码。
代码片段:
// create remote thread to invoke LoadLibraryA
HANDLE tThread = CreateRemoteThread(remoteProcess, NULL, 0, LoadLibraryAAddr, remoteAddress, 0, NULL);
if (!tThread) {
cout << "failed to create remote thread" << endl;
return 1;
}
// wait for remote thread stop
HMODULE exitCode;
WaitForSingleObject(tThread, INFINITE);
cout << "successfully load library" << endl;
GetExitCodeThread(tThread, (LPDWORD)&exitCode);
// clean up, call FreeLibrary to unload dll
LPTHREAD_START_ROUTINE freeLibraryAddr = (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "FreeLibrary");
if (NULL == freeLibraryAddr) {
cout << "failed to get freeLibrary address" << endl;
return 1;
}
“GetExitCodeThread”声明:
BOOL GetExitCodeThread(
[in] HANDLE hThread,
[out] LPDWORD lpExitCode
);
根据文档的描述,lpExitCode应该取“LoadLibraryA”的返回值,即“LoadLibraryA”加载的dll的基地址。然后我创建另一个远程进程来调用“FreeLibrary”来卸载这个dll,但失败了。
经过调试,我发现了问题:lpExitCode只保存了“LoadLibraryA”返回的低32位值。
高32位是0xcccccccc,因为变量“exitCode”在栈中,是用0xcc初始化的。这个结果很容易解释:“lpExitCode”的类型是LPDWORD,它是一个指向32位值的指针,因此它只能影响“exitCode”的低32位
一开始的代码在x86环境下运行得很好,因为x86环境下的地址是32位长,可以正确传递。但是,我在 x64 环境中运行它,“exitCode”仅获取 dll 基地址的低 32 位,然后传递给 FreeLibrary 并导致调用失败。结果,dll仍然位于该远程进程的内存中,这与我的预期不符。
那么有没有办法使用GetExitCodeThread或其他一些windows api来获取64位retuen值,希望有人能回复。
HMODULE getTargetModuleBase(HANDLE processHandle, string targetModuleName) {
// get all moduels in the process
HMODULE moduleHandleList[1024];
DWORD cbNeeded;
BOOL ret = EnumProcessModules(processHandle, moduleHandleList, sizeof(moduleHandleList), &cbNeeded);
if (!ret) {
cout << "failed to enum process modules" << endl;
return NULL;
}
if (cbNeeded > sizeof(moduleHandleList)) {
cout << "to many modules" << endl;
return NULL;
}
DWORD processCount = cbNeeded / sizeof(HMODULE);
// traverse to find target module
char moduleName[1024];
for (DWORD i = 0; i < processCount; i++) {
GetModuleBaseNameA(processHandle, moduleHandleList[i], moduleName, 1024);
if (!strncmp(targetModuleName.c_str(), moduleName, targetModuleName.size())) {
return moduleHandleList[i];
}
}
return NULL;
}
使用EnumProcessModules和GetModuleBaseNameA遍历并比较已加载模块的名称,可以找到目标模块并返回其baseAddress,然后将baseAddress传递给freeLibrary以卸载模块。
上面的代码只是一个简单的例子,如果没有一些错误句柄,moduleHandleList和moduleHandleList在保存结果时可能会超出范围,请注意。您可以检查 EnumProcessModules 和 GetModuleBaseNameA 的返回值来决定是否使用更大的数组再次调用这些 api。