Frida-Labs-Native层操作指南
字数 1112 2025-08-29 22:41:24

Frida Native层操作指南

1. Native层函数Hook基础

1.1 基本Hook模板

Interceptor.attach(targetAddress, {
    onEnter: function(args) {
        console.log("正在进入函数");
        // 可以查看和修改传入参数
    },
    onLeave: function(retval) {
        console.log("正在离开函数");
        // 可以查看和修改返回值
    }
});

1.2 获取函数地址的方法

  1. Module.enumerateExports()

    • 获取导出函数的名称、地址等信息
    • 适用于查找模块自身导出的函数
  2. Module.getExportByName()

    • 通过函数名获取导出项地址
    • 找不到会抛出异常
  3. Module.findExportByName()

    • 通过函数名获取导出项地址
    • 找不到返回null
  4. Module.getBaseAddress()

    • 获取模块基址地址
    • 可用于基于偏移量的计算
  5. Module.enumerateImports()

    • 获取模块导入的外部函数/变量信息

1.3 实际应用示例

Hook libc.so中的strcmp函数:

var strcmp = Module.findExportByName("libc.so", "strcmp");
Interceptor.attach(strcmp, {
    onEnter: function(args) {
        // 增加条件判断,避免hook所有strcmp调用
        if(Memory.readUtf8String(args[0]).includes("666")) {
            console.log("strcmp参数2:", Memory.readUtf8String(args[1]));
        }
    }
});

2. 函数返回值修改

修改Native层函数的返回值:

var check_flag = Module.enumerateExports("liba0x9.so")[0]["address"];
Interceptor.attach(check_flag, {
    onLeave: function(retval) {
        if(retval.toInt32() === 1337) {
            console.log("Flag found!");
        }
        // 修改返回值
        retval.replace(1);
    }
});

3. 导入表与导出表

  • 导入表(Imports): 模块调用的外部函数
  • 导出表(Exports): 模块对外提供的函数

查看导出表示例:

var exports = Module.enumerateExports("liba0x9.so");
exports.forEach(function(exp) {
    console.log("Name:", exp.name, "Address:", exp.address);
});

4. Hook未调用的Native方法

4.1 直接调用Native函数

var native_adr = new NativePointer(<address_of_the_native_function>);
var native_func = new NativeFunction(native_adr, <return_type>, ['argument_data_type']);
var result = native_func(<arguments>);

4.2 查找并调用get_flag函数示例

var base = Module.findBaseAddress("libfrida0xa.so");
var exports = Module.enumerateExports("libfrida0xa.so");
for(var i = 0; i < exports.length; i++) {
    if(exports[i].name === "_Z8get_flagii") { // C++ name mangling
        console.log("get_flag地址:", exports[i].address);
        console.log("偏移:", exports[i].address - base);
        
        var get_flag = new NativeFunction(exports[i].address, 'void', ['int', 'int']);
        get_flag(0, 0); // 调用函数
        break;
    }
}

5. C++ Name Mangling问题

C++编译器会对函数名进行重整(name mangling),例如:

  • int add(int a, int b)_Z3addii
  • float add(float a, float b)_Z3addff

在Hook时需要特别注意使用正确的重整名称。

6. Hook Android日志函数

直接截获__android_log_print的输出:

var android_log_print = Module.findExportByName("liblog.so", "__android_log_print");
Interceptor.attach(android_log_print, {
    onEnter: function(args) {
        // 第四个参数是日志内容
        console.log("Log:", Memory.readUtf8String(args[3]));
    }
});

7. 修改Native层汇编指令

7.1 x86架构模板

var writer = new X86Writer(opcodeaddr);
Memory.patchCode(opcodeaddr, 0x1000, function(code) {
    try {
        // 写入汇编指令
        writer.putNop();
        writer.putRet();
        writer.flush();
    } finally {
        writer.dispose();
    }
});

7.2 ARM64架构示例

修改跳转指令(如nop掉B.NE):

var target = base.add(0x15248); // 偏移地址
Memory.patchCode(target, 4, function(code) {
    var writer = new Arm64Writer(code, {pc: target});
    try {
        writer.putNop(); // 替换B.NE为NOP
        writer.flush();
    } finally {
        writer.dispose();
    }
});

8. 关键注意事项

  1. 权限问题: 修改代码段前需要设置内存为可写(rwx)
  2. 架构差异: x86和ARM64的汇编指令不同
  3. 地址随机化(ASLR): 使用基地址+偏移量的方式更可靠
  4. 资源释放: 使用完Writer后必须调用dispose()
  5. 线程安全: 修改运行时代码需谨慎,可能导致崩溃

9. 实用技巧

  1. 批量Hook: 遍历导出表批量Hook特定模式的函数
  2. 条件Hook: 增加条件判断避免Hook无关调用
  3. 日志过滤: 结合logcat命令查看完整输出
  4. 错误处理: 添加try-catch防止脚本崩溃
  5. 性能优化: 避免在频繁调用的函数中执行复杂操作

通过以上方法,可以有效地对Android应用的Native层进行Hook、分析和修改,实现各种安全分析和逆向工程目的。

Frida Native层操作指南 1. Native层函数Hook基础 1.1 基本Hook模板 1.2 获取函数地址的方法 Module.enumerateExports() 获取导出函数的名称、地址等信息 适用于查找模块自身导出的函数 Module.getExportByName() 通过函数名获取导出项地址 找不到会抛出异常 Module.findExportByName() 通过函数名获取导出项地址 找不到返回null Module.getBaseAddress() 获取模块基址地址 可用于基于偏移量的计算 Module.enumerateImports() 获取模块导入的外部函数/变量信息 1.3 实际应用示例 Hook libc.so中的strcmp函数: 2. 函数返回值修改 修改Native层函数的返回值: 3. 导入表与导出表 导入表(Imports) : 模块调用的外部函数 导出表(Exports) : 模块对外提供的函数 查看导出表示例: 4. Hook未调用的Native方法 4.1 直接调用Native函数 4.2 查找并调用get_ flag函数示例 5. C++ Name Mangling问题 C++编译器会对函数名进行重整(name mangling),例如: int add(int a, int b) → _Z3addii float add(float a, float b) → _Z3addff 在Hook时需要特别注意使用正确的重整名称。 6. Hook Android日志函数 直接截获__ android_ log_ print的输出: 7. 修改Native层汇编指令 7.1 x86架构模板 7.2 ARM64架构示例 修改跳转指令(如nop掉B.NE): 8. 关键注意事项 权限问题 : 修改代码段前需要设置内存为可写(rwx) 架构差异 : x86和ARM64的汇编指令不同 地址随机化(ASLR) : 使用基地址+偏移量的方式更可靠 资源释放 : 使用完Writer后必须调用dispose() 线程安全 : 修改运行时代码需谨慎,可能导致崩溃 9. 实用技巧 批量Hook : 遍历导出表批量Hook特定模式的函数 条件Hook : 增加条件判断避免Hook无关调用 日志过滤 : 结合logcat命令查看完整输出 错误处理 : 添加try-catch防止脚本崩溃 性能优化 : 避免在频繁调用的函数中执行复杂操作 通过以上方法,可以有效地对Android应用的Native层进行Hook、分析和修改,实现各种安全分析和逆向工程目的。