Skip to content

hiyasame/InlineHookTest

Repository files navigation

InlineHookTest

在 android 上实现 inline hook 的一个简单 demo,只支持 arm64 架构

// 只支持 arm64 架构
// 1. 覆盖掉 target_func 头部的 16 bytes,将其修改为跳转到 hook_func 地址的指令
// 2. 原本 target_func 头部的 16 bytes 被存到 trampoline 里面,再接一条跳转到原 target_func 剩余部分的指令
hook_t hook(void *target_func, void *hook_func) {
    auto target_address = reinterpret_cast<uint64_t>(target_func);
    auto hook_address = reinterpret_cast<uint64_t>(hook_func);

    // 16 byte 指令块
    uint32_t hook_instructions[4];
    hook_t hook {
            .origin_func = static_cast<uint32_t *>(malloc(32))
    };
    generate_hook_instructions(target_address, hook_address, hook_instructions);

    // trampoline 跳转指令,16 byte
    auto trampoline_address = reinterpret_cast<uint64_t>(hook.origin_func);
    uint32_t return_instructions[4];
    generate_hook_instructions(trampoline_address + 16, target_address + 16, return_instructions);

    // 前 16 byte 可写就行
    make_rwx(target_func, 16);
    // trampoline 需要可执行
    make_rwx(hook.origin_func, 32);

    memcpy(hook.origin_func, target_func, 16);
    memcpy(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(hook.origin_func) + 16), return_instructions, 16);
    memcpy(target_func, hook_instructions, 16);

    return hook;
}

// 复原
// 将 trampoline 前 16 个字节写回 target_func,并释放 trampoline
void unhook(void *target_func, hook_t *hook) {
    memcpy(target_func, hook->origin_func, 16);
    free(hook->origin_func);
}

void generate_hook_instructions(uint64_t current_addr, uint64_t hook_function_addr, uint32_t* instructions) {
    // 计算页面基址(4KB 对齐)
    uint64_t current_page = current_addr & ~0xFFFULL;
    uint64_t target_page = hook_function_addr & ~0xFFFULL;

    // 计算页面差值(以页面为单位)
    int64_t page_diff = (int64_t)(target_page - current_page) >> 12;

    // 计算页面内偏移
    uint32_t page_offset = hook_function_addr & 0xFFF;

    // 检查是否在 ADRP 范围内
    if (page_diff <= 0x1FFFFF && page_diff >= -0x200000) {
        // 使用 ADRP + ADD + BR(原方案)
        instructions[0] = encode_adrp(16, page_diff);           // ADRP X16, hook_function
        instructions[1] = encode_add_imm(16, 16, page_offset);  // ADD X16, X16, #:lo12:hook_function
        instructions[2] = 0xD61F0200;                          // BR X16
        instructions[3] = 0xD503201F;                          // NOP

        LOGI("Using ADRP method (page_diff: %ld)", page_diff);
    } else {
        // 使用 LDR + BR 方法(无距离限制)
        LOGI("Using LDR method (page_diff: %ld, out of ADRP range)", page_diff);

        // LDR X16, #8    ; 从 PC+8 位置加载 64 位地址到 X16
        // BR X16         ; 跳转到 X16
        // .quad hook_function_addr  ; 64 位目标地址

        instructions[0] = 0x58000050;  // LDR X16, #8 (PC + 8)
        instructions[1] = 0xD61F0200;  // BR X16

        // 将 64 位地址拆分为两个 32 位指令位置
        instructions[2] = (uint32_t)(hook_function_addr & 0xFFFFFFFF);        // 低32位
        instructions[3] = (uint32_t)((hook_function_addr >> 32) & 0xFFFFFFFF); // 高32位
    }
}

About

在 android arm64 上实现 inline hook 的一个 demo

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published