详细解读:远程线程注入DLL到PC版微信
一、远程线程注入的原理
1、其基础是在 windows 系统中,每个 .exe 文件在双击打开时都会加载 kernel32.dll 这个系统模块,该模块中有一个 loadlibrary() 函数,可以将dll文件加载到自身进程中。
2、这样,就可以用 createremotethread() 函数创建一个远程线程,让目标进程调用loadlibrary() 来加载我们自己写的dll 。createremotethread() 有这几个参数比较关键:a:想要注入的进程的句柄,这里可以通过openprocess()得到; b:想要运行的函数,本例中当然是 loadlibrary() 啦; c: 所运行函数的参数,本例中是自己写的dll的存放路径。
3、那么,怎么让 loadlibrary() 找到自己写的dll的存放路径呢?这就需要在内存中开辟一块空间,把路径写入进去。这要先用 virtualallocex()开辟一块空间,然后用writeprocessmemory() 函数把dll路径写进去。
4、小结:总的来说,就是:先在目标进程的内存空间里开辟一块新地方,往新地方里面写入dll的路径,再创建远程线程找到loadlibrary() 函数,并在刚才开辟的新地方中读取dll路径,进而加载我们自己写的dll。
二、代码实现(含详细注释)
1 #include <iostream> 2 #include "stdlib.h" 3 #include <tchar.h> 4 #include <windows.h> 5 6 bool inject(dword dwid, wchar* szpath)//参数1:目标进程pid 参数2:dll路径 7 { 8 //一、在目标进程中申请一个空间 9 10 11 /* 12 【1.1 获取目标进程句柄】 13 参数1:想要拥有的进程权限(本例为所有能获得的权限) 14 参数2:表示所得到的进程句柄是否可以被继承 15 参数3:被打开进程的pid 16 返回值:指定进程的句柄 17 */ 18 handle hprocess = openprocess(process_all_access, false, dwid); 19 20 21 /* 22 【1.2 在目标进程的内存里开辟空间】 23 参数1:目标进程句柄 24 参数2:保留页面的内存地址,一般用null自动分配 25 参数3:欲分配的内存大小,字节单位 26 参数4:mem_commit:为特定的页面区域分配内存中或磁盘的页面文件中的物理存储 27 参数5:page_readwrite 区域可被应用程序读写 28 返回值:执行成功就返回分配内存的首地址,不成功就是null 29 */ 30 lpvoid premoteaddress = virtualallocex( 31 hprocess, 32 null, 33 1, 34 mem_commit, 35 page_readwrite 36 ); 37 38 //二、 把dll的路径写入到目标进程的内存空间中 39 40 dword dwwritesize = 0; 41 /* 42 【写一段数据到刚才给指定进程所开辟的内存空间里】 43 参数1:openprocess返回的进程句柄 44 参数2:准备写入的内存首地址 45 参数3:指向要写的数据的指针(准备写入的东西) 46 参数4:要写入的字节数(东西的长度+0/) 47 参数5: 返回值。返回实际写入的字节 48 */ 49 writeprocessmemory(hprocess,premoteaddress, szpath, wcslen(szpath) * 2 + 2, &dwwritesize); 50 51 52 //三、 创建一个远程线程,让目标进程调用loadlibrary 53 54 /* 55 参数1:该远程线程所属进程的进程句柄 56 参数2:一个指向 security_attributes 结构的指针, 该结构指定了线程的安全属性 57 参数3:线程栈初始大小,以字节为单位,如果该值设为0,那么使用系统默认大小 58 参数4:在远程进程的地址空间中,该线程的线程函数的起始地址(也就是这个线程具体要干的活儿) 59 参数5:传给线程函数的参数(刚才在内存里开辟的空间里面写入的东西) 60 参数6:控制线程创建的标志。0(null)表示该线程在创建后立即运行 61 参数7:指向接收线程标识符的变量的指针。如果此参数为null,则不返回线程标识符 62 返回值:如果函数成功,则返回值是新线程的句柄。如果函数失败,则返回值为null 63 */ 64 handle hthread = createremotethread( 65 hprocess, 66 null, 67 0, 68 (lpthread_start_routine)loadlibrary, 69 premoteaddress, 70 null, 71 null 72 ); 73 waitforsingleobject(hthread, -1); //当句柄所指的线程有信号的时候,才会返回 74 75 /* 76 四、 【释放申请的虚拟内存空间】 77 参数1:目标进程的句柄。该句柄必须拥有 process_vm_operation 权限 78 参数2:指向要释放的虚拟内存空间首地址的指针 79 参数3:虚拟内存空间的字节数 80 参数4:mem_decommit仅标示内存空间不可用,内存页还将存在。 81 mem_release这种方式很彻底,完全回收。 82 */ 83 virtualfreeex(hprocess, premoteaddress, 1, mem_decommit); 84 return 0; 85 } 86 87 88 int _tmain(int argc, _tchar * argv[]) 89 { 90 wchar_t wstr[] = l"e:\\inject.dll"; 91 dword dwid = 0; 92 93 //参数1:(null 94 //参数2:目标窗口的标题 95 //返回值:目标窗口的句柄 96 hwnd hcalc = findwindow(null, l"微信"); 97 printf("目标窗口的句柄为:%d\n", hcalc); 98 99 dword dwpid = 0; 100 101 //参数1:目标进程的窗口句柄 102 //参数2:把目标进程的pid存放进去 103 dword dwrub = getwindowthreadprocessid(hcalc, &dwpid); 104 printf("目标窗口的进程pid为:%d\n", dwpid); 105 106 //参数1:目标进程的pid 107 //参数2:想要注入dll的路径 108 inject(dwpid, wstr); 109 110 return 0; 111 }
执行之后,dll就注入到了pc版的微信进程。且该dll中含有一个弹窗代码,也出现在了pc版微信的界面之上。
附:测试用的dll代码
1 #include <windows.h> 2 3 4 dword winapi runbot(lpvoid lpparam) { 5 // 此处可以写具体的bot代码 6 return 1; 7 } 8 9 10 bool apientry dllmain( hmodule hmodule, 11 dword ul_reason_for_call, 12 lpvoid lpreserved 13 ) 14 { 15 switch (ul_reason_for_call) 16 { 17 case dll_process_attach: 18 messageboxa(null, "dll attached!\n", "game hacking", mb_ok | mb_topmost); 19 createthread(null, 0, &runbot, null, 0, null); 20 break; 21 } 22 return true; 23 }
(以上例程均在 windows 10 系统,visualstudio 2019 环境中编译通过)
上一篇: python 爬虫简介
下一篇: bootstrap思考一