现在的位置: 首页 > 综合 > 正文

Android安全分析挑战:运行时篡改Dalvik字节码

2013年10月12日 ⁄ 综合 ⁄ 共 3050字 ⁄ 字号 评论关闭

本文章由Jack_Jia编写,转载请注明出处。  

文章链接:http://blog.csdn.net/jiazhijun/article/details/8833710

作者:Jack_Jia    邮箱: 309zhijun@163.com

     移动互联网已经是一种趋势,仅2012年就有45亿应用程序下载量。伴随着移动互联网的火爆,众多攻击者也被吸引到这个平台,移动平台恶意软件呈现爆炸式增长态势。与PC平台不同的是,PC平台有大量的反病毒包和恶意软件分析工具,而新兴的移动互联网却缺乏强大的分析工具和技术。这些工具和技术将是保持移动互联网远离恶意软件和恶意应用程序的关键。它们一般来自于学术界和安全界的研究人员,但是它们都有一定的缺陷,并不适合所有的情况,加入安全社区可以帮助我们学习和发展android应用的分析方法。

一、介绍

      首先介绍一下移动应用程序的分析方法和背景。我们可以采用很多工具来对应用程序进行分析,Android应用程序的分析一般都是基于APK文件,APK文件代表了一个应用程序。
     它存储了以下内容:


           1、程序逻辑:dex字节码和so本地库。
           2、元数据信息:AndroidManifest.xml文件。
           3、资源文件:图像或其他类型数据。


     分析工具一般采用以下两种应用分析方法:


          1、静态分析:该方式收集有关应用程序的信息,但程序代码不执行。
          2、动态分析:该方式执行应用程序,同时收集应用运行行为。


     这两种分析技术都各有利弊,在Android逆向分析领域,许多工具都是基于静态分析技术,也有用于动态分析的沙箱系统,但受限于动态分析系统的交互灵活性,分析师往往在那些部分需要动态分析上没有足够的控制力。在逆向工程过程中,分析人员一旦确定了感兴趣的应用程序部分,它们更侧重于使用静态分析工具。问题是如何找到那些部分呢?静态分析技术的另一个主要缺点是不知道什么被真正执行和程序上下文在某特定点的执行是否有效。当我们假定应用程序代码在运行过程中不会改变时,分析工作将是十分容易的,我们可以通过分析apk文件来识别程序代码逻辑,混淆的应用程序会给分析人员带来一定的挑战。随着运行时篡改Dalvik字节码的讲解,我们将暴露这些基于代码流分析的工具的限制和问题。


     我们将在接下来的部分描述一下应用程序的基本组成部分,并指出重要的运行时组件。这将使我们更容易明白当运行crackme时发生了什么事情。之后,我们将讲述用于欺骗静态分析工具所采用的主要技术。最后我们会进入crackme挑战的细节。

二、应用程序执行的上下文

      应用程序的生命周期开始于zygote进程的fork方法,因为它已经预先加载了Android框架,所以应用程序不必再花时间加载这些基础类,同时这也可以有效降低整体的内存开销。在新的进程降低权限之后,它加载了apk文件中的classes.dex文件,该文件包含了可被Dalvik虚拟机(DVM)解释执行的Dalvik字节码,代表了应用程序逻辑。此外,应用程序还带有可以在运行时动态加载的Native库。因为Dalvik虚拟机和Native库运行在同一进程中,因此它们具有相同的权限。一个典型的(缩短的)应用程序的内存布局如图1所示。

图1典型的APP内存布局



       我们可以看到,Android框架和共享库及dex文件一样被映射到我们的进程。我们的dex文件字节码被映射为只读。

三、篡改技术

       回到静态分析工具的话题,如果Dalvik字节码在运行时不能改变的话,静态分析工具将能很好的工作。因为我们可以直接从APK文件中提取的出和运行时相匹配的字节码。你可能会说这种假设是成立的,因为dex文件映射为只读,所以Dalvik指令集是不能够修改的字节码本身的。有限的Dalvik指令集使我们不能够篡改程序字节码,但我们可以利用捆绑在APK文件中的本地库。本地代码和DVM运行在相同的较低水平,如图2:

图2 本地代码和DVM在同一级别的操作

      本地代码是能够任意操作自己进程上下文内存的,因此我们可以通过本地代码覆盖已加载Dalvik字节码。但是classes.dex被映射为只读。这意味着,如果我们修改该段内存,内核将会杀掉我们的进程,因此在实际篡改我们的应用程序的字节码之前,我们必须重新映射该段内存为可写。之后,我们就可以写我们的新字节码到我们的应用程序。如果程序调用我们篡改过的方法,那么将执行新的字节码。没有进一步修改应用程序或DVM的必要。通过这种方法,我们发现“字节码在运行时不能修改”的假设也不是绝对的。只关注classes.dex文件的静态分析工具没有考虑到这种情况,这样的工具就必须改进以应对这种情况。可以使用静态和动态分析的组合来克服这种限制,但这样的复杂的分析系统是不常见的。

三、示例-Crackme

     为了说明我们前面所讨论的一些问题,我们决定创建一个案例研究“challenge”的应用程序“crackme”,它使用恶意软件使用的混淆技术进行了处理。您可以使用任何分析技术和工具,并弄清楚它是如何工作的。找到正确的密码,输入到上面的文本框中。点击按钮,查看是否得到了正确的答案。这将显示按钮下面的文字。

     您可以在这里下载crackme的apk文件的副本:https://github.com/blueboxsecurity/DalvikBytecodeTampering/raw/master/delta.apk

     停止阅读,如果你打算接受挑战。下面是挑战的答案 -----

     首先我们开始分析Action类,这是我们的应用程序的Activity的入口,按钮会触发verify()方法。在这里,我们第一次获取TextField中的输入的文本,并把它转换成一个String。这个String对象并不是java.lang.String类的一个实例而是我们自己的实现。在构造函数中,我们使用第二种方法改变字符串。结果将被储存在私有的区域,和Action类的硬编码在一块。如果密码相同,将被用于显示在屏幕上的消息的加密。

     但是String类内所使用的改变文本方法的方法,或者更准确地说,这种方法的字节码,将永远不会被执行。当应用程序启动后,在Action的静态类的构造函数中,这个方法的字节码已经被替换掉了。在这里,我们加载本地库'libnet.so'和执行READMEM()函数。在这个库中,我们获取一个指针从堆栈到我们的映射的dex文件,并尝试找到文件的开头。这可以很容易地通过正向搜索内存页,直到我们发现dex文件的magic byte。现在我们可以从dex文件的开头解析头文件。当我们解析dex文件时,我们可以找到的我们要篡改方法的地址。但正如前面提到的,我们首先要重新映射内存为可写。这可以使用mprotect()函数实现。之后,我们就可以覆盖原来的字节码,并通过从本机代码到类的初始化的返回来完成。类初始化已经结束,Activity在Android设备上弹出。现在,当我们按下按钮时,我们执行的是新的字节码,而不是原来dex的字节码。

英文源址:http://blog.bluebox.com/2013/03/25/android-security-analysis-challenge-tampering-dalvik-bytecode-during-runtime/

抱歉!评论已关闭.