安卓逆向工具之unidbg

前言部分

在2012-14年间,其间逆向过好多APP,但是对用C写成功的SO,我的处理方法是,直接写一个APK出来调用。
一直没有办法找到可以在WIN平台下跑SO的方法,这几天看了unidbg这个工具。实属是逆向工程的神器。
废话不多说,让我们来看看怎么用。下面是我转载的一篇通俗易懂的文章。

一、unidbg引入

逆向某App,反编译dex得到Java代码,但是有两个加密工具类中的方法放到so文件中。



方法的实现用的C语言编写的,放在了so文件中。在Java中,动态加载so文件,使用native方法的形式隐藏了方法的方法体。难道伟大的逆向工程就此放弃?这显然不符合我们技术人的性格,肯定要想方设法弄出来。
二、unidbg概述
unidbg 是一个基于 unicorn 的逆向工具,可以直接调用Android和iOS中的 so 文件。项目的GitHub地址为https://github.com/zhkl0228/unidbg
我使用unidbg,直接调用libbaseEncryptLib.so、libencryptLib.so中的方法,这样就不用想破脑袋去逆向so文件了。

备注:\color{red}备注:备注:so文件是unix系统中的动态连接库,属于二进制文件,作用相当于windows系统中的.dll文件。在Android中也可调用动态库文件(*.so),一般会将加密算法、密码等重要的方法、信息使用C语言编写,然后编译成so文件,增强了软件的安全性。

三、unidbg使用姿势

1、下载unidbg项目

下载地址:https://github.com/zhkl0228/unidbg

2、导入到IDEA中

unidbg项目用Java编写,并且上面下载的是一个标准的maven项目。我这里演示导入到IDEA中,如果你熟悉其它的IDE,也可以自己去弄。(顺带一提,如果你之前没接触过Java语言,要确保电脑安装好JDK、maven)

①、解压压缩包

②、打开IDEA,导入解压的项目

浏览到刚刚解压好的文件夹


后面一路无脑next即可。。。




第一次导入此项目会自动下载一些jar包,和网速、maven服务器有关,耐心等待吧。

3、测试unidbg

项目中的src/test/java/com/xxxx/frameworks/core/encrypt路径中有一个TTEncrypt测试用例,直接执行其中的main方法。

控制台打印相关调用信息,说明项目导入成功。

4、运行自己的so文件
在前面,我们不是遇到了libbaseEncryptLib.so、libencryptLib.so文件么,利用unidbg直接调用so文件中 的方法。下面演示调用libencryptLib.so文件中的getGameKey函数。

