当前位置:K88软件开发文章中心编程资讯编程资讯21 → 文章内容

Art模式下,Android源代码如何“金蝉脱壳”?

减小字体 增大字体 作者:华军  来源:华军资讯  发布时间:2019-2-18 23:12:44

APK加固是作为保护APK不被反编译、逆向、篡改的常用手段,既保护了敏感数据也隐藏了敏感方法(函数)。通常,APK加固是第三方厂商以开发者服务的手段提供给开发者。开发者把开发好的APK上传到加固厂商,APK被加固后,开发者下载下来,再次签名,就可以发布到各大市场。由于加固服务的开放性,一些恶意APK也会被提交并加固,给安全检测和分析增加困难,因此从被加固保护的APK中解密出原始代码(俗称脱壳),是安全检测的一道重要流程。现在的加壳方法有两种,一种是把dex加密,在APK启动时再动态解密并加载;另外一种是类似vmp的方法,将原有的Android虚拟机字节码做变换,自己充当虚拟机角色,解释执行变换后的字节码。本文以第一种加壳方式为内容,通过修改Android源代码来实现脱壳,一方面可以熟悉Android源代码,另一方面也可以了解Android APK的加载流程。接下来,ISEC实验室的刘老师为大家详解Android源代码脱壳方法!Android系统虚拟机有dalvik和art两种模式,由于新版Android系统只支持art模式,所以我们以Andorid5.0源码为基础,通过修改art虚拟机代码来脱壳。在修改源码之前,我们需要先简单了解下art模式下APK安装、dex加载流程和加固的基本工作原理。1、安装流程A、APK的安装通常由以下方式触发:adb install命令、pm install命令、java代码通过startActivity调用安装接口或者在system/app目录下自动安装。B、以上安装方法最终都会调用到包管理器Package Manager。C、Package Manager对安装包进行一系列(如签名、组件信息)处理后,通过local socket通知守护进程installed。D、守护进程installd启动dex2oat。E、Dex2oat对安装包中的classes.dex进行优化,生成优化后的文件。2、动态加载过程A、在java代码中利用DexClassLoader或者PathClassLoader来动态加载dex、zip或者jar文件,调用到native层的DexFile_openDexFileNative。图1图2图3B、DexFile_openDexFileNative会使用ClassLinker在处理classes.dex文件。C、ClassLinker和installd流程差不多,会启动dex2oat来生成oat文件。图4从1、2可以看出,无论是APK安装,还是动态加载,最终都会调用dex2oat去生成dex文件对应的oat文件。接下来再来看看dex2oat在干什么?A、Dex2oat会打开installed或者GenerateOatFile传过来的文件,这个文件可以是zip文件、jar文件(jar也是zip格式)或者dex文件。图5这里来个小插曲:还记得cve2017-13156吗?这个漏洞可以绕过v1版本的APK签名,插入恶意代码。有以下两个原因:IsZipMagic和IsDexMagic是通过文件头部来判断文件类型的,如果我们在一个zip文件或者jar文件头部放置一个dex文件,那么这个zip或jar文件会被当作dex文件处理;另外v1版签名只会校验zip的数据,新加的dex不属于zip文件数据,所以不会影响签名。Google的修补方案是强制校验zip或jar包的头部,如果不是zip头部(0x06054b50),就返回错误。具体代码可参考/system/core/libziparchive/zip_archive.cc。图6B、如果是zip或jar文件,在内存中解压缩出classes.dex(如果是多dex,逐一解压缩)。C、将dex映射到内存,解析出dex结构,生成DexFile对象。图7D、Dex2oat利用生成的DexFile对象创建oat文件,oat的创建过程我们不需要关心,只需要关注dex文件被映射到内存后是如何被还原解密的。图8从dex到oat的过程了解后,我们再看看壳是如何工作的。1、加壳流程A、加壳时会把原dex加密放到特定目录(不同壳放置的目录不一样)。B、修改AndroidManifest中的Application为壳的Application,把原来的Application的类名称放到其它地方。C、用自己的dex替换掉原来的classes.dex。D、在APK中加入自己的native模块,在自己的Application引用自己的native文件。2、被加壳应用启动流程A、被加壳应用安装过程中,被dex2oat处理的是壳的classes.dex。B、APK被启动后,实际上是运行的壳代码,调用壳的Application。C、通常会在Application中加载native模块,并在native 层hook文件相关操作(read、write等)。D、动态加载加密的dex,通过LD_PRELOAD的环境变量,把自己的模块注入到dex2oat进程中,同样会hook dex2oat进程的文件相关操作,在读取过程或者文件映射过程,动态解密原始dex。此时,在生成DexFile对象时就是解密后的文件,当dex2oat处理完成,要把处理结果写入到磁盘时,再通过hook把数据加密。E、在主进程加载oat文件时,在加载过程中,hook会把加密后的oat文件还原。F、有些壳会阻止dex2oat对dex进行处理,让代码以dalvik字节码方式解释执行,但还是需要还原出原始dex文件。在明白了APK的安装和动态加载过程后,我们会发现,壳的流程其实是一个动态加载的过程,无论是安装还是动态加载,在进行dex2oat的过程中,dex文件最终都会以DexFile对象的方式出现在内存里面,并且是被还原后的。因此,我们可以通过DexFile对象还原出原始的dex文件。接下来通过修改源代码,在DexFile对象生成的时候把dex文件给提取出来,具体实现过程如下:A、在aosp中,定位到/art/runtime/dex_file.cc中的DexFile类。B、通过修改DexFile类,在DexFile对象初始化时加载我们的代码,DexFile的参数包含了dex文件在内存中的位置、大小以及dex文件结构的相关信息,我们可以通过这些信息还原出原始dex。有两种情况:1、整体加密,这时完全可以dump出原始dex文件;2、对方法字节码进行加密,只有这些类被首次引用时才动态解密,这时我们可以根据DexFile参数中的dex文件信息,对dex中的类手动引用一次,然后再dump,就可以还原出原始数据。图9C、因为read、write等函数被hook,dump文件时不能直接调用libc里面的此类函数,因此需要我们自己实现文件操作函数(用syscall函数或者汇编实现)。图10D、脱壳模块根据壳的种类进行分类处理。图11下面是对脱壳结果的简单演示,第一个是只有一个dex文件,第二个是多dex文件。图12图13图14图15动态脱壳过程很简单,实现方式也有多种,文中所述方法只是起到抛砖引玉的作用,在了解了APK运行加载流程、运行机制、hook、Android源代码编译过程等基础后,相信你也可以get到更加强大的脱壳方式!安胜作为国内领先的网络安全类产品及服务提供商,秉承“创新为安,服务致胜”的经营理念,专注于网络安全类产品的生产与服务;以“研发+服务+销售”的经营模式,“装备+平台+服务”的产品体系,在技术研究、研发创新、产品化等方面已形成一套完

[1] [2]  下一页


Art模式下,Android源代码如何“金蝉脱壳”?