Frida 玩转 JNI:方法地址追踪 + 指令反汇编 + Patch 注入

版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/

Frida 反汇编

Frida 提供了反汇编 API,主要用于对目标进程的代码进行动态分析,例如:

  • 获取函数的机器代码并将其反汇编为汇编指令。

  • 分析内存中的指令流。

这些功能在 Frida 的 Instruction 类中实现,基于 Capstone 实现的反汇编功能。

https://frida.re/docs/javascript-api/#instruction

word/media/image1.png

比如,可以通过 Instruction.parse 方法反汇编指定地址的汇编信息

[Remote::AndroidExample]-> Instruction.parse(ptr("0x7e7acdb9a0"));
{
    "address": "0x7e7acdb9a0",
    "groups": [],
    "mnemonic": "sub",
    "next": "0x7e7acdb9a4",
    "opStr": "sp, sp, #0x10",
    "operands": [
        {
            "type": "reg",
            "value": "sp"
        },
        {
            "type": "reg",
            "value": "sp"
        },
        {
            "type": "imm",
            "value": "16"
        }
    ],
    "regsRead": [],
    "regsWritten": [],
    "size": 4
}

Android 示例代码

定义一个 native 函数 add,计算 1+ 1 + 1 并返回结果。

把 add 函数动态注册到 com.cyrus.example.frida.disassemble.FridaDisassembleActivity#add。

#include <jni.h>
#include <android/log.h>

#define LOG_TAG "FridaDisassemble"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

// 实现 add 方法:计算 1 + 1 + 1
jint native_add(JNIEnv *env, jobject obj) {
    return 1 + 1 + 1;
}

// 定义 JNI 方法映射
static const JNINativeMethod methods[] = {
        {"add", "()I", (void *)native_add} // 方法名, 方法签名, C++函数指针
};

// 动态注册 JNI 方法
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
    JNIEnv *env;
    if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
        return JNI_ERR;
    }

    // 获取 Java 类
    jclass clazz = env->FindClass("com/cyrus/example/frida/disassemble/FridaDisassembleActivity");
    if (clazz == nullptr) {
        LOGD("[-] Failed to find class FridaDisassembleActivity");
        return JNI_ERR;
    }

    // 注册 native 方法
    if (env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
        LOGD("[-] Failed to register native methods");
        return JNI_ERR;
    }

    LOGD("[+] Successfully registered native methods");
    return JNI_VERSION_1_6;
}

在 kotlin 层调用 add 函数并 toast 结果。

// 调用 native 方法
val result = add()
// 显示 Toast
Toast.makeText(this, "add() returned: $result", Toast.LENGTH_LONG).show()

当点击按钮可以看到返回结果 3。

word/media/image2.png

接下来通过 Frida 实现:

  1. 找到 add 函数动态注册的地址

  2. 反汇编 add 函数机器码

  3. patch add 函数汇编指令修改返回结果

JNI 方法地址跟踪

1. 启动 Frida Server

# 启用超级管理员
adb root

# 进入命令行
adb shell 

# 启动frida-server,并指定端口
/data/local/tmp/fs -l 0.0.0.0:1234

# 端口转发到本地
adb forward tcp:1234 tcp:1234

Frida 的详细使用参考这篇文章:

### 使用 Frida 进行 JNI Hook 的方法 Frida 是一种强大的动态工具,允许开发者在运行时注入 JavaScript 脚本到原生应用程序中。通过 Frida 可以实现对 Java 和本地代码 (C/C++) 的钩子功能。以下是关于如何使用 FridaAndroid 应用程序中的 JNI 函数进行 Hook 的详细介绍。 #### 什么是 JNI? Java Native Interface (JNI) 提供了一种机制,使 Java 方法可以调用本地 C 或 C++ 编写的函数[^3]。由于许多 Android 应用依赖于这些本地来执行性能敏感的操作或者访问特定硬件特性,因此 Hook JNI 函数对于逆向工程和安全分析非常重要。 #### 如何设置 Frida 环境 要开始使用 Frida 钩住 JNI 函数,首先需要安装并配置好环境: 1. **安装 Frida 工具链** - 安装 Python 版本的 Frida CLI 工具。 ```bash pip install frida-tools ``` - 将目标设备连接至计算机并通过 USB 调试启用它。 2. **验证 Frida 是否能正常工作** - 执行 `frida-ps` 命令查看当前正在运行的应用列表。 #### 实现 JNI Hook 的基本流程 为了拦截某个具体的 JNI 函数,通常按照如下方式编写脚本: 1. **加载应用进程** 利用 Frida API 加载指定包名的目标应用实例。 ```javascript const appPackage = 'com.example.targetapp'; let session; try { session = await frida.attach(appPackage); } catch(e){ console.error('Failed to attach:', e.message); } ``` 2. **定位 SO 文件及其导出符号** 大多数情况下,JNI 接口会被封装在一个 `.so` 动态链接里。可以通过枚举模块找到对应的共享对象文件位置以及其中定义的方法名称。 ```javascript session.enumerateModules().forEach(module => { if (/libnative/.test(module.name)) { // Example regex pattern matching target library name. console.log(`Found module: ${module.base}`); } }); ``` 3. **Hook 导出函数** 当确认了具体哪个 so 文件包含了待 hook 的 native method 后,则可以直接对其入口地址实施拦截逻辑。 ```javascript Interceptor.replace(Module.findExportByName(null, "your_jni_function_name"), function(arg0,arg1,...argsN){ console.log("Arguments passed:", arg0, arg1, ...argsN); var result = this.original.apply(this, arguments); console.log("Result returned from original implementation:",result); return result; }); ``` 以上过程展示了怎样利用 Frida 来监控甚至修改某些关键性的 JNI 行为[^4]。 ```python def example_python_code(): pass ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值