安卓平台是个多进程同时运行的系统,它还缺少合适的动态分析接口。因此,在安卓平台上进行全面的动态分析具有高难度和挑战性。已有的研究大多是针对一些安全问题的分析方法或者框架,无法为实现更加灵活、通用的动态分析工具的开发提供支持。此外,很多研究只是针对单进程的分析,在安卓平台多个应用进程协作完成事务的情境下,则无法进行很好的分析。
目录
2 相关工作
2.1 技术背景
2.1.1 JVM 上的 ShadowVM 框架
2.1.2 DVM 与安卓应用程序
2.1.3 安卓应用的组成
2.1.4 安卓进程间通信 Binder 机制
2.1.5 安卓匿名共享内存 Ashmem
2.2 相关研究工作
2.3 本章小结
2 相关工作
本章旨在介绍本文工作需要的背景技术知识、以及与本文相关的研究。首先介绍了提出框架所依赖的主要技术点,通过介绍已有的 DiSL 和 ShadowVM 技术来初步介绍基于字节码注入技术进行动态分析的技术要点,并介绍了安卓平台与JVM 平台不同的特性以及相关必要的知识;然后,结合相关的研究工作展示了本文研究内容具有的创新性和挑战性。
2.1 技术背景
本节主要讲述与本文框架实现息息相关的技术要点。首先本文是基于已有的DiSL 注入框架和 ShadowVM 分析模型进行的创新性拓展,因此首先会介绍一下这两份工作的内容;其次本文针对的是安卓平台,与已有工作针对 JVM 平台的研究有很大区别,因此紧接着会介绍实现本文框架需要的一些其它必要知识。
2.1.1 JVM 上的 ShadowVM 框架
DiSL是瑞士卢加诺大学开发的一个 JVM 上的字节码动态注入框架,它同时也是一种基于面向方面程序设计的编程模型。程序分析框架的宗旨就是为程序分析开发构建一个平台,利用更加抽象的顶层语言来描述程序分析逻辑,从而简化程序分析工具的开发。DiSL 基于切面/通知模型,使得用户能够方便的定义一个程序分析逻辑,并按照分析需要应用到目标程序不同地方。简单概括来说,DiSL利用了 Java 的语言特性,使用 Java 作为编程语言,为字节码注入构建了一套完整的系统。用户只需要编写基于 DiSL 的注入类,即可实现分析需要的逻辑功能。在注入功能方面,基于 ASM 来作为底层操作 Java 字节码的工具库,通过扩展 Java语言的注解(Annotation)来完成 Java 语义到注入语言的连接;在动态加载方面,基于 java agent 来提供类重写事件从而实现了注入范围的全覆盖。总之,DiSL 提供了一个 JVM 平台上高可用、高性能、拥有丰富语义、用户友好的编程模型。
ShadowVM是基于 DiSL 注入框架的新的研究成果。从名字上也能看出,ShadowVM 提供了一个影子虚拟机。基于字节码注入的程序分析,存在低覆盖率以及较差的隔离性等问题。低覆盖率就是指一些类不能被注入从而导致分析的功能会受到限制,而较差的隔离性是指注入的字节码对原来程序的执行会造成干扰,轻则造成程序性能问题,严重则会影响程序的控制流,造成死锁等严重后果。而ShadowVM 的提出就是旨在为基于 JVM 字节码注入的程序分析提供更好的覆盖率(coverage)以及隔离性(isolation),它通过在目标进程以外的新进程中维护一个“影子”虚拟机,来维护虚拟机状态,并将程序分析逻辑设计成异步的方法。具体来讲,ShadowVM 的核心功能,一方面是注入,这点继承了 DiSL 动态注入的特点并采用 DiSL 程序语言来描述注入;另一方面就是异步分析,这就包括将待分析 JVM 进程中的分析需要的数据发送到远程的影子虚拟机、在影子虚拟机维护需要的影子对象并在影子虚拟机上执行实际的分析代码。ShadowVM 通过注入native 方法,来降低对原 Java 程序的影响,并通过开辟一个专有的线程来发送缓冲的分析数据。此外 ShadowVM 是考虑到并发多线程性能优化的,能够在保证分析事件的有序基础上尽可能发挥多线程的优势。ShadowVM的架构如图2-1所示,进程 1 表示待分析的 JVM 进程,它通过 java agent 与注入服务器进程 2 通信;进程 3 就是“影子”虚拟机,进程 1 会通过注入的 native 方法,利用 C 实现的 socket通信方式把异步分析调用以及 JVMTI 事件发送给影子虚拟机。ShadowVM 的这种异步分析模式能够很有效的被应用在许多分析场合,并很好地解决传统的基于注入的动态分析的覆盖率以及隔离性的问题。
DiSL 以及 ShadowVM 的这种运作模式,极大丰富了动态程序分析的功能,同时,也方便了动态分析工具的开发。如何将这种注入、分析与目标程序分开部署的技术应用到安卓平台上,并能适合安卓的编程模型和特有语义,是本文的一大重要探索和创新点。
2.1.2 DVM 与安卓应用程序
Fork 系统调用后的父进程与子进程拥有这片共享的内存区域,由于这片区域是只读的,因此在内存里只会保存一份拷贝,从而达到了节约内存的目的。本文后面介绍分析框架的部分,还会详细介绍这个过程。
当然,与 JVM 相同,安卓应用程序不仅仅只是用 Java 程序实现,它同时也支持 JNI(Java Native Interface)的调用。JNI 方法允许 Java 代码与其它语言写的代码进行交互,比如 C、C++程序,这些库的存在往往都是为了提高性能或者实现平台相关的特性而被引入。在 Java 代码中,这些 JNI 方法被申明为 native 方法。native 方法的存在一方面丰富了应用程序的功能,但也一定方面增加了 Java程序分析的难度。有不少研究是能够对系统进行监控的程序分析 。
2.1.3 安卓应用的组成
安卓的多组件的组成方法,给传统的静态分析带来的不小的麻烦 [19] 。因为静态分析往往需要掌握一个程序的入口,而安卓程序的每个组件都有可能是程序的入口点;此外,组件之间的通信也很难仅仅通过静态分析连接起来。还有安卓里回调函数的广泛存在。动态分析则能很好的解决这些难点。
2.1.4 安卓进程间通信 Binder 机制
众所周知,安卓系统是基于 Linux 内核的。Linux 中支持多样的进程间通信(Inter Process Communication,简称 IPC),比如管道(Pipe)、信号(Signal)以及追踪(Trace)用于父子进程间通信;以及命名管道(Named Pipe)、消息队列(Message Queue)、共享内存(Shared Memory)以及信号量(Semaphore)、套接字(Socket)等多种其它的更加丰富的 IPC 方式。然而安卓系统上设计和实现了一种不同的 IPC 进程间通信的方式——Binder。Binder 在安卓里能够提供类似远程过程调用(Remote Procedure Call,简称 RPC)的功能。前面提过安卓是一个多进程多应用组件构成的系统,组件与组件之间、进程与进程之间、应用程序与系统服务之间都有着密切的联系。而 Binder 就是被设计来在这样的条件下为安卓提供进程间的通信。
2.1.5 安卓匿名共享内存 Ashmem
Ashmem(Anonymous Shared Memory)是安卓平台针对设备内存有限提供的一种内存共享机制,是安卓 Linux 内核特有的功能之一。它有 C++以及 Java 两种语言的接口,这些接口与一般的文件操作类似。不同的进程通过共享一个文件描述符,实现对同一块内存的共同访问和读写。前面也介绍过 Binder 可以传输文件描述符,也正是利用这点,Ashmem 可以方便的进行内存共享。
不同进程之间通过 Binder 可以交换文件描述符,从而实现不同进程共享相同的内存空间。
int create_ashmem(int numOfPages){
int fd = ashmem_create_region(NULL, numOfPages*PAGE_SIZE);
char *addr = (char*)mmap(NULL, PAGE_SIZE * numOfPages,PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
ASSERT(addr != MAP_FAILED);
return fd;
}
void free_ashmem(int fd, char* addr, int numOfPages){
munmap(addr, numOfPages * PAGE_SIZE);
close(fd);
return;
}
2.2 相关研究工作
DroidScope是一个模拟器层次的分析框架,它通过修改 QEMU 模拟器,来恢复安卓操作系统以及 Java 层的语义。它给用户提供了一些注入接口并允许用户使用这些接口来实现他们的分析,比如可以用来进行追踪 API 的使用情况(记录方法的调用),能追踪本地方法(native method),并通过追踪程序的数据流来进行一些污点分析(taint analysis)功能。DroidScope 与本文的工作有很多相似的地方,都是提供了一种事件驱动的动态分析模型,然而 DroidScope 有如下的缺点:它用于驱动的事件都很底层,用户很难对已有的事件进行扩展,同时由于它是基于安卓 QEMU 模拟器的,所以它不可能被实际部署到设备上。因此,DroidScope更像是一个比较底层的基于二进制注入的工具。相比之下,本文提供的动态分析框架注入以及分析的逻辑都可以使用 Java 语言编写,这大大方便的注入和分析的开发,同时由于安卓应用本身是 Java 开发的,因此 Java 编写分析逻辑能消除 native代码与 Java 之间的隔阂。相对于 DroidScope,本文提出的模型也更加抽象,能够进行更加多样的注入,也更易于扩展和维护。
而通过对安卓系统 IPC 通信的 Binder 核心库,TaintDroid 也能够支持安卓多部件、多进程的污点传播维护。TaintDroid 采取了一个粗粒度的污点传播策略,对 IPC 消息进行污点记录而不精细到每个对象,来减少对 IPC 监视带来的性能开销。尽管 TaintDroid 的研究具有很大的创新型,被后续的很多研究所扩展或者借鉴,但是也存在一些不足,比如系统较为复杂、难以部署,分析功能比较局限等。
DVM 字节码的改写也是一种常见的技术 [36] ,被不少研究采取用来进行安卓平台上静态或者动态程序分析。比如,Dexpler是一个静态分析工具,它利用Dedexer 以及 Soot 库将 Dalvik 字节码转换成 Jimple 格式的表示,从而进一步利用基于操作 Jimple 语言的工具来修改。FlowDroid也利用该技术来为应用程序进行精确的静态分析,它能够识别不同的安卓组件之间可能的数据泄露。同样,本文也采取了字节码改写的技术,将 DVM 字节码转换成到 JVM 字节码,以充分利用 DiSL 注入框架来实现功能强大的注入。DiSL 充分考虑了用户的易用性以及注入的灵活性以及性能,而本文还实现了 DVM 上的动态加载事件,注入的过程对用户而言是完全透明的,用户可以专注于分析逻辑的开发,而不需要考虑如何进行注入的部署和配置。
2.3 本章小结
本章首先介绍了本文框架中需要用到的关键技术点,包括本文基于的 DiSL和 ShadowVM 的基础工作,以及 Dalvik 虚拟机、安卓平台应用的组成以及 Binder和 Ashmem 等相关的背景技术。接着,通过介绍一些学术界的研究,比如动静态分析相关的以及字节码改写技术相关的工作,表明了本框架的研究意义和创新性,展示了本框架实用的价值。