购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

1.3 第一个unidbg项目

接下来,我们一起运行第一个unidbg项目。

1.3.1 unidbg介绍

unidbg是一个基于Unicorn的逆向工具,可以黑盒调用Android和iOS中的so文件。这使逆向人员无须了解so内部算法原理,只需主动调用so中的函数,传入所需的参数,补全运行所需的环境,即可得到需要的结果。

对于Android逆向来说,unidbg有以下几个特点:

❏模拟JNI调用的API,因而可以调用JNI_OnLoad函数。

❏支持JavaVM和JNIEnv。

❏支持模拟系统调用指令。

❏支持ARM32和ARM64。

❏支持基于Dobby的Inline Hook。

❏支持基于xHook的GOT Hook。

❏Unicorn后端支持简单的控制台调试器、GDB Stub、指令追踪和内存读写追踪。

❏支持Dynarmic。

笔者将会在接下来的内容中逐步讲解unidbg的特点。

1.3.2 unidbg下载与运行示例

unidbg的下载地址为https://github.com/zhkl0228/Unidbg,直接使用以下命令即可将它下载到本地。

git clone https://github.com/zhkl0228/Unidbg.git

Cloning into'Unidbg'...

remote:Enumerating objects:33604,done.

remote:Counting objects:100%(533/533),done.

remote:Compressing objects:100%(317/317),done.

remote:Total 33604(delta 158),reused 394(delta 107),pack-reused 33071

Receiving objects:100%(33604/33604),552.55 MiB|5.82 MiB/s,done.

Resolving deltas:100%(16642/16642),done.

Updating files:100%(1334/1334),done.

unidbg是一个标准的Java项目,下载完成后,使用IDEA打开unidbg项目文件夹,并在弹出的窗口中选择相应的项目,如图1—6所示。

图1—6 使用IDEA打开unidbg项目

当第一次打开项目时,IDEA会下载一些依赖,慢慢等待下载完成即可。可以通过jnettop命令查看IDEA后台下载情况,执行命令后的结果如图1—7所示。

图1—7 通过jnettop命令查看IDEA后台下载情况

下载完成后,打开项目根目录下的unidbg-android/src/test/java/com/kanxue/test2/MainAc-tivity.java文件,单击main方法左侧的绿三角(快捷键<Ctrl+Shift+F10>)来运行该代码。如果运行成功,则证明unidbg环境搭建完成,如图1—8所示。

图1—8 unidbg环境搭建完成

1.3.3 unidbg示例讲解

在上一小节我们成功运行了unidbg的示例代码,接下来我们根据代码的执行流程对示例代码进行讲解。

public static void main(String[]args){

//获取系统当前时间

long start=System.currentTimeMillis();

//实例化一个MainActivity(即当前类)对象

MainActivity mainActivity=new MainActivity();

//打印当前时间与开始时间差值,即实例化MainActivity对象的时间

System.out.println("load offset="+(System.currentTimeMillis()-start)+"ms");

//执行MainAcitivty的crack()实例方法

mainActivity.crack();

}

首先看main()方法。其主要工作为实例化MainActivity对象,调用它的crack()方法,并记录和打印实例化对象的时间。由上一小节运行的结果来看,实例化对象的过程是比较耗时的,但对于逆向安全人员来讲,达成最终目的更重要,这点性能损耗可以忽略。

其次看MainActivity的构造方法MainActivity()。该构造方法通过AndroidEmulatorBuilder构建了一个AndroidEmulator实例。其中调用的for32Bit()方法指定模拟器为32位。addBa-ckendFactory()方法则为模拟器添加一个后端工厂,此处添加的后端工厂为DynarmicFactory。虽然牺牲了一定的特性,但它的执行速度比较快,后续可以根据情况切换成相应的后端工厂。这里传入的参数true的含义为“当出现问题时,回退到Unicorn后端工厂”。最后调用build()方法来创建对象。

除了DynarmicFactory,unidbg还支持hypervisor、KVM、Unicorn2以及默认的Unicorn。后端工厂通常位于项目根目录下的backend文件夹中,如图1—9所示。默认的Unicorn则位于项目根目录下的unidbg-api/pom.xml文件中以Maven的方式被引用。

然后emulator通过调用getMemory()方法获得了Memory对象。Memory接口可以让我们进行一些内存相关的操作。

