如今Android应用市场上的双开软件越来越多,譬如平行空间,双开大师,这些双开软件使得用户在同一台手机设备上使用同时登录两个微信账号,同时玩一个游戏的两个账号。这些软件相信大多数人都有所耳闻,甚至每天都在使用,看起来很厉害的样子,它们使用了什么技术呢?应用层虚拟化技术!这种技术也许你没有听过,但是想必大家使用过360安全卫士、花椒相机吧,它们也是基于应用层虚拟化技术的。
当然,随着用户量增多和广泛的应用,这类给予应用层虚拟化技术的双开软件暴露出了很多安全威胁,比如恶意软件使用该技术窃取微信的登录密码,造成了严重的用户损失。因此,各个手机厂商开始在手机系统中嵌入该功能,如今市场上的手机厂商都逐渐增加了应用双开的功能,如小米,华为,OPPO。他们是如何做到的呢?
小米和华为手机具有系统分身的功能,在一个Android手机设备实现多个系统空间,即系统分身,系统之间互相隔离。下面三张图是小米的系统分身和应用双开的截图。图2中的红框分别是应用双开和系统分身入口图标,图3是通过切换分身图标进入新系统中,没有任何原系统中的应用及数据。
系统层虚拟化方案主要有Linux内核层和Android framework层两种方案。小米和OPPO都在Linux内核层做的。其中,小米用的应该是加拿大软件公司Graphite Software的Secure Spaces技术,以下是官网截图。小米,酷派,联想,blackphone等手机都使用了Graphite的产品。接下来来介绍Linux内核层和Android framework层两种方案的具体实现。
《Cells: A Virtual Mobile Smartphone Architecture》
SOSP 2011 (ACM Symposium on Operating Systems Principles)
哥伦比亚大学 Jeremy Andrus, Christoffer Dall, Alexander Van’t Hof
哥伦比亚大学虚拟化研究室的这篇论文DEMO后来被以色列公司cellrox在2014年进行了商业化
关于namespace:
Linux Namespace是一种Linux Kernel提供的资源隔离方案,提供PID,Network,IPC,UTS,Mount,User六种资源的隔离,每个Namespace下的这些资源对于其他Namespace是不可见的。
一个进程可以同时属于多个Namespace。Linux Kernel、Namespace、Process之间的关系可以用下图描述。
在Linux kernel层利用namespace + device proxy来实现虚拟android系统(VP),每个VP都有私有的虚拟namespace。
foreground VP独占屏幕资源,而background VP依然在后方运行,能够接受系统事件,并执行任务。VP在电脑端生成和配置,通过USB线下载到手机上。
三种访问配置:
(1)no access:VP可限制某些权限,即使用户同意使用
(2)shared access:foreground VP和background VP可共享
(3)exclusive access:当foreground VP运行时,它独占所有资源,可防止信息泄露
1.共享可读的系统文件,减少内存使用
2.隔离VP以及root namespace
(1)利用UID namespace虚拟化用户凭证
(2)在内核层用namespace隔离VP及其数据
(3)使用mount namespace隔离VP文件
(4)去除VP内创建设备节点的能力
提供 隔离+硬件资源多样化
kernel device namespace:在驱动层表示数据结构并注册回调函数。当device namespace状态转变的时候回调函数被调用
每个VP都有一个device namespace
(1)虚拟化内核接口
创建device driver wrapper,用于接收foreground VP的请求,并更新设备状态。如屏幕显示的Framebuffe
(2)修改设备子系统使其能感知device namespace,如图7的输入子系统
(3)修改设备驱动使其能感知device namespace,如Binder drive
user device namespace proxy:虚拟化设备配置,比如wifi和电话配置。
root namespace用于管理VP及两种namespace,可访问整个文件系统。
VP的启动:
CellD将挂载VP文件系统,将自己克隆到一个具有单独namespace的新进程中,并启动VP的init进程以启动用户空间环境。
CellD设置了一组IPC套接字,供VP中的进程与root namespace通信。
Cells利用LXC进行资源控制,以防止单个VP的资源不足。
Android的屏幕显示依赖于Linux framebuffer (FB)来实现
进程和GPU硬件可以读写屏幕内存
创建新的FB device driver mux_fb
进程通过ioctl控制FB硬件状态
foreground VP可访问屏幕内存和显示硬件,而background VP维持着虚拟硬件状态,并将输出保存到内存中的backing buffer中。
当foreground VP mmap一个打开的FB device,mux_fb驱动时,mux_fb驱动会将相关的屏幕内存映射到进程内存中
当background VP mmap一个打开的FB device,mux_fb驱动时,mux_fb驱动会将backing buffer映射到进程内存中
foreground VP与background VP的切换过程:
交换屏幕内存和backing buffer,将backing buffer中的信息重新映射到FB,同步硬件状态,并将内存地址转换通知给GPU,以便它能更新内部图像内存映射。
2.GPU
GPU独立图像内容+ FB屏幕内存虚拟化
当foreground VP使用GPU时,会导致屏幕内存的直接变化
当background VP使用GPU时,会导致backing buffer的变化
Cells通过namespace来虚拟化这个子系统
Android有三种电池管理的接口
(1)early suspend:允许驱动在设备suspend之前和resume之后接收通知
Cells通过禁止background VP初始化suspend操作来虚拟化这个子系统。
(2)frame buffer early suspend:将设备的suspend和resume状态展示到用户空间
Cells通过namespace来虚拟化这个子系统。background VP会一直认为设备在睡眠。当转换VP时,原来的background VP会感知到设备苏醒。降低电池使用度
(3)wake locks:有两种状态active和inactive,当inactive时,系统进入低电量模式或暂停。
虚拟化radio stack(射频协议栈),实现VP的电话隔离。
由于Vendor RIL是闭源库,无法直接修改源码加入namespace,因此利用user device namespace proxy在原来的Radio Interface Layer上加了一个RIL Proxy,包括Cells RIL和CellD。
用于控制拨打和接收电话,使得可以接收background VP的来电。
利用VoIP服务实现SIM卡复用。
内核层+用户层虚拟化
(1)核心网络资源虚拟化 network namespace
如IP地址,网络适配器,路由表和端口号
VP的虚拟标识符被转换成物理标识符
内核层实现网络和VP端Ethernet对的NAT转换,实现VP之间的网络隔离
(2)无线配置管理虚拟化
和Telephony一样,利用user device namespace proxy加入了一层代理,代替原有的无线网络配置库和RIL库。
《Condroid: A Container-based Virtualization Solution Adapted for Android Devices》
MobileCloud 2015
项⽬本来有源码的后来取消掉了,剩下⽂档了。文档地址:http://condroid.github.io/
(1)公司监控员工设备,但是员工想保护隐私
(2)攻击需要支持员工的工作环境,在工作后Destroy,下一个工作日又进行恢复
(1)修改Android framework层,构建独立、安全、隔离的一个Android手机设备的多系统
(2)替代了Boionic库(Android的内核库)中不支持的函数
(3)由于安卓系统版本的不同替代了一些系统调用
(4)使用Android NDK toochain交叉编译
(5)重编译内核,融入namespace和cgroup
(1)基于namespace特征的资源隔离
namespace的目的:将一个特定的全局系统资源包装在一个抽象中,使命名空间中的进程觉得它们拥有自己的全局资源的独立实例。每个容器都感知不到其他容器。
(2)基于cgroup特征的资源控制
限制、说明和隔离流程组的资源使用
每个容器都有自己的资源区,不会被其他容器访问
(3)系统服务共享机制
/proc 文件系统
(4)文件系统共享机制
/system分区
Cells修改linux kernel层,Condroid主要修改Android framework层,更多虚拟化Binder子系统
基于容器的结构
内核层和用户层设备虚拟化结合
(1)每个容器都是一个独立的安卓系统
(2)Linux容器技术(Linux Container, LXC)是一种操作系统层的轻量级虚拟化技术,LXC的实现依赖Linux 内核中的NameSpace和Cgroups 机制, NameSpace机制为不同容器间提供了隔离性,Cgroups实现了对容器的资源进行配额。
(3)虚拟化 标识符和硬件资源
(4)host android是控制中心,不会安装任何下载的app
一个Android手机设备的多系统 Binder driver是ServiceManager, Service和apps的桥梁,他们通过在/dev/binder上使用syscall来传递request和response。
Condroid在内核初始化阶段注册一系列的virtual Binder devices。如Figure 2所示,Host提供主要的IPC组件(Binder Driver, ServiceManager),而在容器中的app通过virtual Binder Device与host的Binder进行通信。
Virtual Binder Driver主要有两个功能:
(1)将app在virtual binder driver上做的操作转给real binder drive
(2)如果操作是注册或请求服务,virtual driver会将service名改为Hash值,解决了命名冲突的问题
Foreground container独占显示屏,但是background container的显示图像需要被及时更新和保存,以便切换系统时能及时显示实时图像。
Cells:在Linux kernel层虚拟化framebuffer device
ConDroid:在Android framework层修改WindowManager(控制window生命周期、输入时间、位置等参数的系统服务),WindowManager会将所有的window元数据发送给SurfaceFlinger,由SurfaceFlinger进行图形显示。
WindowManager的window stack决定了SurfaceFlinger会将哪个window显示在屏幕上。ConDroid通过修改container的偏移来进行屏幕切换。
拦截非当前系统的event事件,只有foreground container才能感知到用户输入
input manager有两个对象:mInputDisaptcher和mInputReader(修改对象)。mInputDisaptcher负责将输入事件分配到现在激活的窗口中,mInputReader负责监控输入事件。
有些服务是可以在多个container之间共享的,比如电池、wifi等,Condroid允许用户通过/proc文件系统定制共享服务。
host共享只读文件及目录给各个container
系统层虚拟化的两种方案就介绍到这里了,想要知道更多细节的可以点进两种方案的链接深入学习。那么,大家有没有好奇应用层虚拟化技术是怎么实现的呢?且听下回分解。
技术创作101训练营
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。