Inline Hook

本文详细介绍了Inline Hook的基本原理,包括如何通过修改程序汇编指令实现函数调用的劫持。讨论了在Windows环境下,由于内存保护机制需要使用VirtualProtect函数改变代码段属性来实现代码写入。通过一个具体的示例展示了如何设置Inline Hook,并在SayHello函数中插入自定义逻辑,打印寄存器值和函数参数。最后,给出了运行结果。
摘要由CSDN通过智能技术生成

所谓 InlineHook 的本质就是添加或修改程序函数中的汇编指令(如 jmp、call 指令),以实现程序逻辑改变造成跳转,即 Shellcode 注入。当执行完目标函数后,在将程序 EIP 跳转后原代码处,以避免影响原程序的正常功能。

需要注意的是,当程序开始在操作系统中加载运行时,其不同段的属性已经被设置,如代码段为可读可执行但不可写,而数据段则只允许读写而不允许执行等。需要通过 API 函数 VirtualProtect 将目标代码段的属性设置为可读可写可执行,才能实现修改进程代码段,否则写命令将会被拒绝,从而引起读写错误异常。

测试代码如下:

#include <stdio.h>
#include <windows.h>

BYTE code[20];	//存储原硬编码
LPSTR lpszParam;	//函数参数
DWORD dwRet;	//指向函数返回地址
DWORD codeLength;	//覆盖目标代码段数据长度
DWORD dwdstFuncAddr;	
DWORD dwsrcFuncAddr;

struct Reg
{
	DWORD EAX;
	DWORD ECX;
	DWORD EDX;
	DWORD EBX;
	DWORD ESP;
	DWORD EBP;
	DWORD ESI;
	DWORD EDI;
	DWORD EFL;
};

Reg reg;	

VOID __declspec(naked)InlineHook()
{
	__asm
	{
		pushad
		pushfd
		mov reg.EAX,eax
		mov reg.ECX,ecx
		mov reg.EDX,edx
		mov reg.EBX,ebx
		mov eax,[esp+0x10]
		mov reg.ESP,eax
		mov reg.EBP,ebp
		mov reg.ESI,esi
		mov reg.EDI,edi
		mov eax,[esp]
		mov reg.EFL,eax
		mov eax,[esp+4*10]
		mov lpszParam,eax
	}

	//打印寄存器的值
	printf("eax: %x\n",reg.EAX);
	printf("ecx: %x\n",reg.ECX);
	printf("edx: %x\n",reg.EDX);
	printf("ebx: %x\n",reg.EBX);
	printf("esp: %x\n",reg.ESP);
	printf("ebp: %x\n",reg.EBP);
	printf("esi: %x\n",reg.ESI);
	printf("edi: %x\n",reg.EDI);
	printf("elf: %x\n",reg.EFL);

	//打印函数参数
	printf("函数参数: %s\n", lpszParam);
	
	//恢复代码
	memcpy((LPVOID)dwsrcFuncAddr, &code, codeLength);

	__asm
	{
		popfd
		popad
		jmp dwRet
	}
}

BOOL SetInLineHook(LPVOID lpdstFuncAddr, LPVOID lpsrcFuncAddr, DWORD codeLen)
{
	//地址转换, 将jmp SayHello指令地址转化为真正的函数地址
	dwdstFuncAddr = *(DWORD*)((DWORD)lpdstFuncAddr+1) + (DWORD)lpdstFuncAddr + 5;
	dwsrcFuncAddr = *(DWORD*)((DWORD)lpsrcFuncAddr+1) + (DWORD)lpsrcFuncAddr + 5;

	//将原代码的硬编码存储在code数组中
	codeLength = codeLen;
	memcpy(&code, (LPVOID)dwsrcFuncAddr, codeLength);

	//返回地址
	dwRet = dwsrcFuncAddr;

	//计算jmp的硬编码
	BYTE shellCode[5] = {
		0xe9, 0x00, 0x00, 0x00, 0x00
	};
	DWORD jmpAddr = dwdstFuncAddr - (dwsrcFuncAddr + codeLength);
	memcpy((LPVOID)((DWORD)&shellCode+1), &jmpAddr, 4);

	//修改页面属性
	DWORD flOldProtect;
	DWORD ret = VirtualProtectEx(GetCurrentProcess(), (LPVOID)dwdstFuncAddr, codeLength, PAGE_EXECUTE_READWRITE, &flOldProtect);
	if(!ret)
	{
		printf("页面属性设置失败!\n");
		return FALSE;
	}

	//将shellCode写入代码中
	memset((LPVOID)dwsrcFuncAddr, 0x90, codeLength);
	memcpy((LPVOID)dwsrcFuncAddr, &shellCode, 5);
	return TRUE;
}

VOID SayHello(LPSTR lpszName)
{
	printf("\nhaha,%s!\n", lpszName);
}

int main()
{
	//初始化code数组
	memset(code, 0, 20);

	//设置InLineHook
	SetInLineHook(InlineHook, SayHello, 5);
	

	SayHello("walker");

	return 0;
}

效果图如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值