#hook #elf #symbols #linker #object #plt

plt-rs

用于检查、分析和构建Linux和Android应用程序运行时符号链接的库

3个版本 (重大更新)

0.3.0 2024年8月11日
0.2.0 2024年3月11日
0.1.0 2023年5月5日

Unix API中排名195

Download history 4/week @ 2024-04-29 2/week @ 2024-05-20 87/week @ 2024-05-27 8/week @ 2024-06-03 7/week @ 2024-06-10 22/week @ 2024-06-17 31/week @ 2024-06-24 18/week @ 2024-07-01 9/week @ 2024-07-08 8/week @ 2024-07-22 71/week @ 2024-08-05 56/week @ 2024-08-12

每月下载量135

MIT许可

35KB
648

Plt-rs

变更日志

0.1.0 初始版本

0.2.0 完全重写

  • 移除了hooking功能
  • 减少了Linux/Android的冗余
  • 文档化,并使库更加易用

0.3.0 易用性改进

  • 将动态库中查找函数的功能推广为公共功能
  • 添加了测试
  • 在依赖项中不使用补丁版本
  • ci/cd 依赖项更新

灵感来源

在开发此库时参考和受到启发的项目。

概述

通过爬取可执行文件动态加载的对象,我们可以hook导出的函数。PLT hooking通常是一个理想的解决方案,只要你能够保证Unix Like环境。此库不进行任何内联hooking,因此没有特定的架构(i686、arm等)汇编魔法,使得跨兼容性变得非常容易。确实存在架构特定的常量,但非常少。

为什么

视频游戏模组制作、逆向工程等

  • 可以hook网络调用:recv / send
  • 渲染调用:eglSwapBuffers / 视频游戏模组和外挂
  • 应用程序加固和监控
  • 防御性和进攻性使用

支持并测试了许多目标

突出显示的构建

  • i686-unknown-linux-gnu
  • x86_64-unknown-linux-gnu
  • aarch64-unknown-linux-gnu
  • aarch64-linux-android
  • armv7-linux-androideabi

看看代码吧

这里我们hook了我们的可执行文件对libc getpid的使用。有关完整示例,请参阅examples/hook_getpid.rs,支持Android和32位。大部分代码用于实际指针替换以hook函数!


/// our own get pid function
unsafe fn getpid() -> u32 {
    999
}

fn main() -> Result<()> {
    let my_pid = unsafe { libc::getpid() };
    println!("application pid is {my_pid}");

    let executable_entry = find_executable().ok_or(anyhow!("unable to find target executable"))?;
    println!("successfully identified executable");

    let dyn_lib = DynamicLibrary::initialize(executable_entry)?;
    println!("successfully initialied dynamic library for instrumentation");

    let target_function =
        dyn_lib.try_find_function("getpid").ok_or(anyhow!("unable to find getpid symbol"))?;
    println!(
        "successfully identified libc getpid offset: {:#X?}",
        target_function.r_offset
    );

    let base_addr = dyn_lib.library().addr();
    let plt_fn_ptr = (base_addr + target_function.r_offset as usize) as *mut *mut c_void;
    let page_size = unsafe { libc::sysconf(libc::_SC_PAGE_SIZE) as usize };
    let plt_page = ((plt_fn_ptr as usize / page_size) * page_size) as *mut c_void;
    println!("page start for function is {plt_page:#X?}");

    let _stored_address = unsafe {
        // Set the memory page to read, write
        let prot_res = libc::mprotect(plt_page, page_size, libc::PROT_WRITE | libc::PROT_READ);
        if prot_res != 0 {
            println!("protection res: {prot_res}");
            return Err(anyhow!("mprotect to rw"));
        }

        // Replace the function address
        let previous_address = std::ptr::replace(plt_fn_ptr, getpid as *mut _);

        // Set the memory page protection back to read only
        let prot_res = libc::mprotect(plt_page, page_size, libc::PROT_READ);
        if prot_res != 0 {
            return Err(anyhow!("mprotect to r"));
        }

        previous_address as *const c_void
    };

    let get_pid = unsafe { libc::getpid() };
    println!("new pid is: {get_pid}");

    Ok(())
}
application pid is 127765
successfully identified executable
successfully initialied dynamic library for instrumentation
successfully identified libc getpid offset: 0x7E460
page start for function is 0x000061019c41b000
new pid is: 999

参考/灵感来源

在开发此库时参考和受到启发的项目。

依赖项

~275–770KB
~18K SLoC