随着Android系统安全漏洞的大幅减少,Android设备的root门槛变得越来越高,知名的root工具KingRoot甚至停止了维护,利用漏洞来root变成一件很困难的事情。
另一方面,厂商对Secure Boot的实现也在不断增强,大多数手机厂商关闭了bootloader解锁通道,通过刷第三方rom或recovery来root设备的方式逐渐不可行。
root是安全人员必备的研究环境,除了使用Nexus系列设备外,Vitual APP下的hook不失为一种办法。此外,由于上手简单,VA下的hook更多是被黑产或脚本所利用,本文对这种技术的原理进行分析。
一、Vitual APP原理
广义的Vitual App 可以理解为轻量级的“Android虚拟机”,即一个宿主APP上运行多个其他APP的形式,一定程度上也可以理解为我们熟知的“应用多开”。这种“虚拟机”并未打破Android原有的系统机制,因此,宿主APP及其虚拟运行的多个APP共享同一个uid/gid。
我们知道Android上每个APP都运行在自己的沙盒环境中,但APP对于自己的进程、子进程等具有完全的控制权,在自己的沙箱内运行起其他APP,就实现了虚拟化。然而,常规的APP除了运行自己的代码外,还会和操作系统频繁交互,例如各种各样的服务、文件系统等,Vitual App如果成为了APP和操作系统的“中间人”,便实现了APP无感知的虚拟机,这也是Vitual APP的核心技术。
常见的Vitual APP有以下几类:
- 基于VitualAPP引擎的虚拟工具,例如“太极” (这里的VitualAPP特指github上一款工具,而Vitual APP是广义的虚拟化应用)
- 基于MultiDroid引擎的虚拟工具,例如“LBE平行空间”
- 基于DroidPlugin,如“360分身大师”
- 厂商自带的“应用分身工具”、“多开工具”等
Vitual APP目前被广泛应用于插件化开发、无感知热更新、应用多开、手机模拟信息、脚本自动化等技术领域,这里我们对常见技术流派的原理进行简单分析。
1.VitualAPP
VirtualApp是一个开源的Android App虚拟化引擎,允许在其中创建虚拟空间,并在这个虚拟空间中运行其他应用。项目地址:https://github.com/asLody/VirtualApp(PS:VA的作者是一名高中生)
VirtualApp主要有三部分构成:
- Main Process
进程名io.virtualapp,主要负责VirtualApp用户界面及应用管理 - Server Process
进程名io.virtualapp:x,主要负责实现各种系统服务的代理,这部分也是其能够完成虚拟APP的核心 - VApp Process
进程名io.virtualapp:p[x],作为将来运行client应用的进程,当client应用启动后,其进程名会更新为client应用的包名
VirtualApp之所以能够实现虚拟空间,是因为其对许多系统服务进行了代理和替换。Android应用调用系统服务,是通过Binder机制进行IPC。因此,应用所持有的是系统服务的BinderProxy,VirtualApp通过对这些BinderProxer构造代理并替换,便实现了对系统服务的代理和替换。具体的替换方式可参考http://rk700.github.io/2017/03/15/virtualapp-basic/
原理虽然简单,但由于需要处理各种各样的系统服务,VirtualApp的代码实现起来还是比较麻烦的,此外,VA还要处理APP的安装、启动、广播等。由于巨大的工作量,后期的VitualApp也推出了商业版本。一份非官方的VA文档可以作为参考https://github.com/prife/VirtualAppDoc。
2.MultiDroid
MutiDroid并没有开源其代码,据一些非官方的文档(https://blog.csdn.net/xiaoyangsavvy/article/details/73479780)描述,其关键的实现技术有:
- Framework层的虚拟实现
- 文件系统虚拟化
- Android系统组件管理
- 应用进程管理
但这些技术同样也是VitualApp需要处理的,也有人在逆向LBE的dex里发现了和VA相同的类,毕竟都是对系统服务进行代理,系统服务相关的类名相同自然也是应该的,由于对其未开源,这里对MultiDroid引擎的实现不作分析。
3.DroidPlugin
DroidPlugin是360推出的一款虚拟插件https://github.com/DroidPluginTeam/DroidPlugin ,weishu的文章里详细解释了DroidPlugin的原理(https://github.com/tiann/understand-plugin-framework),DroidPlugin更多的被用于热修复中。
DroidPlugin主要通过Binder动态代理的方式对系统进行hook,同时也对Android的四大组件进行了处理,详细实现可以参考作者github中的Doc目录里的分析文章。
4.厂商实现
由于可以定制化修改系统,相比于其他绞尽脑汁的hook方案,厂商可谓开启的上帝模式,因此在系统上运行一个APP的两个实例实现起来轻而易举。所以严格来讲,手机厂商的实现不能叫Vitual APP了。此外,厂商还可以用Android的多用户机制,实现“访客模式”、“隐私模式”等功能。
二、无root下的hook
我们知道常用的hook工具如Xposed、frida等都需要在root环境下运行,这是因为在无root的环境下,hook工具和目标APP是相互独立的进程,hook工具没有注入目标代码的权限。
通过Vitual APP的技术,我们把目标APP加载到自己控制的沙箱空间内,本质上可以注入任意代码,因此就可以实现hook的功能了。上文解释Vitual APP原理时,我们也提到了hook,但和此节的hook还是有区别的,前者是对系统服务等关键函数的hook,后者作为一个工具,需要实现任意函数下的hook。因此,无root环境下的hook除了结合Vitual APP外,还需要实现任意函数hook,这也就是常说的AOP拦截(Aspect Oriented Programming)。
例如,“太极”(https://github.com/taichi-framework/TaiChi) 是一款比较知名的无root环境下的hook工具,
1.Epic原理
Epic 是一个在虚拟机层面、以Java Method为粒度的运行时Hook 框架(支持 Android 4.0 ~ 10.0)。
它可以拦截本进程内部几乎任意的 Java 方法调用,可用于实现 AOP 编程、运行时插桩、性能分析、安全审计等。Epic 被 VirtualXposed 以及 太极 使用,用来实现非 Root 场景下的 Xposed 功能,已经经过了相当广泛的验证。
Epic的实现原理可参考http://weishu.me/2017/11/23/dexposed-on-art/, 其大致原理是:每一个java方法在ART虚拟机中都对应一个ArtMethod对象,这个ArtMethod对象包含Java方法的所有信息,例如名字,参数类型,方法本身代码的入口地址(entrypoint)等。其中的entrypoint是函数执行的入口,通过替换entrypoint可以实现控制流的挟持。
ArtMethod类定义如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44//http://androidxref.com/8.1.0_r33/xref/art/runtime/art_method.h#708
class ArtMethod {
GcRoot<mirror::Class> declaring_class_; //method所属的class
// Short cuts to declaring_class_->dex_cache_ member for fast compiled code access.
GcRoot<mirror::PointerArray> dex_cache_resolved_methods_;
// Short cuts to declaring_class_->dex_cache_ member for fast compiled code access.
GcRoot<mirror::ObjectArray<mirror::Class>> dex_cache_resolved_types_;
// Access flags; low 16 bits are defined by spec.
uint32_t access_flags_;
/* Dex file fields. The defining dex file is available via declaring_class_->dex_cache_ */
// Offset to the CodeItem.
uint32_t dex_code_item_offset_;
// Index into method_ids of the dex file associated with this method.
uint32_t dex_method_index_;
/* End of dex file fields. */
// Entry within a dispatch table for this method. For static/direct methods the index is into
// the declaringClass.directMethods, for virtual methods the vtable and for interface methods the
// ifTable.
uint32_t method_index_;
// Fake padding field gets inserted here.
// Must be the last fields in the method.
// PACKED(4) is necessary for the correctness of
// RoundUp(OFFSETOF_MEMBER(ArtMethod, ptr_sized_fields_), pointer_size).
struct PACKED(4) PtrSizedFields {
// Method dispatch from the interpreter invokes this pointer which may cause a bridge into
// 以interpreter模式调用入口
void* entry_point_from_interpreter_;
void* entry_point_from_jni_; //jni函数入口
// 以quick code调用时的函数入口
void* entry_point_from_quick_compiled_code_;
} ptr_sized_fields_;
}
例如,hook Log.i()函数的实现如下图:
找到Log.i()函数对应的ArtMethod对象,其对应的entry_point指向Log.i()函数的指令,修改对应指令的前8个字节,使程序执行到预先分配好的内存(图中的0x7f132450),这段内存的指令实现一个分发器的功能,例如判断是否需要hook,如不修要跳回原来的地址执行,如需要hook,则跳转到另一个java方法的entrypoint执行。
Epic的原理虽然简单,但实现起来需要维护堆栈平衡,以及需要支持6.0,7.0,8.0,9.0等不同系统上的ART实现,例如第一次运行的时候采用的还是解释执行的方式,需要手动触发编译成机器码等等。
三、Vitual APP应用
Vitual APP作为Andoird APP上的虚拟技术,有比较广泛的应用,例如:
应用多开
如微信多开这样的需求,需要注意的是,由于多开应用和Vitual APP处于同一个进程空间,多开的应用数据会被互相读取,彼此之间没有沙箱隔离机制。
另外,多开技术也广泛被黑产、羊毛党等利用,是他们用更低的成本来获取更多的利润。
监测工具
Vitual APP这种“自我hook”的技术也可以用于APP自身的监控,例如hook一些敏感API的调用,监测和记录第三方SDK有没有其他恶意行为。也可以用于一些自动化的测试、埋点分析等。hook
由于可以实现无root环境下的hook,Vitual APP技术可以用来模拟数据(如修改定位数据、修改设备参数)、制作插件(如抢红包插件)等免杀
由于Vitual APP的特性,恶意应用通过将恶意代码加密存储在虚拟环境中,实现动态调用。传统的静态检测皆是对应用的包名、证书、代码等进行识别,识别的则是Vitual APP的信息,没有恶意特征,因此躲避了查杀。
参考资料:
- VitualAPP https://github.com/asLody/VirtualApp
- 太极 https://www.taichi-app.com/#/about
- epic https://github.com/tiann/epic
- epic原理 http://weishu.me/2017/11/23/dexposed-on-art/
- VirtualApp沙盒基本原理 http://rk700.github.io/2017/03/15/virtualapp-basic/
- 应用多开对抗 https://bbs.pediy.com/thread-255212.htm
- VitualAPP非官方文档 https://github.com/prife/VirtualAppDoc