詳細解讀:遠端執行緒注入DLL到PC版微信

Stuxnet發表於2019-05-11

一、遠端執行緒注入的原理

  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 環境中編譯通過)

 

相關文章