高手请飘过~~~~~~~~~~~~~~~~~
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;
}