首页
社区
课程
招聘
[原创]Got表hook和inlinehook有什么区别?
发表于: 2025-3-18 19:28 1805

[原创]Got表hook和inlinehook有什么区别?

2025-3-18 19:28
1805

GOT HookInline Hook 都是修改函数调用流程的技术,但它们的原理和适用场景不同。


1. GOT Hook(Global Offset Table Hook)

GOT Hook 是一种基于 ELF (Executable and Linkable Format) 机制的 Hook 技术,主要针对 动态链接库(so 库) 进行劫持。

原理

  • ELF 中,GOT(全局偏移表)存储了动态链接的函数地址,如 mallocopenread 等系统 API。
  • 当程序调用动态链接库函数时,会先查找 GOT 表中的地址,再跳转执行。
  • GOT Hook 通过修改 GOT 表中的地址,将其指向我们的 Hook 函数,从而拦截目标函数调用。

示例代码(GOT 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
#include <stdio.h>
#include <dlfcn.h>
#include <string.h>
#include <elf.h>
#include <sys/mman.h>
 
// Hook 目标函数
ssize_t (*old_read)(int, void *, size_t);
 
// 自定义 read 函数
ssize_t my_read(int fd, void *buf, size_t count) {
    printf("[+] Hooked read()! fd: %d, count: %zu\n", fd, count);
    return old_read(fd, buf, count); // 调用原始 read
}
 
// 修改 GOT 表
void hook_function(const char *symbol, void *new_func) {
    void *handle = dlopen(NULL, RTLD_NOW);
    if (!handle) return;
 
    // 获取符号原始地址
    old_read = dlsym(handle, symbol);
 
    // 遍历 GOT 表,找到目标地址并替换
    ElfW(Dyn) *dyn = (ElfW(Dyn) *)dlsym(handle, "_DYNAMIC");
    while (dyn->d_tag != DT_NULL) {
        if (dyn->d_tag == DT_PLTGOT) {
            void **got = (void **)dyn->d_un.d_ptr;
            for (int i = 0; got[i] != NULL; i++) {
                if (got[i] == old_read) {
                    // 修改 GOT 表指针
                    mprotect((void *)((uintptr_t)got & ~0xFFF), 0x1000, PROT_READ | PROT_WRITE);
                    got[i] = new_func;
                    mprotect((void *)((uintptr_t)got & ~0xFFF), 0x1000, PROT_READ);
                    break;
                }
            }
        }
        dyn++;
    }
    dlclose(handle);
}
 
// 初始化 Hook
void __attribute__((constructor)) init() {
    hook_function("read", my_read);
}

适用场景

  • 适用于拦截 动态链接库(如 libc.solibart.so)中的函数。
  • 适用于 Hook 系统 API(如 openreadwrite)。
  • 不适用于 Hook 静态链接 的函数(因为静态链接的函数地址不会经过 GOT 表)。

2. Inline Hook(指令级 Hook)

Inline Hook 直接修改目标函数的汇编指令,通常是修改函数的前几条指令,使其跳转到自定义的 Hook 代码。

原理

  • 目标函数的前几条指令通常是 可预测的,例如:
    push   rbp
    mov    rbp, rsp
    
  • Inline Hook 通过修改这些指令,插入 无条件跳转(jmp) 指令,使程序执行自定义 Hook 代码。
  • Hook 代码执行完后,再跳转回原始函数,确保程序正常运行。

示例代码(Inline 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
#include <stdio.h>
#include <stdint.h>
#include <sys/mman.h>
#include <string.h>
 
// 定义目标函数
ssize_t (*orig_read)(int, void *, size_t);
 
// 自定义 Hook 函数
ssize_t my_read(int fd, void *buf, size_t count) {
    printf("[+] Inline Hooked read()! fd: %d, count: %zu\n", fd, count);
    return orig_read(fd, buf, count);
}
 
// 修改目标函数首地址
void hook_function(void *target, void *hook) {
    uint8_t *addr = (uint8_t *)target;
 
    // 备份原始代码(5 字节)
    uint8_t orig_code[5];
    memcpy(orig_code, addr, 5);
 
    // 计算跳转偏移
    uintptr_t relative_addr = ((uintptr_t)hook - (uintptr_t)target - 5);
 
    // 修改内存权限
    mprotect((void *)((uintptr_t)addr & ~0xFFF), 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC);
 
    // 写入跳转指令(JMP hook)
    addr[0] = 0xE9;  // JMP opcode
    *(uint32_t *)(addr + 1) = relative_addr;
 
    // 恢复内存权限
    mprotect((void *)((uintptr_t)addr & ~0xFFF), 0x1000, PROT_READ | PROT_EXEC);
}
 
// 初始化 Hook
void __attribute__((constructor)) init() {
    orig_read = (ssize_t (*)(int, void *, size_t))dlsym(RTLD_NEXT, "read");
    hook_function((void *)orig_read, (void *)my_read);
}

适用场景

  • 适用于所有函数(包括静态和动态链接)。
  • 可以 Hook 内核函数(如 syscall)。
  • 可以 Hook Java 方法(使用 ART Hook)。
  • 不受 GOT 限制,但需要处理指令恢复问题。

3. GOT Hook vs Inline Hook 对比

比较项 GOT Hook Inline Hook
原理 修改 GOT 表中的函数地址 修改目标函数的机器指令
适用对象 仅适用于动态链接函数(ELF SO 库) 适用于所有函数(包括静态和动态链接)
实现方式 修改 GOT 表指针 插入 JMPBL 指令
对系统 API 的影响 只影响当前进程 可能影响整个系统
稳定性 稳定,不影响函数的内部实现 可能导致崩溃(如果修改不当)
适用场景 Hook openreadwrite 等系统 API Hook Java 方法、ART 虚拟机、内核函数

4. 什么时候用哪种 Hook?

目标 推荐 Hook 方式
Hook libc.so 里的 open()read() GOT Hook
Hook libart.so 里的 Java 方法解析 GOT Hook
Hook libc.so 里的 syscall Inline Hook
Hook JNI 层函数 Inline Hook
Hook 目标 App 自定义的函数 Inline Hook

5. 进阶:如何防止被 Hook?

防止 GOT Hook

  • 使用 dlsym() 直接调用原始函数,而不是 GOT 表。
  • init_array 中定期检查 GOT 表。

防止 Inline Hook

  • 计算目标函数的校验和(CRC/MD5),检测是否被修改。
  • 在关键函数内 动态解密 代码,避免被直接 Hook。
  • 运行时 检测 JMP 指令 是否被篡改。

总结

  • GOT Hook 适用于动态链接库中的函数(如 open())。
  • Inline Hook 适用于所有函数,包括 Java 和内核函数。
  • GOT Hook 更稳定,但不能 Hook 静态函数。
  • Inline Hook 更强大,但更危险,可能导致崩溃。

推荐文章:https://bbs.kanxue.com/thread-272870.htm


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费
支持
分享
最新回复 (1)
雪    币: 57
活跃值: (2482)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2025-3-18 21:54
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册