之后,实例化一个Android库解析器,将SDK版本设置为23。unidbg提供了两个SDK版本,分别是19和23,位于项目根目录下的unidbg-android/src/main/resources/android目录下。SDK的目录下有一些运行时依赖库,用于模拟相关的环境,如图1—10所示。

图1—9 unidbg支持的后端工厂

图1—10 unidbg支持的SDK

同时给Memory接口的对象设置这个Android库解析器。

通过emulator模拟器对象的createDalvikVM()方法创建了一个vm虚拟机,并通过setVerbose()方法禁止输出详细日志。vm对象的其他个性化配置将会在后文中一一讲解。

之后使用vm.loadLibrary()方法将so文件加载到内存中。该方法需传入两个参数:第一个参数是一个File对象,传入的地址是基于项目根目录的路径;第二个参数控制是否自动执行so文件中的init函数,此处设置为false,表示不自动执行(如果设置为true,则unidbg会在加载时自动调用相应的init函数)。

so文件加载成功后会返回一个DalvikModule对象,可以使用该对象来执行callJNI_OnLoad()方法,从而使unidbg执行JNI_OnLoad函数。其中传入的参数为模拟器对象。

这样,通过MainActivity的构造方法,我们完成了模拟器及so文件运行所需的一些环境的初始化。

接下来便是调用MainActivity对象的crack()方法了。

在crack()方法的第一行,ProxyDvmObject.createObject(vm,this)通过代理Dvm对象创建了一个DvmObject对象,其中:第一个参数为vm虚拟机;第二个参数为传入的this指针,在运行过程中,传入的是com.kanxue.test2.MainActivity实例对象。这一行得到的obj是一个DvmObject对象,该对象可以通过callJniMethodBoolean()等方法来调用so文件中JNI的方法,调用方法的返回值为Boolean类型。这是unidbg中调用JNI方法的操作。

再下面是一个三层循环,使用LETTERS字符表遍历组成三个字符的字符串。通过obj对象调用callJniMethodBoolean()方法来执行so文件中的jnitest(Ljava/lang/String;)Z函数,通过返回值来判断是否成功。如果返回值为真,则打印传入的参数与所耗时间并退出函数。

callJniMethodBoolean()方法有三个参数:第一个参数为模拟器实例对象;第二个参数为so文件中的JNI方法签名;第三个参数为函数的参数列表,此处为JNI方法所需的参数字符串。

接下来我们将相应路径中的so提取出来,使用IDA打开,在函数列表中使用组合键<Ctrl+F>搜索jnitest命令来找到相应的函数,使用快捷键F5查看相应的伪代码,如图1—11所示。

不难看出,这个JNI方法添加了OLLVM混淆,会增加逆向人员的分析难度。unidbg允许我们在不需要知道函数内部逻辑及算法细节的情况下,对函数进行主动调用,只需传入相应的参数即可获得运行结果,使函数可以“为我所用”,从而极大地提高逆向人员的效率。这也是unidbg最重要的应用。

图1—11 IDA关于jnitest函数的伪代码

与此同时,我们可以看到,实际上调用的JNI方法声明为int__fastcall Java_com_kanxue_test2_MainActivity_jnitest(JNIEnv * env,jobject thiz,jstring str);。在上述实际调用过程中,我们的方法名只写了jnitest,且只传入了最后一个参数。对于缺失的前两个参数,unidbg会自动帮助我们完成补全操作。

对于JNI方法的函数名,unidbg也会根据ProxyDvmObject.createObject(vm,this)这个代理对象传入参数中的this参数,来解析对应的类的全类名,并对JNI方法名进行补全操作。这也是为什么MainActivity的包名为com.kanxue.test2,它是与so中JNI方法的方法名相对应的。只有相应的包名与类名配置正确,unidbg才能正确地执行JNI方法。

unidbg是一个非常强大的框架。Unicorn只是模拟了一个CPU来执行一些汇编指令。而unidbg在Unicorn的基础上添加了一些so运行所依赖的环境,会自动帮助我们完成so所需的加载、Linker链接等一系列复杂操作,使我们可以非常方便地调用so中的JNI方法,获得我们想要的结果。 YVtDcNX35INZih2FD8gYdV+b40f4M5s7E/SHUcK6faIdiDobn4Uu0ljpoDoXi3cC

点击中间区域
呼出菜单
上一章
目录
下一章
×