原理:
打開目標進程以后,將要注入的動態庫的路徑寫入這個地址空間,然后調用開啟遠程線程的函數,來執行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;
}
