百趣云 百趣云的博客

jnitrace 实战:把 JNI 层的每一次调用都看光

JNI 层是 Java 与 SO 的边境检查站

分析带 native 签名的 App 时,最有价值的信息都发生在 JNI 边界:Java 层把什么参数传进了 SO,SO 又把什么结果还了回来。jnitrace 这个 Frida 工具就是干这个的——自动 hook 所有 JNI 函数调用,打印参数和返回值

pip install jnitrace
jnitrace -l libtarget.so com.target.app

-l 指定要跟踪的 SO。跑起来后,目标 SO 的每一次 JNI 调用(FindClass、GetMethodID、CallObjectMethod、NewStringUTF……)全部实时打印。

输出怎么读

           /* TID 12345 */
   12345 ms  JNIEnv->FindClass("com/xxx/SignUtils")
   12345 ms  JNIEnv->GetMethodID(0x1234, "getSign", "(Ljava/lang/String;)Ljava/lang/String;")
   12346 ms  JNIEnv->NewStringUTF("timestamp=1787968800&data=...")
   12346 ms  JNIEnv->CallObjectMethod(0x1234, 0x5678, 0x9abc)
   12347 ms  JNIEnv->GetStringUTFChars(0x9abc) => "a8f5c3...签名结果"

这一小段就讲完了整个故事:Java 层传了 timestamp=...&data=... 进 native,native 返回了签名结果。签名算法的输入输出格式不用逆 SO 就拿到了

精髓一:用 jnitrace 做"算法黑盒分析"

拿到输入输出后,立刻做对照实验:

  1. 固定输入,多次调用看输出是否变化(判断有没有随机数/时间戳参与)
  2. 改输入的一个字符,看输出变化范围(雪崩效应明显 = 标准哈希/加密;只变几位 = 自定义简单变换)
  3. 输入全 0、全 F 等特征值,看输出模式(识别算法家族)

这三板斧下来,不用打开 IDA 就能判断算法类型,决定是"手搓还原"还是"Frida 直调"。

精髓二:过滤噪音

jnitrace 全量输出非常吵(App 的 JNI 调用每秒几百次),过滤是关键:

# 只看指定方法相关的调用
jnitrace -l libtarget.so -m "getSign|check" com.target.app

# 忽略某些 JNI 函数(字符串操作类最吵)
jnitrace -l libtarget.so -i "GetStringUTFChars" -i "NewStringUTF" com.target.app

# 输出到文件慢慢分析
jnitrace -l libtarget.so -o trace.log com.target.app

实战节奏:先全量跑一遍摸清调用规模,然后逐步加过滤条件收敛到目标方法附近。

精髓三:配合 RegisterNatives 定位

jnitrace 还能抓动态注册——输出里的 RegisterNatives 调用会列出所有方法名和地址。这和我之前讲的手动 hook RegisterNatives 是同一个信息,但 jnitrace 零成本:

12350 ms  JNIEnv->RegisterNatives(0x1234, 0x7f8abc, 3)
            method[0] = getSign (Ljava/lang/String;)Ljava/lang/String; @ 0x7f12345000
            method[1] = check (I)Z @ 0x7f12346000

拿到地址后 模块基址 + 偏移 算出 IDA 里的位置,直接跳过去看实现。

与其他工具的组合拳

  • jnitrace 拿输入输出 → 判断算法类型
  • Frida hook 具体 native 函数 → 验证猜测(改输入看输出)
  • IDA 静态分析 → 彻底理解算法(需要手搓时)
  • unidbg 模拟执行 → 需要脱离设备批量调用时

jnitrace 是这条链路的侦察兵,花十分钟跑一遍,后面每一步的方向都清晰了。

总结

  1. jnitrace 自动 hook 全部 JNI 调用,Java↔SO 边界的参数返回值全透明
  2. 黑盒分析三板斧:固定输入看稳定性、改输入看雪崩、特征输入看模式
  3. 用 -m/-i 过滤收敛噪音,先全量后聚焦
  4. RegisterNatives 输出直接给 native 函数地址,衔接 IDA

交流微信:run1255

By 百趣云 阅读量:2 On