Inline Hook

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

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

猜你喜欢

转载自blog.csdn.net/weixin_43890959/article/details/113922011