①、编写EncryptUtilsJni类

  1. package cn.hestyle;
  2.  
  3. import com.github.unidbg.Module;
  4. import com.github.unidbg.arm.ARMEmulator;
  5. import com.github.unidbg.linux.android.AndroidARMEmulator;
  6. import com.github.unidbg.linux.android.AndroidResolver;
  7. import com.github.unidbg.linux.android.dvm.*;
  8. import com.github.unidbg.memory.Memory;
  9.  
  10.  
  11. import java.io.File;
  12. import java.io.IOException;
  13.  
  14. /**
  15.  * description: EncryptUtils调用so
  16.  *
  17.  * @author hestyle
  18.  * @version 1.0
  19.  * @className unidbg->EncryptUtilsJni
  20.  * @date 2020-05-20 22:01
  21.  **/
  22. public class EncryptUtilsJni extends AbstractJni {
  23. // ARM模拟器
  24. private final ARMEmulator emulator;
  25. // vm
  26. private final VM vm;
  27. // 载入的模块
  28. private final Module module;
  29.  
  30. private final DvmClass TTEncryptUtils;
  31.  
  32. /**
  33.   *
  34.   * @param soFilePath 需要执行的so文件路径
  35.   * @param classPath 需要执行的函数所在的Java类路径
  36.   * @throws IOException
  37.   */
  38. public EncryptUtilsJni(String soFilePath, String classPath) throws IOException {
  39. // 创建app进程,包名可任意写
  40. emulator = new AndroidARMEmulator("cn.hestyle");
  41. Memory memory = emulator.getMemory();
  42. // 作者支持19和23两个sdk
  43. memory.setLibraryResolver(new AndroidResolver(23));
  44. // 创建DalvikVM,利用apk本身,可以为null
  45. vm = ((AndroidARMEmulator) emulator).createDalvikVM(null);
  46. // (关键处1)加载so,填写so的文件路径
  47. DalvikModule dm = vm.loadLibrary(new File(soFilePath), false);
  48. // 调用jni
  49. dm.callJNI_OnLoad(emulator);
  50. module = dm.getModule();
  51. // (关键处2)加载so文件中的哪个类,填写完整的类路径
  52. TTEncryptUtils = vm.resolveClass(classPath);
  53. }
  54.  
  55. /**
  56.   * 调用so文件中的指定函数
  57.   * @param methodSign 传入你要执行的函数信息,需要完整的smali语法格式的函数签名
  58.   * @param args 是即将调用的函数需要的参数
  59.   * @return 函数调用结果
  60.   */
  61. private String myJni(String methodSign, Object ...args) {
  62. // 使用jni调用传入的函数签名对应的方法()
  63. Number ret = TTEncryptUtils.callStaticJniMethod(emulator, methodSign, args);
  64. // ret存放返回调用结果存放的地址,获得函数执行后返回值
  65. StringObject str = vm.getObject(ret.intValue() & 0xffffffffL);
  66. return str.getValue();
  67. }
  68.  
  69. /**
  70.   * 关闭模拟器
  71.   * @throws IOException
  72.   */
  73. private void destroy() throws IOException {
  74. emulator.close();
  75. System.out.println("emulator destroy...");
  76. }
  77.  
  78. public static void main(String[] args) throws IOException {
  79. // 1、需要调用的so文件所在路径
  80. String soFilePath = "src/test/resources/myso/libencryptLib.so";
  81. // 2、需要调用函数所在的Java类完整路径,比如a/b/c/d等等,注意需要用/代替.
  82. String classPath = "com/.../EncryptUtils";
  83. // 3、需要调用函数的函数签名,我这里调用EncryptUtils中的getGameKey方法,由于此方法没有参数列表,所以不需要传入
  84. String methodSign = "getGameKey()Ljava/lang/String;";
  85. EncryptUtilsJni encryptUtilsJni = new EncryptUtilsJni(soFilePath, classPath);
  86. // 输出getGameKey方法调用结果
  87. System.err.println(encryptUtilsJni.myJni(methodSign));
  88. encryptUtilsJni.destroy();
  89. }
  90. }

②、参数说明
EncryptUtilsJni类中最重要的设置为main方法中的soFilePath、classPath、methodSign三个参数,它们的作用在main方法中已经注释过了,这里再次解释一下。

soFilePath,填写你需要调用的so文件路径
classPath,填写你需要调用的函数所在Java类的完整类路径。

methodSign,填写你要调用的函数签名,语法为smali。(在jadx中,直接可以看smali代码)

备注:如果你要调用的函数还需要传入参数,直接传入myJni方法中即可,myJni方法中省略args参数就是供你传入参数。

③、执行结果

五、总结
unidbg确实很强大,直接在pc端模拟调用so文件,省去了反汇编逆向so文件的麻烦。上面的教程只演示了unidbg项目的导入、封装自己的调用so文件的API,其实这只是入门了,unidbg还支持断点调试so文件,也能导入到IDA中进行动态调试,自己去研究下吧,博主我也比较菜。
若是喜欢,可以素质三连一下\color{red}若是喜欢,可以素质三连一下若是喜欢,可以素质三连一下😂😂😂
————————————————
版权声明:本文为CSDN博主「hestyle」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_41855420/article/details/106265603

运行demo测试环境:

  1. 菜单中 Run -> Edit Configgurations
  2.  
  3. Main class 选择要测试的class
  4.  
  5. Vm Options 填入 -Djava.library.path=prebuilt/win64 -Djna.library.path=prebuilt/win64
  6. win64可以根据自己系统版本更改, 支持: linux64, win32, win64, osx64
  7.  
  8. 接着Apply -> Ok
  9.  
  10. 接入Run

装完依赖的目录结构应该如下

  1. .idea/ //idea配置相关
  2. .mvn/ //maven配置
  3. assets/ //项目图片图标资源
  4. prebuilt/ //unicron支持
  5. src/main //emulator源码
  6. src/test/java //一些demo
  7. src/test/resouces //要模拟的文件
  8. target/ //编译目标路径
  9. target/classes/android //依赖的lib和vfs,作者这里提供了SDK 19与23的库

实现了以下lib的函数

  1. libc.so
  2. libcrypto.so
  3. libdl.so
  4. liblog.so
  5. libm.so
  6. libssl.so
  7. libstdcpp.so
  8. libz.so

发表评论

邮箱地址不会被公开。 必填项已用*标注