使用FRIDA为Android应用进行脱壳的操作指南

857 阅读5分钟
原文链接: www.ctolib.com

FortiGuard实验室最近遇到了很多加壳Android恶意软件。这类恶意软件一个很有趣的点是,尽管使用的加壳工具是一样的,但生成的恶意软件却常常会发生变化。

分析加壳工具通常令人望而生畏。因为不光分析流程很难理解,并且分析过程中往往也伴随着大量的垃圾信息。

正因为如此,我们想分享我们在处理分析这类恶意软件时出现的一些问题。并且这篇文章也将演示如何使用开源免费工具解压当今最常见的dropper部署的恶意软件。

参考样本是:509aa4a846c6cb52e9756a282de67da3e8ec82769bceafa1265428b1289459b3

静态分析

样本概述

首先,看看我们正在处理的APK。

使用FRIDA为Android应用进行脱壳的操作指南

图1:APK中包含的文件

这个样本显然就比较可疑,比如MawmjulbcbEndsqku ^ nd.cml文件是个什么鬼?

我们先从bash命令开刀,看看能不能处理这个文件,然而并没有检测到任何文件类型。接着我们再试图通过hex editor去打开文件(但我们实际上使用了radare2,它是一个很好用的开源逆向工程框架),不过最后还是无法确定此文件的类型。

使用FRIDA为Android应用进行脱壳的操作指南

图2:hex视图下的MawmjulbcbEndsqku ^ nd.cml

列的内容和名称看起来像是随机字符,这可能是主应用程序使用的加密文件。

也许通过Android Manifest,我们才能获得我们想得到的信息。

Android Manifest

AndroidManifest.xml是一个Android二进制XML文件,其中包含有关该应用程序的大量信息,包括:

·应用程序的软件包名称,可以在设备上访问

· 应用程序使用的活动、服务和接收器的完整列表(如果未在此处声明,以后将无法使用它们)

· 完整的权限列表

· 执行期间使用的意图过滤器的完整列表

· 其他通常不那么重要的东西,比如使用的图标等。

我们首先注意到的就是完全随机的字符串组成了该应用程序所有组件的名称。这是一种恶意意图的标识,但合法的应用开发人员也会使用它来使竞争对手更难以对其产品进行逆向工程。

接着引起我们注意的一件事是:除了应用类com.asgradc.troernrn之外,yeSACsSs文件中没有声明Android组件(活动、接收方和服务类)。这样很奇怪:声明不存在的类并跳过现有的类有什么用呢?

现在很明显的一个事实是,这个APK加载了额外的外部代码。此外,考虑到请求的权限的数量和性质(比如请求发送SMS消息),我们可以相当肯定这段代码没有任何用处。

使用FRIDA为Android应用进行脱壳的操作指南

图3:AndroidManifest SMS过滤器

逆向脱壳工具

有许多免费工具可将APK反编译成可读代码,包括:

· Apktool:获取类的SMALI表示

· dex2jar:将.dex文件转换为jar存档,可以使用jd-gui进行分析

· jadx:将java中的所有代码反编译成方便的GUI

我个人最喜欢用的是jadx,但多些选择也不错,因为在极少数情况下,只有部分工具能够反编译代码。

所以我们接下来开始分析jadx上的APK。然而,事情并不如我想象中那么顺利……

使用FRIDA为Android应用进行脱壳的操作指南

图4:脱壳工具的应用程序类

在真正的脱壳过程中,我们遇到了许多无用的垃圾信息:无意义的字符串、无意义的计算、无意义的函数。我们花了一段时间来尝试理解执行流程:如果加密文件要解密,那么它要么需要调用某个加密库,要么拥有自己的解密例程。一旦解密完成,就需要使用某种类加载器对象加载新文件。

不幸的是,APK导入文件中没有包含这些库。APK中包含的内容是允许文件间接调用任何已加载库的Reflection方法。然而,再一次,这些反射方法参数也是使用无数无法理解的函数动态创建的。

很明显静态分析不能解决这个问题。我们必须转而找寻新方法了。

动态分析

谷歌有提供所有Android版本中sdk下载,可以通过Android Studio创建模拟器。这是一种测试恶意软件的完美方式,不会有被感染的风险。

因此,我们首先使用Marshmallow 6.0模拟器获取此示例并通过adb(Android Debug Bridge)安装了APK。如果APK要加载新的可执行文件,设备的内置记录器(在我们的例子中是模拟器)应该能够获取到。

我们运行了连接到系统记录器的adb命令,并且只选择了包含我们的dropper包名的那些行:

$ adb logcat | grep "com.jgnxmcj.knreroaxvi"

然后我们启动了应用程序。在很多杂乱的输出中,我们终于找到了我们一直在寻找的东西:

