声明
- 最近工作上涉及到对Android系统安全性的改造,在改造之前先分析整理下目前Android系统自身的安全性;
- 参考了一些文章及书籍,在这里大部分是对别人描述的提炼,我挑出一些对我有用的内容整理;
1 Dalvik/ART层上的权限(应用权限)
1.1 对Dalvik/ART上Java代码的监视和对原生Native层上C/C++代码的监视
因为Android的Java代码需要运行在Dalvik/ART虚拟机上,使得Dalvik/ART虚拟机能够在监视操作和强制安全检查方面有很大操作空间。而对于原生Native代码,虽然也能靠监视系统调用的方式来获知程序对资源的访问情况,但监视系统调用的问题是: 它们所能提供的监视粒度不够精确。比如:
- 文件访问,也就只有“open/read/write/close”这几个操作;
- 完成一次DNS查询,由于需要调用多个系统调用,监视起来就很费力;
此时,虚拟机的优势就显现出来了,因为大多数的操作都是由预先提供的包或类来实现的,而这些包或类中己经自带了权限检查功能。
1.2 绕过Dalvik/ART上Java代码的监视?
Android系统做得很绝,作为恶意编程者来说即便你有虚拟机层面的监事操作和强制安全检查,但是我依然可以在一个正常的Java类中显式地导入其他类,并在这些被导入的其他类中实现一些恶意的功能代码,甚至我直接在类里添加Native方法使用JNI来逃避虚拟机的监控范围,从而避开Dalvik/ART虚拟机权限检查。这样做可不可以呢?
但是这一做法在Android早就考虑到了,因为我在《[日更-2019.5.6、7] Android 系统的安全性分析(一)--移动设备上的安全威胁》中提到用户APP安装后只有有限的权限可用,它在Linux层上没有任何权限或权能,它对任何超越权限的系统底层资源的访问都会被直接拒绝。因为用户APP想要做任何影响会超出应用自身范围的操作时,都必须调用getSystemService()函数,通过system_server 中的服务完成相关操作。
1.3 Android留的后手:system_server及应用权限系统
任何应用都能任意发起调用system_server中相关系统服务的请求,但是请求是不是会被允许,就不是应用说了算的,因为system_server会对请求是否符合权限规定进行审核。这一审核是在应用自身进程之外进行的,所以除了事先就已经被分配到了的权限之外,应用是没有任何途径能获取相关服务的访问权限的。
而权限的分配则是在安装或加载应用或时执行的(不过在Android 6.0以后Android也开始采用iOS那种运行时检查权限的模式,在相关操作发生的时候,才使用应用自身进程以外的另一个进程来提示用户),这也就意味着用户会看到系统自动弹出一个对话框,提示该应用需要什么权限,再由用户同意授予应用这些的权限。如果应用运行时所请求的操作因没有相关权限而被拒绝,那么就会抛出一个安全异常(正常情况下,这会导致应用崩溃一一除非开发者专门为这类异常编写了异常处理代码,这种情况下,应用将会自己来处理这个异常,通常会弹出一个对话框解释应用需要什么权限,有时也会静静地做好收尾工作,并结束程序)。
接下来要说的是:权限本身是不需要任何特殊的数据结构或复杂的元数据来表示的。在Dalvik虚拟机中的权限只不过是一个简单的常量值一一这个值是根据应用在它的(AndroidManifest.xml文件中的) < user-permission>元素中声明的权限,分配在它的mainifest 中的。应用也可以在Manifest 中的<permission>标签里,定义它自己的常量。当包管理器安装一个应用时,它会把应用自己声明的权限,添加到“权限数据库”中去。这个所谓的“权限数据库”实际上只是包数据库(/data/system/packages.xml)的一部分。这个数据库中除了权限之外,还含有大量(包括各个应用的公钥在内的)极具价值的信息。
2 Android 如何将APP在Dalvik/ART虚拟机层上的权限映射至Linux UID上
Dalvik/ART虚拟机层上的权限最终还是会落在它的支撑者Linux的UID/GID上,因为它的权限机制实现的Linux基础就是Linux自身的用户机制,不同的权限对应的就是Linux上的不同UID/GID。
Dalvik层面上的权限到Linux层面上的权限之间的“桥梁”是/system/etc/permissions/platform.xml文件。这是个包含在AOSP源码中的文件,有良好的文档支持,以便厂商能够(谨慎地〉往其中添加特定的权限或AID 。映射可以以两种方式进行:
- 可以用<permission>标签,把Dalvik上Java语言使用的权限与记录在<group> 标签中的GID关联起来;
- 也可以用<assign-permission>Dalvik上Java语言使用的权限赋予某个UID。
如果查看你自己的移动设备上的/system/etc/permissions/目录,或许会看到目录中有另外几个XML文件(android.hardware.和android.software.),这些文件都是在build系统的过程中,从AOSP源码文件中复制过来的,其中有些也可能是厂商加进来的文件。
3 代码签名
在第1节提到了应用权限问题,但是存在一个操作上的问题,因为所有的应用都能在它的AndroidManifest.xml中声明它需要使用哪些权限,而一些不靠谱的用户也可能在提示框弹出后,看也不看就直接去点“确定”按钮。
所以为了保证安全性,Google规定所有上传到Google Play商店中的应用都必须经过数字签名,这样就能验证应用开发者的身份,并在必要时能够追究相关的责任。
因此,所有的Android应用都必须经过签名。Google出于同苹果竞争的考虑,开放了Google Play商店,希望通过简化发布验证流程的形式,吸引开发者。相对于苹果公司冗长的发布验证流程(所有的应用都必须通过苹果公司的审查,并对它们做数字签名),Google则让任何人都能对应用进行数字签名,只要创建一对(公,私)密钥,公开他们的公钥,井用私钥对他们的APK文件做数字签名就行了。
Google这样做的理由是:在仍然保证可以有效验证APK的作者的前提下,极大的简化将应用提交到商店中的流程。这一做法使得Google Play商店里恶意软件的数量爆炸式增长。Google处理这一问题却采取了亡羊补牢的对策:一旦发现或有人举报恶意软件,就直接把它从商店里删掉,同时把对应的公钥加入黑名单里去。