我正在尝试为自己制作一个从进程中提取/释放dll的工具。我已经体验过LoadLibrary和注入,但这次逻辑似乎并不适用。 这是我的代码:
HMODULE findModuleOffset(HANDLE proc, char *mod_name) {
//Finds module address in specified process. 0 if not found
HMODULE hMods[2048];
DWORD modules_byte_size;
if (EnumProcessModules(proc, hMods, sizeof(hMods), &modules_byte_size))
{
for (unsigned long i = 0; i < (modules_byte_size / sizeof(HMODULE)); i++) {
CHAR module_name[MAX_PATH];
// Get the full path to the module's file.
if (GetModuleFileNameExA(proc, hMods[i], module_name, sizeof(module_name))) {
if (strcmp(strrchr(module_name,'.')+1,"exe")!=0 && compareExeName(module_name, mod_name)) {
return hMods[i];
}
}
}
}
return 0;
}
bool compareExeName(char *path, char *partial_name) {
//This will substract the filename from path and compare it with partial_name
char *lastSlash = strrchr(path, '\\') + 1;
if (lastSlash != NULL && strstr(lastSlash, partial_name) == lastSlash) return 1;
return 0;
}
void unload_all_dll(char *dll_name) {
DWORD process_ids[2048];
DWORD process_byte_size; //size of filled process_ids in BYTES (after the call)
DWORD process_count; //count of all elements in process_ids
HMODULE ext_dll_module;
HANDLE opened_process;
HANDLE Hthread;
DWORD thread_exit_code = 1;
CHAR exe_path[1024];
if (EnumProcesses(process_ids, sizeof(process_ids), &process_byte_size)) {
process_count = process_byte_size / sizeof(DWORD);
for (int i = 0; i < process_count; i++) {
thread_exit_code = 0;
if ((opened_process = OpenProcess(PROCESS_ALL_ACCESS, false, process_ids[i])) == NULL) continue;
GetModuleFileNameExA(opened_process, 0, exe_path, MAX_PATH);
if ((ext_dll_module = findModuleOffset(opened_process, dll_name)) != 0) {
while (thread_exit_code == 0) {
if ((Hthread = CreateRemoteThread(opened_process, NULL, 0, (LPTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandleA("kernel32.dll"), "FreeLibrary"), (void*)ext_dll_module, 0, NULL)) == NULL) {
cout<<"Process closed meanwhile or dll unloaded";
break; //process has closed meanwhile
}
while (WaitForSingleObject(Hthread, 1000) == WAIT_TIMEOUT);
GetExitCodeThread(Hthread, &thread_exit_code);
}
cout << "Dll unloaded from " << exe_path << endl;
}
}
}
}
警告:某些变量名称可能令人困惑(我很着急)
但每次我尝试弹出一个DLL都会崩溃(当然,只有包含指定dll的应用程序)。我测试了所有可能的东西,一切似乎都很好:findModuleOffset
返回的模块地址很好(根据进程资源管理器给出的值进行检查)。我没有想到createremotethread或thread_exit_code
的返回值是什么,因为应用程序崩溃(它将dll驱逐出来......所以......)。你能救我吗?
答案 0 :(得分:4)
(从评论中移出)
鉴于目标进程中有线程正在运行卸载的dll中的代码,它们将在dll被释放后立即崩溃 - 毕竟,CPU正在执行的代码页面正在被取消映射!
为了避免这个问题,必须以某种方式通知正在运行的线程,因此它们可以在卸载dll之前终止; Windows提供了许多IPC方法,一种很少使用的方法特别适用于这种情况,即mailslots。
当注入dll时,创建的“主”线程将创建一个具有众所周知名称的邮件槽,并定期检查是否有任何消息供他使用。当你想要卸载dll时,不要粗暴地注入一个强力释放dll的线程,只要问你的“内部人”:向邮件槽发一条消息,要求它终止 1 。
线程将看到邮件槽中有消息,注意可能终止在目标进程内启动的其他线程(可以使用共享原子变量+ WaitForSingleObject
),并且当清理时完成后,调用FreeLibraryAndExitThread
自杀最后一个线程和dll。
备注强>