C++ 通过调用CreateRemoteThread:崩溃弹出dll
我正在尝试为自己制作一个从进程中提取/释放DLL的工具。我已经体验过LoadLibrary和注入,但这次的逻辑似乎不适用。 这是我的代码:C++ 通过调用CreateRemoteThread:崩溃弹出dll,c++,dll,C++,Dll,我正在尝试为自己制作一个从进程中提取/释放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
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;
}
}
}
}
HMODULE findModuleOffset(HANDLE proc,char*mod_name){
//在指定进程中查找模块地址。如果未找到,则为0
HMODULE-hMods[2048];
DWORD模块\字节\大小;
if(enumProcessModule(proc、hMods、sizeof(hMods)和modules\u byte\u size))
{
对于(无符号长i=0;i<(模块\字节\大小/sizeof(HMODULE));i++){
字符模块名称[最大路径];
//获取模块文件的完整路径。
if(GetModuleFileNameExA(proc,hMods[i],module_name,sizeof(module_name))){
if(strcmp(strrchr(模块名称,'.')+1,“exe”)!=0和&compareExeName(模块名称,模块名称)){
返回hMods[i];
}
}
}
}
返回0;
}
bool compareExeName(字符*路径,字符*部分名称){
//这将从路径中减去文件名,并将其与部分名称进行比较
char*lastsslash=strrchr(路径“\\”)+1;
if(lastSlash!=NULL&&strstrstr(lastSlash,partial_name)==lastSlash)返回1;
返回0;
}
无效卸载所有dll(字符*dll\U名称){
德沃德进程[2048];
DWORD process_byte_size;//已填充的进程ID的大小(字节)(在调用之后)
DWORD进程\u计数;//进程\u ID中所有元素的计数
HMODULE ext_dll_模块;
处理开放式流程;
处理Hthread;
DWORD线程出口代码=1;
CHAR exe_路径[1024];
if(枚举进程(进程ID、进程ID和进程字节大小)){
进程计数=进程字节大小/大小(DWORD);
for(int i=0;i
假设目标进程中有线程正在运行正在卸载的dll中的代码,那么它们将在dll释放后立即崩溃—毕竟,CPU正在执行的代码页正在被取消映射
为了避免该问题,必须以某种方式通知正在运行的线程,以便它们可以在卸载dll之前终止;Windows提供了许多IPC方法,其中一种很少使用的方法特别适合这种情况,即
当dll被注入时,被创建的“主”线程将创建一个具有众所周知的名称的邮箱,并定期检查是否有任何消息给他。当你想卸载dll时,与其粗暴地注入一个线程来强制释放dll,不如问你的“内部人员”:向邮箱发送消息,要求其终止1
线程将看到邮件槽中有一条消息,注意可能终止在目标进程内启动的其他线程(可以使用共享原子变量+WaitForSingleObject
)并且,当清理完成后,调用freellibraryandexitthread
删除最后一个线程和dll
注释
MailSlot的一个特别有趣的特性是,如果使用相同的名称多次创建它们,则发送到该名称的消息将传递给所有这些名称,因此,如果您希望同时关闭所有注入的DLL,这将大大简化控制程序-甚至不需要枚举e运行进程
嗯,除非你自己注入dll,在目标进程实际使用的dll上调用freebrary
,否则代码将以崩溃告终……不过,在尝试从目标进程卸载dll之前,你始终可以将调试器附加到目标进程,并查看它崩溃的位置。是的,确实,我应该提到。dll是我的并且大部分是空的。其中有几个循环。这是原因吗?freelibrary不应该强制卸载dll吗?我现在无法使用调试器进行检查。明天我将返回一个响应。如果目标进程中有线程正在该dll中运行代码(那些循环?),当然它会崩溃-这不会有任何不同,运行的线程无法知道它们正在运行的代码正在从内存中取消映射。确定更多详细信息:我使用CreateRemoteThread注入该dll,因此有一个。在dll中,我创建了另外两个线程,其中一个线程正在检查注册表的值(在循环中).就是这样。那么这些线程是导致问题的还是第一个线程(用于注入)?