0%

InlineHook

Ring3层下的Inline Hook是最常用的Hook手段之一,是一种通过修改机器码的方式来实现hook的技术。

JMP的地址 (88881234) – 代码地址 (010073bb) – 5(字节) = 机器码跳转地址 (E9 87879e74)

jmp跳转的地址=自己实现的函数地址-(jmp所在的地址+5)

1. 需要手动脱钩

  1. 构造跳转指令。
  2. 在内存中找到要Hook函数地址,并保存要Hook位置处的前5字节。
  3. 将构造的跳转指令写入需Hook的位置处。
  4. 当被Hook位置被执行时会转到自己的流程执行。
  5. 如果要执行原来的流程,那么取消Hook,也就是还原被修改的字节。
  6. 执行原来的流程。
  7. 继续Hook住原来的位置。
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
#include <Windows.h>
#include <stdio.h>


typedef int (WINAPI* lPMessageBoxA)(HWND, LPCSTR, LPCSTR, UINT);

BYTE olddata32[5] = { 0 };
void hook();
void unhook();
int num = 0;

int WINAPI MyMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) {
//调用原来的MessageBoxA API 先脱钩
unhook();
lPMessageBoxA messagebox = (DWORD)GetProcAddress(GetModuleHandle("user32.dll"), "MessageBoxA");
int ret = messagebox(0, "Hook", "Hook", 0);
num++;
printf("MessageBox被调用%d次\n",num);
hook();//函数中之前再次hok 为了拦截下次调用
return ret;
}

//挂钩
void hook() {
//获取MessageBox的地址
DWORD messagebox = (DWORD)GetProcAddress(GetModuleHandle("user32.dll"), "MessageBoxA");
BYTE data[5] = { 0xe9,0,0,0,0 }; //{ 0xe9, }默认初始化为0 0xe9->jmp
DWORD offset = (DWORD)MyMessageBoxA - messagebox - 5; //计算jmp跳转的偏移量

//保存前五个字节数据
memcpy(olddata32, messagebox, 5);
//把偏移量与 JMP指令拼接
memcpy(&data[1], &offset, 4); //4个与jmp指令拼接
//memcpy(data+1, &offset, 4); 也可以这样写

DWORD oldProtected = 0;
//将内存改为可读可写可执行
VirtualProtect(messagebox, 5, PAGE_EXECUTE_READWRITE, &oldProtected);
memcpy(messagebox, data, 5);
//还原内存属性
VirtualProtect(messagebox, 5, oldProtected, &oldProtected);

}

//脱钩
void unhook() {
//获取MessageBox的地址
DWORD messagebox = (DWORD)GetProcAddress(GetModuleHandle("user32.dll"), "MessageBoxA");

DWORD oldProtected = 0;
//将内存改为可读可写可执行
VirtualProtect(messagebox, 5, PAGE_EXECUTE_READWRITE, &oldProtected);
memcpy(messagebox, olddata32, sizeof(olddata32));
//还原内存属性
VirtualProtect(messagebox, 5, oldProtected, &oldProtected);

}


void main() {
hook();
while (1)
{
MessageBoxA(0, "正常调用MessageBoxA", "未Hook", 0);
Sleep(2000);
}

}
img

2.

将三条指令保存起来

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
#include <Windows.h>
#include <stdio.h>

DWORD jump = 0;

_declspec(naked) int _stdcall Transfer(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) {
_asm {
mov edi, edi
push ebp
mov ebp, esp
mov ebx, jump
jmp ebx
}
}

BYTE olddata32[5] = { 0 };
void hook();
int num = 0;

int WINAPI MyMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) {

num++;
printf("MessageBox被调用%d次\n", num);
char* text = "Hook";

hook();//函数中之前再次hok 为了拦截下次调用
return Transfer( hWnd, text, text, uType);
}

//挂钩
void hook() {
//获取MessageBox的地址
DWORD messagebox = (DWORD)GetProcAddress(GetModuleHandle("user32.dll"), "MessageBoxA");

DWORD value = (DWORD)MyMessageBoxA - messagebox - 5; //计算jmp跳转的偏移量

DWORD oldProtected = 0;
//将内存改为可读可写可执行
VirtualProtect(messagebox, 5, PAGE_EXECUTE_READWRITE, &oldProtected);

jump = messagebox + 5; //+5 越过jmp指令 | mov edi edi| push ebp | mov ebp, esp
_asm {
mov eax,messagebox
mov byte ptr [eax], 0xe9 //jmp
inc eax
//后面还有4个字节 用一个寄存器存储
mov ebx, value
mov dword ptr [eax], ebx

}
//还原内存属性
VirtualProtect(messagebox, 5, oldProtected, &oldProtected);

}

void main() {
hook();
while (1) {
MessageBoxA(0, "正常调用MessageBoxA", "未Hook", 0);
Sleep(2000);
}
}

欢迎关注我的其它发布渠道

------------- 💖 🌞 本 文 结 束 😚 感 谢 您 的 阅 读 🌞 💖 -------------