Called InlineHook
essence is to add or modify the program function assembler instruction (e.g., jmp、call
instructions) to implement the program logic causes a jump, i.e. Shellcode
injection. When executing the target function, the program EIP
source 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 API
function VirtualProtect
to 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: