Inline Hook

Called InlineHookessence is to add or modify the program function assembler instruction (e.g., jmp、callinstructions) to implement the program logic causes a jump, i.e. Shellcodeinjection. When executing the target function, the program EIPsource code, after a jump, to avoid affecting the normal function of the original program.

It should be noted that when the program starts to load and run in the operating system, the attributes of its different segments have been set. For example, the code segment is readable and executable but not writable, while the data segment only allows reading and writing but not execution, etc. . Need to APIfunction VirtualProtectto read and write the properties of the target executable code segment is set to achieve the modification process code segment, or write command will be rejected, causing abnormal read and write errors.

The test code is as follows:

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

The renderings are as follows:
Insert picture description here

Guess you like

Origin blog.csdn.net/weixin_43890959/article/details/113922011