unidbg快速入门使用 so直接调用 ndk调试 unidbg实在太强大太方便辣
现在很多app都把核心加密放到了so层,如果是Java层主动调用ndk的形式运行的话,用unidbg直接调用会很方便unidbg github地址 https://github.com/zhkl0228/unidbg下载好后,用idea打开(需要预先配置好maven,这里不多说),最好上个机场,下载配置会快一点全部搞定之后,到这个路径(C:\Users\Administrator\Desktop\
现在很多app都把核心加密放到了so层,如果是Java层主动调用ndk的形式运行的话,用unidbg直接调用会很方便
致谢
unidbg github地址 https://github.com/zhkl0228/unidbg
蟹蟹成哥的帮助 https://www.cnblogs.com/xbjss/p/12110083.html
还有肉丝姐的星球有好多干货
开始
下载好后,用idea打开(需要预先配置好maven,这里不多说),最好上个机场,下载配置会快一点
全部搞定之后,到这个路径
(C:\Users\Administrator\Desktop\unidbg-master\unidbg-android\src\test\java\com\bytedance\frameworks\core\encrypt\TTEncrypt.java)
跑一遍,能跑通就是配置完成了
代码部分
初始化
直接看代码
TTEncrypt(boolean logging) {
this.logging = logging;//是否log
emulator = new AndroidARMEmulator("com.qidian.dldl.official"); // 创建模拟器实例,要模拟32位或者64位,在这里区分
final Memory memory = emulator.getMemory(); // 模拟器的内存操作接口![在这里插入图片描述](https://img-blog.csdnimg.cn/20201104103449870.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjQ1MzkwNQ==,size_16,color_FFFFFF,t_70#pic_center)
memory.setLibraryResolver(new AndroidResolver(23)); // 设置系统类库解析
vm = emulator.createDalvikVM(null); // 创建Android虚拟机
vm.setVerbose(logging); // 设置是否打印Jni调用细节
DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/resources/example_binaries/libttEncrypt.so"), false); // 加载libttEncrypt.so到unicorn虚拟内存,加载成功以后会默认调用init_array等函数
dm.callJNI_OnLoad(emulator); // 手动执行JNI_OnLoad函数
module = dm.getModule(); // 加载好的libttEncrypt.so对应为一个模块
TTEncryptUtils = vm.resolveClass("com/bytedance/frameworks/core/encrypt/TTEncryptUtils");//注册调用类
}
- AndroidARMEmulator模拟器名字可以随便的
- createDalvikVM(File file) 这个函数的file是apk文件,有些签名验证的部分可以通过导入apk文件来让他自动获取签名(成哥教的)
- vm.loadLibrary加载类的路径可以通过idea直接右键复制,注意斜杠
- vm.resolveClass调用的类需要跟调用so的类一模一样,在jadx中的smail代码模式可以复制到
初始化完成后就是主动调用的部分了.主要是下面这一句话
主动调用
ByteArray array = TTEncryptUtils.callStaticJniMethodObject(emulator, "ttEncrypt([BI)[B", new ByteArray(vm, data), data.length); // 执行Jni方法
- ttEncrypt([BI)[B 是so中的方法
- ttEncrypt是方法名
- [BI是参数 byte[] , int
- [B是返回值
也是可以从jadx中的smail代码模式可以复制到
传参
如果全都没错,而且是静态注册的话,已经可以正常跑起来了.
上面是byte和int 如果传其它参数的话这边大概有个参考
- Context
DvmObject context = vm.resolveClass("android/content/Context").newObject(null);
vm.addLocalObject(context);
- String
vm.addLocalObject(new StringObject(vm, "123"));
解决报错
毕竟第一次使用,肯定会有各种各样的报错
- vm.setJni
直接按照上面写的话有可能会出现这个关键词的报错
把
vm.setJni(this);
添加到初始化部分的代码中
- java.lang.UnsupportedOperationException: com.xxx.object->getPackageManager()Landroid/content/pm/PackageManager;
这里的错误是我的so进行了签名验证,但是我只加载了so文件,他没
Landroid/content/pm/PackageManager
这个方法,就报错了
可以通过重写部分函数来把环境补齐
public DvmObject callObjectMethodV(BaseVM vm, DvmObject dvmObject, String signature, VaList vaList) {
if (signature.contains("->getPackageManager()Landroid/content/pm/PackageManager;")) {
return vm.resolveClass("Landroid/content/pm/PackageManager;").newObject(null);
}
return dvmObject;
}
因为extends AbstractJni 继承了AbstractJni,可以看看AbstractJni 中有什么可以重写的然后把so中需要的环境补齐,有时候可以返回空对象,有时候可以手动生成一个对象传过去给他调用
可以通过输出signature来确定走了哪些地方是跟java层有关的
优化
public static void main(String[] args) throws Exception {
// for (int i = 0; i <100 ; i++) {
Long time1 = new Date().getTime();
XXEncrypt test = new XXEncrypt();
test.test();
test.destroy();
System.out.println(new Date().getTime() - time1);
// }
}
调用的时候可以创建对象之后多次调用,这样就不用浪费创建对象的时间了,因为要创建个虚拟机所以耗时还是挺大了,至少可以节省100~200ms,实际调用的时间就可以降低到20ms左右了
但是,unidbg作者说了,unicron有内存泄漏的风险,所以这个对象是需要定期更换的,这个大家自己动动脑子咯
最后
unidbg实在太强大太方便辣
我加了个unidbg-web的服务,把主动调用变成可直接调用的接口,还能直接打包放到线上服务器上~
可以看下一篇(还没写)
更多推荐
所有评论(0)