引入


根据上节课IAT HOOK结尾的局限性分析,自己写的函数,或者是通过LoadLibrary进来的函数在IAT 表中都是不存在的。这时候我们就需要用到Inline HOOK

Inline HOOK(内联HOOK),CE工具中的代码注入用到的就是这种HOOK。原理就是,在HOOK点修改指令,跳转到我们的函数位置,然后此时就可以获取到寄存器,堆栈信息。执行完我们自己的代码后再跳转回到原来的位置执行。

注意事项


在制作Inline hook的过程中有不少需要注意的地方:

  1. 当我们在跳转的时候可以用E8(Call),E9(Jmp)这些后面跟的地址都是需要通过公式计算的。公式:X = 要跳转到的地址 - 5 - 当前地址(X就是跳转指令后面的值)
  2. 当我们HOOK插入跳转指令的时候会修改掉一些指令,但是当前函数还没有执行这几条指令,所以在我们的函数执行完成之前还得调用回这几条指令
  3. 当我们跳转到我们自己的函数区域时可能会对堆栈、寄存器做修改,这时候就得在执行这些操作之前保存寄存器的值,在完成操作后恢复寄存器和堆栈
  4. 这里还有一个要注意的地方就是想要直接获取到自定义函数的函数首地址不能直接用函数名,这里有个坑是这样的,当我们在调试过程中进入函数名的地址中时我们会发现这里不是函数所在的地方,而是一个jmp,跳转到函数的首地址。我们来验证一下这个观点:
    自定义一个函数,然后调试->转到反汇编,看看函数地址:
    QQ_1728487761135
    此时的函数地址时413660,我们再看看DWORD tmp = (DWORD)函数地址是什么个东西,诶?这个tmp它不是首地址,那他是个啥咧?:
    QQ_1728488276708

我们直接启动调试,然后在反汇编窗口直接跳到这个位置,发现这里是一个jmp,而jmp的地址就是函数的首地址

QQ_1728487845633

大致流程:

1231

代码实现


Main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include "IAT_Hook.h"
#include "InlineHOOK.h"

VOID Test_IAT_HOOK();


DWORD RetAddr;
typedef struct _REGISTER
{
DWORD EAX;
DWORD EBX;
DWORD ECX;
DWORD EDX;
DWORD EBP;
DWORD ESP;
DWORD ESI;
DWORD EDI;
}Register;

DWORD dwParaX;
DWORD dwParaY;
Register reg = { 0 };
CHAR szBuffer[100] = { 0 };

// naked裸函数,堆栈平衡要自己写
extern "C" _declspec(naked)void HookProc()
{
// 保存寄存器
_asm
{
pushad
pushfd
}

_asm
{
mov reg.EAX, eax
mov reg.EBX, ebx
mov reg.ECX, ecx
mov reg.EDX, edx
mov reg.ESP, esp
mov reg.EBP, ebp
mov reg.ESI, esi
mov reg.EDI, edi

mov EAX, DWORD PTR SS : [ESP + 0x28]
mov dwParaX, EAX
mov EAX, DWORD PTR SS : [ESP + 0x2C]
mov dwParaY, EAX
}
sprintf(szBuffer, "EAX:%x\nEBX:%x\nECX:%x\nEDX:%x\nESP:%x\nEBP:%x\nESI:%x\nEDI:%x\n", reg.EAX, reg.EBX, reg.ECX, reg.EDX, reg.ESP, reg.EBP, reg.ESI, reg.EDI);
MessageBoxA(NULL, szBuffer, "[Register]", MB_OK);
memset(szBuffer, 0, 100);
sprintf(szBuffer, "dwParaX: %d\ndwParaY: %d\n", dwParaX, dwParaY);
MessageBoxA(NULL, szBuffer, "[参数]", MB_OK);

// 还原现场
_asm
{
popfd
popad
}

// 执行被删除的代码
_asm
{
push ebp
mov ebp, esp
sub esp, 0C0h
}

// 跳转回去
_asm
{
jmp RetAddr
}
}


int main()
{
//Test_IAT_HOOK();
DWORD HookAddr = *(PDWORD)((DWORD)plus + 1) + (DWORD)plus + 5;
RetAddr = SetInlineHOOK(HookAddr, (DWORD)HookProc, 9);
int x = plus(5, 10);
printf("%d\n", x);
return 0;
}

InlineHook.h

1
2
3
4
5
6
7
8
9
10
11
#include "Main.h"

int plus(int x, int y);

//=========================================
// 函数功能 :设置HOOK
// dwHookAddr : HOOK点地址
// dwProcAddr : HOOK函数地址
// dwLength : 修改的指令所需的长度
//=========================================
DWORD SetInlineHOOK(DWORD dwHookAddr, DWORD dwProcAddr, DWORD dwLength);

InlineHook.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include "InlineHOOK.h"

// 全局变量
DWORD g_dwHookAddr; // HOOK开始的地址
DWORD g_dwRetAddr; // HOOK返回到的地址
PBYTE g_pCodePatch; // 存放被HOOK的内存原来的代码
DWORD g_dwLength; // HOOK的字节数
DWORD g_dwHookFlag; // HOOK状态:1表示成功 0表示失败


DWORD SetInlineHOOK(DWORD dwHookAddr, DWORD dwProcAddr, DWORD dwLength)
{
BOOL bRet = FALSE;
DWORD dwOldProctect;
DWORD dwJmpCode;

// 参数校验
if (dwHookAddr == NULL || dwProcAddr == NULL)
{
printf("SetInlineHook失败: HOOK地址/HOOK函数地址填写错误!");
return FALSE;
}

// HOOK字节数不能小于5个字节
if (dwLength < 5)
{
printf("HOOK字节数小于5,无法修改指令");
return FALSE;
}

bRet = VirtualProtectEx(::GetCurrentProcess(), (LPVOID)dwHookAddr, dwLength, PAGE_EXECUTE_READWRITE, &dwOldProctect);
if (!bRet)
{
printf("内存权限申请失败\n");
return FALSE;
}

// 申请一个堆空间放置HOOK前的内存代码
g_pCodePatch = new BYTE[dwLength];
memcpy(g_pCodePatch, (PDWORD)dwHookAddr, dwLength);

// 将HOOK点的代码全部修改成nop
dwJmpCode = dwProcAddr - 5 - dwHookAddr;
memset((PVOID)dwHookAddr, 0x90, dwLength);
*(PBYTE)dwHookAddr = 0xE9;
*(PDWORD)(dwHookAddr + 1) = dwJmpCode;

g_dwHookAddr = dwHookAddr;
g_dwRetAddr = dwHookAddr + dwLength;
g_dwLength = dwLength;
g_dwHookFlag = 1;
return g_dwRetAddr;
}


int plus(int x, int y)
{
return x + y;
}