Gancho en línea

La InlineHookesencia llamada es agregar o modificar la instrucción del ensamblador de la función del programa (por ejemplo, jmp、callinstrucciones) para implementar la lógica del programa que provoca un salto, es decir, la Shellcodeinyección. Al ejecutar la función de destino, el EIPcódigo fuente del programa , después de un salto, para evitar afectar la función normal del programa original.

Cabe señalar que cuando el programa comienza a cargarse y ejecutarse en el sistema operativo, se han configurado los atributos de sus diferentes segmentos. Por ejemplo, el segmento de código es legible y ejecutable pero no escribible, mientras que el segmento de datos solo permite lectura y escritura pero no ejecución, etc. La necesidad de APIfuncionar VirtualProtectpara leer y escribir las propiedades del segmento de código ejecutable de destino está configurada para lograr el segmento de código de proceso de modificación, o el comando de escritura será rechazado, causando errores anormales de lectura y escritura.

El código de prueba es el siguiente:

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

Las representaciones son las siguientes:
Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/weixin_43890959/article/details/113922011
Recomendado
Clasificación