【安卓逆向】模拟安卓环境调用SO库
原创
墨雪飘影
墨雪飘影
墨雪飘影
2026年7月10日 08:42
湖北
在小说阅读器读本章
去阅读
最近帮群友逆向一个 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/unidbg
Unicorn 项目: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 依赖配置
unidbg-android
然后编写 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 存在 \"老化\" 问题(长时间运行后稳定性下降),需要定期重启或维护。
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。











评论