原理:
打開目標進程以后,將要注入的動態庫的路徑寫入這個地址空間,然后調用開啟遠程線程的函數,來執行LoadLibraryA或者LoadLibraryW(其實不存在LoadLibrary這個函數,他只是一個宏,如果是UNICODE環境的話會調用LoadLibraryW,否則就是LoadLibraryA)來執行這個動態庫,動態庫一旦被加載起來,DllMain中的DLL_PROCESS_ATTACH則會被執行,我們將要執行的代碼寫在DLL_PROCESS_ATTACH分支即可。之所以把LoadLibraryA(W)作為線程函數,是因為它剛好只有1個參數,在不考慮參數類型的情況下,可以認為它的原型與線程函數一樣,示例如下:
HMODULE WINAPI LoadLibraryW(
_In_ LPCWSTR lpLibFileName
);
DWORD WINAPI ThreadProc(
_In_ LPVOID lpParameter
);
注意:由於從Windows Vista 開始,微軟為了增強系統的安全性,對系統服務和登錄用戶進行了會話(Session)隔離,系統服務屬於會話0,登錄的第一個用戶屬於會話1,之前系統服務和第一個登錄用戶都屬於會話0。此方法並不能突破SESSION 0隔離。原因是在 CreateRemoteThread 函數中對此進行了檢查,如果不在同一會話中,調用 CsrClientCallServer 為新進程進行登記的操作就會失敗,這就直接導致了線程創建的失敗。
步驟:
- 打開目標進程
- 在目標進程中申請空間
- 將要注入的Dll路徑寫入剛申請的空間中
- 獲取LoadLibrary函數地址
- 在目標進程中創建線程,線程回調函數就是LoadLibrary函數,回調函數參數就是要注入的Dll路徑
- 等待線程結束
- 清理環境
代碼如下:
BOOL CBiaoBai1Dlg::CreateRemoteThreadInjectDll(DWORD dwProcessId, char* pszDllFileName) { // 1.打開目標進程 HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, // 打開權限 FALSE, // 是否繼承 dwProcessId); // 進程PID if (NULL == hProcess) { MessageBox("打開目標進程失敗!"); return FALSE; } // 2.在目標進程中申請空間 LPVOID lpPathAddr = VirtualAllocEx( hProcess, // 目標進程句柄 0, // 指定申請地址 strlen(pszDllFileName) + 1, // 申請空間大小 MEM_RESERVE | MEM_COMMIT, // 內存的狀態 PAGE_READWRITE); // 內存屬性 if (NULL == lpPathAddr) { MessageBox("在目標進程中申請空間失敗!"); CloseHandle(hProcess); return FALSE; } // 3.在目標進程中寫入Dll路徑 SIZE_T dwWriteSize = 0; if (FALSE == WriteProcessMemory( hProcess, // 目標進程句柄 lpPathAddr, // 目標進程地址 pszDllFileName, // 寫入的緩沖區 strlen(pszDllFileName) + 1, // 緩沖區大小 &dwWriteSize)) // 實際寫入大小 { MessageBox("目標進程中寫入Dll路徑失敗!"); CloseHandle(hProcess); return FALSE; } //獲取LoadLibraryA的函數地址 //FARPROC可以自適應32位與64位 FARPROC pFuncProcAddr = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA"); if (NULL == pFuncProcAddr) { MessageBox("獲取LoadLibrary函數地址失敗!"); CloseHandle(hProcess); return FALSE; } // 4.在目標進程中創建線程 HANDLE hThread = CreateRemoteThread( hProcess, // 目標進程句柄 NULL, // 安全屬性 NULL, // 棧大小 (PTHREAD_START_ROUTINE)pFuncProcAddr, // 回調函數 lpPathAddr, // 回調函數參數 NULL, // 標志 NULL // 線程ID ); if (NULL == hThread) { MessageBox("目標進程中創建線程失敗!"); CloseHandle(hProcess); return FALSE; } // 5.等待線程結束 WaitForSingleObject(hThread, -1); DWORD code; GetExitCodeThread(hThread, &code); code = GetLastError(); // 6.清理環境 VirtualFreeEx(hProcess, lpPathAddr, 0, MEM_RELEASE); CloseHandle(hThread); CloseHandle(hProcess); return TRUE; }