安卓逆向——Frida的进阶用法
字数 840 2025-08-22 12:23:18

Frida进阶用法:Native层Hook与修改指南

一、Hook Native函数基础

1.1 基本Hook流程

  1. 定位目标函数:使用Module.findExportByName()获取目标函数地址
  2. 附加拦截器:使用Interceptor.attach()附加回调函数
  3. 处理参数和返回值:在onEnteronLeave回调中操作
var strcmp_adr = Module.findExportByName("libc.so", "strcmp");
Interceptor.attach(strcmp_adr, {
    onEnter: function(args) {
        console.log("Hooking the strcmp function");
        var flag = Memory.readUtf8String(args[1]);
        console.log("The flag is " + flag);
    },
    onLeave: function(retval) {
    }
});

1.2 过滤特定调用

通过检查参数值来过滤无关调用:

Interceptor.attach(strcmp_adr, {
    onEnter: function(args) {
        var arg0 = Memory.readUtf8String(args[0]);
        var flag = Memory.readUtf8String(args[1]);
        if(arg0.includes("HELLO")) {
            console.log("Hooking the strcmp function");
            console.log("Input " + arg0);
            console.log("The flag is " + flag);
        }
    }
});

二、修改Native函数返回值

2.1 修改返回值方法

onLeave回调中使用retval.replace()修改返回值:

var check_flag = Module.findExportByName("liba0x9.so", "Java_com_ad2001_a0x9_MainActivity_check_1flag");
Interceptor.attach(check_flag, {
    onLeave: function(retval) {
        console.log("Original return value:" + retval);
        retval.replace(1337); // 修改返回值为1337
    }
});

2.2 完整模板

Interceptor.attach(targetAddress, {
    onEnter: function(args) {
        console.log('Entering ' + functionName);
    },
    onLeave: function(retval) {
        console.log('Leaving ' + functionName);
        retval.replace(value); // 修改返回值
    }
});

三、调用Native函数

3.1 调用流程

  1. 获取函数地址
  2. 创建NativePointer对象
  3. 创建NativeFunction对象
  4. 调用函数
var adr = Module.findBaseAddress("libfrida0xa.so").add(0x1DD60);
var get_flag_ptr = new NativePointer(adr);
const get_flag = new NativeFunction(get_flag_ptr, 'void', ['int', 'int']);
get_flag(1, 2);

3.2 完整模板

var native_adr = new NativePointer(<address_of_the_native_function>);
const native_function = new NativeFunction(native_adr, '<return type>', ['argument_data_type']);
native_function(<arguments>);

四、修改Native指令

4.1 修改指令步骤

  1. 获取指令地址
  2. 修改内存保护属性
  3. 使用ARM64Writer修改指令
  4. 刷新并释放资源
var jnz_adr = Module.getBaseAddress("libfrida0xb.so").add(0x170CE);
Memory.protect(jnz_adr, 0x1000, "rwx");
var writer = new Arm64Writer(jnz_adr);
try {
    writer.putNop(); // 将jnz指令替换为NOP
    writer.flush();
    console.log("Command modification successful.");
} finally {
    writer.dispose();
}

4.2 完整模板

var writer = new ARM64Writer(<address_of_the_instruction>);
try {
    /* 自定义指令实现 */
    writer.flush();
} finally {
    writer.dispose();
}

五、实用API参考

5.1 函数地址获取方法

  1. 从导出表获取

    Module.findExportByName("libc.so", "strcmp")
    Module.getExportByName("libc.so", "strcmp") // 找不到会抛出异常
    
  2. 从导入表获取

    Module.enumerateImports("libfrida0x8.so")[4]["address"]
    
  3. 基地址+偏移量

    Module.getBaseAddress("libfrida0x8.so").add(0x864)
    

5.2 内存操作API

  1. 读取内存字符串

    Memory.readUtf8String(address)
    
  2. 修改内存保护

    Memory.protect(address, size, "rwx")
    

六、实战技巧

  1. 处理ASLR:Android的地址空间随机化会导致每次运行地址不同,建议使用基地址+偏移量的方式

  2. 错误处理:使用try-finally确保资源释放

  3. 性能考虑:在Hook频繁调用的函数时,尽量减少日志输出

  4. 多架构支持:注意区分ARM和x86架构的指令差异

  5. 调试技巧:使用console.log()输出关键变量值辅助调试

七、总结

Frida在Native层的Hook能力非常强大,通过掌握这些进阶用法,可以:

  1. 拦截和修改任意Native函数调用
  2. 动态修改程序逻辑
  3. 调用未暴露的Native函数
  4. 修改机器指令改变程序行为

关键是要理解Native函数调用的原理和内存操作的基本概念,结合具体场景灵活运用这些技术。

Frida进阶用法:Native层Hook与修改指南 一、Hook Native函数基础 1.1 基本Hook流程 定位目标函数 :使用 Module.findExportByName() 获取目标函数地址 附加拦截器 :使用 Interceptor.attach() 附加回调函数 处理参数和返回值 :在 onEnter 和 onLeave 回调中操作 1.2 过滤特定调用 通过检查参数值来过滤无关调用: 二、修改Native函数返回值 2.1 修改返回值方法 在 onLeave 回调中使用 retval.replace() 修改返回值: 2.2 完整模板 三、调用Native函数 3.1 调用流程 获取函数地址 创建NativePointer对象 创建NativeFunction对象 调用函数 3.2 完整模板 四、修改Native指令 4.1 修改指令步骤 获取指令地址 修改内存保护属性 使用ARM64Writer修改指令 刷新并释放资源 4.2 完整模板 五、实用API参考 5.1 函数地址获取方法 从导出表获取 : 从导入表获取 : 基地址+偏移量 : 5.2 内存操作API 读取内存字符串 : 修改内存保护 : 六、实战技巧 处理ASLR :Android的地址空间随机化会导致每次运行地址不同,建议使用基地址+偏移量的方式 错误处理 :使用 try-finally 确保资源释放 性能考虑 :在Hook频繁调用的函数时,尽量减少日志输出 多架构支持 :注意区分ARM和x86架构的指令差异 调试技巧 :使用 console.log() 输出关键变量值辅助调试 七、总结 Frida在Native层的Hook能力非常强大,通过掌握这些进阶用法,可以: 拦截和修改任意Native函数调用 动态修改程序逻辑 调用未暴露的Native函数 修改机器指令改变程序行为 关键是要理解Native函数调用的原理和内存操作的基本概念,结合具体场景灵活运用这些技术。