10-25 17:12:11.001 24358 24358 W dex2oat : /system/bin/dex2oat --runtime-arg -classpath --runtime-arg  --instruction-set=x86 --instruction-set-features=smp,ssse3,-sse4.1,-sse4.2,-avx,-avx2 --runtime-arg -Xrelocate --boot-image=/system/framework/boot.art --runtime-arg -Xms64m --runtime-arg -Xmx512m --instruction-set-variant=x86 --instruction-set-features=default --dex-file=/data/user/0/com.jgnxmcj.knreroaxvi/app_files/rzwohkt.jar --oat-file=/data/user/0/com.jgnxmcj.knreroaxvi/app_files/rzwohkt.dex

APK确实创建了一个新的.dex文件。很好,我们只需要获取此文件,就不需要逆转dropper了。

但问题又来了,当我们尝试抓取该文件时,我们无法在/data/user/0/com.jgnxmcj.knreroaxvi/app_files中找到它。显然许多恶意软件编码器的创作者通常会在使用后清理了它们。所以我们面临的下一个问题是,如何阻止dropper删除文件?

让我向您介绍这个完美工具:FRIDA。

FRIDA是一个非常棒的检测工具包,它允许在应用程序执行期间连接Javascript代码,还可以修改函数、字段等等。

在这种情况下我们想要做的是阻止应用程序删除rzwohkt.jar文件,以便我们可以将它拉到我们的机器上进行分析。

使用FRIDA的过程一般是这样的:我们的MO将先找到负责删除的类,然后勾住类函数并跳过它。但是,我们不想再次重复静态分析的状况,所以使用动态分析来跳过这部分。

我们只有找出哪个系统调用被用于删除执行,我们才能绕过它。不管在混乱的代码中调用是在哪里进行的,如果我们在系统中钩住了正确的本机函数,那么应该能够检索所需的有效负载。

使用Strace

接下来的一个重要问题是,我们怎么才能找到正确的函数呢?幸运的是,有一种简单的方法可以获得执行期间发生的所有函数调用的完整列表。

Strace是一个很棒的Linux实用工具,它能让用户获得进程和Linux内核之间所有交互的完整报告,并且Android支持它,所以它是我们的理想工具。

使用FRIDA为Android应用进行脱壳的操作指南

图5:Strace的输出结果

FRIDA代码

最后,我们获得了所需的所有信息。现在是时候创建我们的FRIDA钩子了。

首先,根据所使用的架构,我们需要在移动仿真器上运行正确的frida-server。

既然我们有了连接FRIDA代码的方法,现在要做的就是创建脚本,钩住unlink()函数并跳过它。为此,我们使用了Interceptor.replace(目标,替换)方法,它允许我们替换目标处的函数,并用了Module.findExportByName(module,exp)获取指向函数的指针,如果模块名称未知,null可以作为模块传递(但会影响速度)。

console.log("[*] FRIDA started");
 
console.log("[*] skip native unlink function");
 
 
 
// create a pointer to the function in the module
 
var unlinkPtr = Module.findExportByName(null, 'unlink');
 
 
 
Interceptor.replace(unlinkPtr, new NativeCallback(function (){  
 
    console.log("[*] unlink() encountered, skipping it.");
 
}, 'int', []));

现在,每当调用unlink()函数时,FRIDA将拦截调用并运行我们的代码。在这种情况下,它只会输出一个记录器字符串,并通知我们已经跳过了调用。

最后,我们只需要将脚本附加到应用程序进程里。所运行的dropper_startup.py是一个快速启动应用程序的python脚本,我们接着将FRIDA脚本附加到frida-server。

使用FRIDA为Android应用进行脱壳的操作指南

图6:FRIDA输出

但在前几次执行过程中,unlink()也同样会对相应文件进行删除操作。最后,在二次取消链接后,我们能够运行:

$ adb pull /data/user/0/com.jgnxmcj.knreroaxvi/app_files/rzwohkt.jar

并成功获取了文件——一个包含classes.dex有效负载的jar存档。

结论

Android恶意软件的发展日新月异,其架构就像更成熟的Windows恶意软件一样,也在往复杂化的趋势前进。Droppers只是部署有效负载的一种确实有效的方式。随机字符串和无意义函数的确很容易欺骗AV引擎,但是,使用以下签名可以保护Fortinet客户端免受这些因素的影响:

Dropper:Android / Agent.CHG!tr
Payload:Android / Agent.ARL!tr

FortiGuard Labs将对这些恶意软件活动保持持续监控。

此博客中使用的所有脚本都可以在FortiGuard Lion github页面上找到。

IOC:

Packer: 509aa4a846c6cb52e9756a282de67da3e8ec82769bceafa1265428b1289459b3

Payload: 4fa71942784c9f1d0d285dc44371d00da1f70f4da910da0ab2c41862b9e03c89

查看原文: 使用FRIDA为Android应用进行脱壳的操作指南