Native Hook详细讲解

Native Hook详细讲解

本文链接:https://blog.csdn.net/feather_wch/article/details/131737387



1、Native Hook

是一种用于拦截某个native函数的调用,使得执行流程转向到自定义的代码中。

2、应用场景有哪些?

内存监控
线程监控
GC监控

3、实现方法分为三大类

  1. GOT/PLT hook
  2. Trap hook
  3. inline hook

4、GOT/PLT是什么?

Global Offset Table(全局偏移表)和 Procedure Linkage Table(过程链接表)

5、ELF是什么?

Linux文件格式,有四大类

  1. 可重定向文件 a.o
  2. 可执行文件 a.out
  3. so
  4. core dump文件

6、GOT/PLT hook大体思路

  1. 修改GOT表中目标函数的地址
  2. 让其跳转到我们的函数
  3. 我们函数执行完之后,执行原函数

7、inline hook

  1. 将目标函数的开头几条指令替换为跳转指令,跳转到我们的 hook 函数中。
  2. 在 hook 函数中执行被替换的指令,再跳回目标函数的剩余部分。

8、trap hook

  1. 在目标跳转指令前,增加trap,导致会触发SIGTRAP信号
  2. 信号处理函数里面修改PC值
  3. 执行我们的函数,执行完之后,修改PC值到原函数

Native hook是什么

Native hook 是一种用于截获进程对某个原生函数(native function)的调用,使得函数的执行流程转向我们实现的代码片段,从而实现我们所需要的功能¹。Native hook 技术在 Android 应用性能优化中有很多应用场景,比如监控内存、线程、GC 等²。

Native hook 的实现方式有多种,比较常见的有 GOT/PLT hook、Trap hook 和 Inline hook¹。这些方式的原理和优缺点可以参考这篇文章¹。

GOT/PLT hook

下面我给出一个使用 GOT/PLT hook 的例子,它是通过修改 GOT 表或 PLT 表中的函数地址来实现的³。

假设我们想要 hook libart.so 中的 pthread_create 函数,我们可以使用如下的代码:

#include <stdio.h>
#include <dlfcn.h>
#include <unistd.h>
#include <sys/mman.h>
#include <elf.h>

// 定义一个结构体,用于保存原始函数地址和 hook 函数地址
typedef struct {
   
    void *original;
    void *hook;
} HookStruct;

// 定义一个全局变量,用于保存 pthread_create 的地址信息
HookStruct pthread_create_hook;

// 定义一个新的 pthread_create 函数,用于替换原始函数
int pthread_create_hooked(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) {
   
    printf("Hooked pthread_create\n");
    // 调用原始函数
    return ((int (*)(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *))pthread_create_hook.original)(thread, attr, start_routine, arg);
}

// 定义一个函数,用于获取目标函数在 GOT 表中的地址
void* get_got_address(const char* library_name, const char* function_name) {
   
    // 打开目标库文件
    void* handle = dlopen(library_name, RTLD_NOW);
    if (handle == NULL) {
   
        printf("dlopen failed: %s\n", dlerror());
        return NULL;
    }
    // 获取目标库文件的基址
    Elf32_Ehdr* elf_header = (Elf32_Ehdr*)handle;
    // 获取目标库文件的程序头表
    Elf32_Phdr* program_header = (Elf32_Phdr*)((uint8_t*)handle + elf_header->e_phoff);
    // 遍历程序头表,找到动态段
    Elf32_Dyn* dynamic = NULL;
    for (int i = 0; i < elf_header->e_phnum; i++) {
   
        if (program_header[i].p_type == PT_DYNAMIC) {
   
            dynamic = (Elf32_Dyn*)(program_header[i].p_vaddr + (uint32_t)handle);
            break;
        }
    }
    if (dynamic == NULL) {
   
        printf("dynamic segment not found\n");
        return NULL;
    }
    // 遍历动态段,找到符号表和重定位表
    Elf32_Sym* symtab = NULL;
    char* strtab = NULL;
    Elf32_Rel* rel = NULL;
    int rel_count = 0;
    for (int i = 0; dynamic[i].d_tag != DT_NULL; i++) {
   
        switch(dynamic[i].d_tag) {
   
            case DT_SYMTAB:
                symtab = (Elf32_Sym*)(dynamic[i].d_un.d_ptr + (uint32_t)handle);
                break;
            case DT_STRTAB:
                strtab = (char*)(dynamic[i].d_un.d_ptr + (uint32_t)handle);
                break;
            case DT_JMPREL:
                rel = (Elf32_Rel*)(dynamic[i].d_un.d_ptr + (uint32_t)handle);
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猎羽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值