#hook #disassemble #assemble

ilhook

一个提供在x86和x86_64架构中内联二进制代码hook方法的库

13个版本 (7个稳定版)

2.1.1 2024年7月2日
2.1.0 2023年9月6日
2.0.0 2023年4月5日
1.4.0 2023年1月3日
0.1.2 2019年12月14日

#75硬件支持

Download history 31/week @ 2024-04-29 5/week @ 2024-05-06 7/week @ 2024-05-20 18/week @ 2024-05-27 12/week @ 2024-06-03 13/week @ 2024-06-10 2/week @ 2024-06-17 178/week @ 2024-07-01 23/week @ 2024-07-08 11/week @ 2024-07-15 38/week @ 2024-07-22 79/week @ 2024-07-29 8/week @ 2024-08-05 28/week @ 2024-08-12

每月155次下载

MIT 许可证

86KB
2K SLoC

ilhook

此包提供内联hook x86x64 指令集二进制代码的方法。

HOOK 是一种拦截函数调用并通过用户定义的代码处理它们的机制。

安装

此包与Cargo兼容,位于 crates.io 上。将其添加到您的 Cargo.toml 中,如下所示

[dependencies]
ilhook = "2"

hook类型

Ilhook支持4种hook类型。

跳回hook

此类型用于您希望在指定时间获取一些信息或修改某些值(参数、栈变量、堆变量等)时。

假设我们有一个C++函数

void check_serial_number(std::string& sn){
    uint32_t machine_hash = get_machine_hash();
    uint32_t sn_hash = calc_hash(sn);

    // we want to modify the result of this comparison.
    if (sn_hash == machine_hash) {
        // success
    }
    // fail
}

并且它编译成汇编代码

0x401054 call get_machine_hash   ;get_machine_hash()
0x401059 mov ebx, eax

; ...

0x401070 lea eax, sn
0x401076 push eax
0x401077 call calc_hash          ;calc_hash(sn)
0x40107C add esp, 4
0x40107F cmp eax, ebx            ;we want to modify the eax here!
0x401081 jnz _check_fail

; check_success

现在我们开始

use ilhook::x86::{Hooker, HookType, Registers, CallbackOption, HookFlags};

unsafe extern "C" fn on_check_sn(
    reg: *mut Registers,
    _: usize
) {
    println!("m_hash: {}, sn_hash: {}", (*reg).ebx, (*reg).eax);
    (*reg).eax = (*reg).ebx; //we modify the sn_hash!
}

let hooker = Hooker::new(
    0x40107F,
    HookType::JmpBack(on_check_sn),
    CallbackOption::None,
    0,
    HookFlags::empty(),
);
hooker.hook().unwrap();

然后 check_serial_number 将始终走成功路径。

函数hook

此类型用于您想用您自定义的函数替换函数时。请注意,您应该只在函数的开始处hook。

假设我们有一个函数

fn foo(x: u64) -> u64 {
    x * x
}

assert_eq!(foo(5), 25);

并且您想让它返回 x*x+3,这意味着 foo(5)==28。

现在让我们hook

use ilhook::x64::{Hooker, HookType, Registers, CallbackOption, HookFlags};

unsafe extern "win64" fn new_foo(
    reg: *mut Registers,
    _ :usize,
    _ :usize
) -> usize {
    let x = (&*reg).rdi as usize;
    x * x + 3
}

let hooker = Hooker::new(
    foo as usize,
    HookType::Retn(new_foo),
    CallbackOption::None,
    0,
    HookFlags::empty(),
);
unsafe { hooker.hook().unwrap() };
assert_eq!(foo(5), 28);

跳转地址hook

此类型用于您想更改原始运行路径到您想要的任何路径时。

枚举 HookType::JmpToAddr 的第一个元素表示在回调例程返回后,EIP希望跳转到何处。

跳转返回hook

此类型用于您想更改原始运行路径到您想要的任何路径,并且目标地址可能由输入参数更改。

EIP将跳转到回调例程返回的值。

注意

如果您没有指定 HookFlags::NOT_MODIFY_MEMORY_PROTECT,则此包不是线程安全的。当然,如果您指定了,您需要自己修改目标地址的内存保护。

由于Rust的测试并行运行,如果不指定 --test-threads=1,它可能会崩溃。

依赖关系

~16–30MB
~440K SLoC