我們進行系統層級的安全監控的時候,防範木馬的時候,經常需要進行遠程代碼注入執行。
執行步驟如下
1. 提升進程許可權,如果許可權不夠的話,很容易造成 OpenProcess 失敗;
2. 確定你的宿主進程,即你所要注入代碼的進程,這個其實很好辦,你要是不想你的木馬或者病毒被別個一下子就結束了的話,
最好是選擇系統要想運行,則必須開啟的那種進程,比如資源管理員進程 Explorer.exe,
Windows 子系統進程 csrss.exe 等等,但是這裡注意的是,我注入 System 進程的時候造成了失敗哦,
所以最好還是別拿 System 做實驗,而且如果你注入失敗了的話,是會造成宿主進程崩潰的,
等下一不小心把 System 進程給弄崩潰了就不好了;
3. 開啟宿主進程了(我這裡開啟的是 Explorer.exe 進程),思路是首先變數當前系統下啟動並執行所有的進程,
然後遍曆擷取到得所有的進程的 PID,再調用 ProcessIsExplorer 函數來判斷這個進程是否為 Explorer.exe 進程,
如果是則記錄下這個進程的 PID 就可以了,這樣就獲得了 Explorer.exe 進程的 PID 了,
再通過 OpenProcess 來開啟這個 Explorer.exe 進程就 OK 了;
4. 在宿主進程中分配好儲存空間,這個儲存空間是用來存放我們將要建立的遠程線程的線程處理常式的,
這裡需要注意的是:我們分配的記憶體必須標記必須帶有 EXECUTE,因為分配的這塊記憶體是用來存放線程處理常式的,
而線程處理常式必須得執行,所以必須得帶有 EXECUTE 標記,而至於 WRITE 標記的話,很明顯是需要的,
因為我們在後面的代碼中還必須調用 WriteProcessMemory 來將線程處理常式寫入到這塊記憶體中,自然其必須可寫;
5. 將遠程線程處理常式寫入到 4 中在宿主進程中所分配的記憶體中,這個可以直接調用 WriteProcessMemory 來實現;
6. 在宿主進程中分配好儲存空間,這個儲存空間是用來存放我們將要傳遞給遠程線程線程處理常式的參數,
從下面的結構體中可以看出,其由三個參數組成,第一個參數代表要在對話方塊中顯示的內容,
第二個參數代表要在對話方塊中顯示的標題,第三個參數則是 MessageBox 這個 API 的地址,
因為在 Explorer.exe 中 MessageBox 的地址會發生重新導向,所以需要將其地址通過參數傳遞給線程處理常式;
7. 將參數寫入到 6 中在宿主進程中所分配的記憶體中,同樣是調用 WriteProcessMemory 來完成;
8. 調用 CreateRemoteThread 在 Explorer.exe(宿主進程)中建立遠程線程;
注意,當遠程線程沒有執行完時,不能夠通過 VirtualFreeEx 來將遠程進程中的記憶體釋放掉,
你想啊,我他媽的線程都還在 Explorer.exe 裡面執行,你他媽的在外面把我占的記憶體給釋放掉了,我還執行個屁啊 !
所以這裡調用了 WaitForSingleObject 來等待這個遠程線程執行完畢,
其執行完畢後再釋放在 Explorer.exe 中所分配的儲存空間 !
請見代碼實現與注釋講解
/* 標頭檔 */#include <windows.h>#include <Tlhelp32.h>/************************************** BOOL EnablePrivilege (PCSTR name)* 功能提升本許可權** 參數PCSTR name所需的許可權* 返回是否成功**************************************/DWORD EnablePrivilege (PCSTR name){HANDLE hToken;BOOL rv;//設定結構TOKEN_PRIVILEGES priv = { 1, {0, 0, SE_PRIVILEGE_ENABLED} };// 尋找許可權值LookupPrivilegeValue (0,name,&priv.Privileges[0].Luid);// 開啟本進程TokenOpenProcessToken(GetCurrentProcess (),TOKEN_ADJUST_PRIVILEGES,&hToken);// 提權AdjustTokenPrivileges (hToken,FALSE,&priv,sizeof priv,0,0);// 傳回值,錯誤資訊,如果操作成功,則應為ERROR_SUCCESS,為Orv = GetLastError();// 關閉TokenCloseHandle (hToken);return rv;}/************************************** BOOL LoadRometeDll(DWORD dwProcessId, LPTSTR lpszLibName)* 功能通過建立遠程線程給其他進程載入Dll** 參數DWORD dwProcessId目標進程PID*LPTSTR lpszLibNameDll的路徑* 返回是否成功**************************************/BOOL LoadRometeDll(DWORD dwProcessId, LPTSTR lpszLibName){BOOL bResult = FALSE; HANDLE hProcess = NULL;HANDLE hThread = NULL;PSTR pszLibFileRemote = NULL;DWORD cch;PTHREAD_START_ROUTINE pfnThreadRtn;__try {// 獲得想要注入代碼的進程的控制代碼.hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);if (hProcess == NULL)__leave;// 計算DLL路徑名需要的位元組數.cch = 1 + lstrlen(lpszLibName);// 在遠程線程中為路徑名分配空間.pszLibFileRemote = (PSTR)VirtualAllocEx(hProcess, NULL, cch, MEM_COMMIT, PAGE_READWRITE);if (pszLibFileRemote == NULL) __leave;// 將DLL的路徑名複製到遠程進程的記憶體空間.if (!WriteProcessMemory(hProcess, (PVOID)pszLibFileRemote, (PVOID)lpszLibName, cch, NULL)) __leave;// 獲得LoadLibraryA在Kernel32.dll中的真正地址. pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), TEXT("LoadLibraryA"));if (pfnThreadRtn == NULL) __leave;// 建立遠程線程,並通過遠程線程調用使用者的DLL檔案. hThread = CreateRemoteThread(hProcess, NULL, 0, pfnThreadRtn, (PVOID)pszLibFileRemote, 0, NULL);if (hThread == NULL) __leave;// 等待遠程線程終止.WaitForSingleObject(hThread, INFINITE);bResult = TRUE; }__finally { // 關閉控制代碼. if (pszLibFileRemote != NULL) VirtualFreeEx(hProcess, (PVOID)pszLibFileRemote, 0, MEM_RELEASE);if (hThread != NULL) CloseHandle(hThread);if (hProcess != NULL) CloseHandle(hProcess);}return bResult;}/************************************** BOOL GetProcessIdByName(LPSTR szProcessName, LPDWORD lpPID)* 功能通過進程名擷取進程PID** 參數LPSTR szProcessName進程名*LPDWORD lpPID指向儲存PID的變數* 返回是否成功**************************************/BOOL GetProcessIdByName(LPSTR szProcessName, LPDWORD lpPID){// 變數及初始化STARTUPINFO st;PROCESS_INFORMATION pi;PROCESSENTRY32 ps;HANDLE hSnapshot;ZeroMemory(&st, sizeof(STARTUPINFO));ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));st.cb = sizeof(STARTUPINFO);ZeroMemory(&ps,sizeof(PROCESSENTRY32));ps.dwSize = sizeof(PROCESSENTRY32);// 遍曆進程hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0);if(hSnapshot == INVALID_HANDLE_VALUE){return FALSE;}if(!Process32First(hSnapshot,&ps)){return FALSE;}do{// 比較進程名if(lstrcmpi(ps.szExeFile,"explorer.exe")==0){// 找到了*lpPID = ps.th32ProcessID;CloseHandle(hSnapshot);return TRUE;}}while(Process32Next(hSnapshot,&ps));// 沒有找到CloseHandle(hSnapshot);return FALSE;}/************************************** int WinMain(*HINSTANCE hInstance,*HINSTANCE hPrevInstance,*LPSTR lpCmdLine,*int nCmdShow*)**************************************/int WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){DWORD dwPID;// 提權,擷取SE_DEBUG_NAME許可權,// 可以在其他進程的記憶體空間中寫入、建立線程if(0!=EnablePrivilege (SE_DEBUG_NAME))return 0;// 擷取目錄進程的PIDif(!GetProcessIdByName("explorer.exe",&dwPID))return 0;// 通過建立遠程線程載入DLL// 將msg.dll放置在系統目錄下if(!LoadRometeDll(dwPID,"msg.dll"))return 0;return 1;}