最近帮群友逆向一个 APP,加密参数都已经分析出来了,唯独缺一个加密算法。
后面在一堆 SO 文件里找到了目标,IDA 加载一看——混淆非常严重,纯算法还原太耗时间。于是决定直接调用 SO 文件中的加密方法,走模拟执行路线。
0 获取调用链
通过 JEB 或 MT 文件管理器加载 APK 后反编译,定位到目标 SO 文件路径。

根据路径可以初步判断这是一个 JNI 库。接下来用 nm -D查看 JNI 导出的函数名称:
▸ Shell 命令
nm -D libsu.so | grep encrypt

可以看到是静态注册的方式,理论上可以直接用 Java 调用这个 JNI 方法。
1 直接调用(Java 方式)
先尝试最直观的方案:直接用 Java 加载 SO 文件并调用 native 方法。
▸ NativeDemo.java
public class NativeDemo { static { System.load("C:\\sofile\\libsu.so"); } public native String encrypt(String input, String salt); public static void main(String[] args) { NativeDemo demo = new NativeDemo(); String input = "test"; String salt = "123456"; System.out.println(demo.encrypt(input, salt)); }}
编译运行后报错:

AMD-64 平台无法加载 ARM64 SO 文件的错误信息
⚠️ 报错原因无法在 AMD-64 平台调用 ARM64 架构的 SO 文件。这是安卓原生库与桌面 Java 环境的架构差异导致的,直接加载方案行不通。
不可能为了调用一个方法单独起个 APP 去跑,所以必须换方案——模拟安卓环境。
2 模拟安卓环境(Unidbg)
Unidbg 基于 Unicorn 引擎,可以模拟安卓原生库的执行环境,支持 ARM/ARM64 架构。
相关项目Unidbg 项目:https://github.com/zhkl0228/unidbgUnicorn 项目:https://www.unicorn-engine.org/需要 JDK 1.8 + Maven 环境,拉取项目后在本地编译。
▸ Maven 编译命令
& "C:\Program Files\JetBrains\IntelliJ IDEA 2026.1.1\plugins\maven\lib\maven3\bin\mvn.cmd" install "-Dgpg.skip=true" "-DskipTests"

编译完成后 unidbg-android 依赖已安装到本地 Maven 仓库
编译完成后,在项目中引入依赖:
▸ pom.xml 依赖配置
<dependency> <groupId>com.github.zhkl0228</groupId> <artifactId>unidbg-android</artifactId> <version>0.9.10-SNAPSHOT</version></dependency>
然后编写 Unidbg 调用引擎:
▸ UnidbgEngineContext.java
package cn.mxpy;import com.github.unidbg.AndroidEmulator;import com.github.unidbg.Module;import com.github.unidbg.linux.android.AndroidEmulatorBuilder;import com.github.unidbg.linux.android.dvm.*;import com.github.unidbg.memory.Memory;import com.github.unidbg.linux.android.AndroidResolver;import java.io.File;import java.io.IOException;public class UnidbgEngineContext extends AbstractJni { private final AndroidEmulator emulator; private final VM vm; private final DalvikModule dm; private final Module module; public UnidbgEngineContext() throws IOException { emulator = AndroidEmulatorBuilder .for64Bit() .setProcessName("com.xxxx.xxxx") .build(); Memory memory = emulator.getMemory(); memory.setLibraryResolver(new AndroidResolver(23)); vm = emulator.createDalvikVM(); vm.setJni(this); vm.setVerbose(false); File soFile = new File("C:\\Users\\i\\sofile\\libsu.so"); dm = vm.loadLibrary(soFile, false); module = dm.getModule(); dm.callJNI_OnLoad(emulator); } public String encrypt(String arg0, String arg1) { DvmClass clazz = vm.resolveClass("com/xxx/xx/xxx"); StringObject result = clazz.callStaticJniMethodObject( emulator, "encrypt(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", new StringObject(vm, arg0), new StringObject(vm, arg1) ); return result.getValue(); }}
在 App.java 中调用测试:
▸ App.java
package cn.mxpy;import java.io.IOException;public class App { public static void main(String[] args) throws IOException { System.out.println("Hello World!"); UnidbgEngineContext unidbgEngineContext = new UnidbgEngineContext(); System.out.println(unidbgEngineContext.encrypt("1", "1")); }}

控制台输出加密后的字符串,证明调用成功
调用成功!
3 集成 SpringBoot 提供 HTTP 接口
将 Unidbg 与 SpringBoot 结合,把 SO 库中的加密方法封装成 HTTP 服务,供外部调用。

Controller 层接收参数,调用 UnidbgEngine 返回加密结果
通过 HTTP 请求即可获取加密结果:
▸ HTTP 调用示例
GET /api/encrypt?input=test&salt=123456→ 返回加密后的字符串
4 总结与注意事项Unidbg 实例初始化耗时较长,本地测试约 7-8 秒,云主机约 12 秒左右。生产环境建议做实例池化或预热。另外 Unidbg 存在 "老化" 问题(长时间运行后稳定性下降),需要定期重启或维护。
夜雨聆风