← 返回首页
Android JNI Native

安卓 JNI / Native Bridge 逆向:别卡在 Java 层,要顺着桥往下走

Android 逆向里有个特别典型的断点:Java 层明明已经追到一个很可疑的方法,结果点进去只看到 native,很多人就在这里开始掉线。其实问题不在于 JNI 多神秘,而在于你没把它当成一座“桥”来看——桥的上面、桥本身、桥下面,都要连起来。

先说结论:JNI 逆向不是跳层,是连层

很多人把 Java 层和 so 层当成两个世界。实际上更好的理解是:

Java 入口 -> native 声明 -> JNI 注册/绑定 -> 参数转换 -> Native 核心逻辑

你如果只盯 Java,看不到真正算法;只盯 so,又很容易不知道谁在什么场景下调用它。真正有用的是把整条桥连起来。

第一步:先确认这座桥怎么连的

JNI 绑定通常有两种典型路径:

不先分清这点,后面很容易找错入口。

静态注册的信号

动态注册的信号

第二步:别急着进算法,先看参数怎么过桥

JNI 场景里特别容易误判的一点是:你以为你看到的是“算法入口”,其实你看到的可能只是参数搬运层。

常见情况包括:

如果你不先搞清 Java 参数到了 native 层后变成什么,后面看算法很容易对不上号。

第三步:区分“桥”和“核心”

很多 native 方法其实只干两件事:

这时候最关键的问题就不是“这个 JNI 方法看不看得懂”,而是:

如果你只停在桥上,很容易把包装层误当核心层。

第四步:回到 Java 层确认调用场景

为什么同一个 native 函数,有时候看起来很复杂?因为它可能被多个场景共用。

所以你还得回头看 Java 层:

一旦场景不清楚,你在 native 层看到的很多分支就会显得很乱。

特别高频的几个逆向目标

1. 找签名/加密逻辑

很多 Android 应用会把关键签名、摘要、加密逻辑下沉到 so 层。你要重点看:

2. 找设备信息采集

有些字段表面在 Java 层拿,真正整理和混淆在 native 层做。别只停留在 Java API 名字上。

3. 找校验放行点

很多人会在 Java 层 patch 布尔值,但更稳的方法往往是先看 native 返回值和错误码生成位置。

最容易犯的错误

我更推荐的排查顺序

  1. 先在 Java 层锁定可疑调用点
  2. 确认是静态注册还是动态注册
  3. 把 Java 参数和 native 参数一一对齐
  4. 找到桥下面真正的核心函数
  5. 最后再决定静态深挖还是动态 hook

这套顺序的核心不是复杂,而是稳:先把桥接关系理顺,再深挖实现细节。

给新手的一句最实在的话

如果你现在卡在一个 native 方法上,先别急着感叹“so 好难”。先问自己:

  1. 这个方法是怎么注册进去的?
  2. Java 参数到了 native 层后变成了什么?
  3. 我看到的是桥接层,还是核心计算层?
JNI 真正折磨人的,不是代码本身,而是你如果不连层看,就会一直在桥上打转。

结尾

Android 的 JNI / Native Bridge 逆向,说到底不是“Java 不会 so、so 不会 Java”的问题,而是你要学会把两边连成一条完整链路。

一旦你把这条链路理清,很多本来很像迷宫的问题,都会落成几个特别具体的工程问题:

到这个颗粒度,JNI 也就不再是玄学桥段,而是正常可拆的工作流。

上一篇协议重放失败排查:别反复补 header,先把失败归因分层 下一篇RegisterNatives 定位思路:JNI 动态注册别只看 OnLoad,要把绑定表掏出来