Android中有些应用APP会用到系统Server提供的服务,其中有些Server是android 原生自带的,有些是OEM厂商定制添加的,可以使用service list 命令查看,怎么评估其安全性呢? 这些Server是注册在ServiceManager中,使用android binder机制进行通信,厂商定制的Server常用AIDL的方式编写服务, 所以先对android binder,ServiceManager,AIDL做简单的介绍, 基于上述原理

写自动化测试工具辅助安全测试。

01 Android binder架构

Binder 是android系统中使用的IPC进程间通信机制,应用层APP intent通信就是依赖底层Binder机制,它整体机制比较复杂,如下图所示:

android 安全檢驗 android检测中心_android app系统的测试

简要概况如下:

内核空间主要是binder驱动,它是一个标准的Linux驱动,Binder Driver将自己注册成misc device并向上层提供一个/dev/binder节点,可以提供open(), ioctl(), mmap()等常用文件操作,通过一次内存拷贝实现进程间数据共享。 用户空间分为C/C++和Java两个部分,中间通过JNI进行衔接。其中ServiceManager大部分代码都是用C/C++实现,Java层ServiceManger通过JNI实现了代码复用。 02 ServiceManger

Binder架构以客户端-服务端模型运行,也就是C/S架构。允许多个进程(client)同时调用进程(server)中的多个方法。ServiceManager用来管理注册的Server,给client提供查询Server接口的功能。如下图所示:

android 安全檢驗 android检测中心_Server_02

android 安全檢驗 android检测中心_返回包禁止返回server_03


ServiceManager内部维护着一个svclist列表,用于存储所有Server相关信息,查询和注册都是基于这个列表展开,并且通过Binder驱动协议与底层Binder驱动通信。 03 AIDL

手工实现一个Binder Server比较麻烦, 有没有更简洁的方式?答案是AIDL , AIDL是Android 接口定义语言(Android interface define language)。用于生成可以在Android设备上两个进程通讯(IPC interprocess communication)的代码,  AIDL的优点是:跨进程,多并发。 现在很多集成开发工具如android studio通过创建aidl文件自动生成所需java代码,所以基于AIDL的Binder Server很常见。如下图所示,可见还是基于Binder机制通信 。

android 安全檢驗 android检测中心_Server_04

android 安全檢驗 android检测中心_android 安全檢驗_05

Server端实现分三步骤

·

抽象接口,编写aidl文件 ·

编写service, 实现接口,处理客户端请求,并将Binder返回 ·

Androidmanifest.xml配置Service,将Service暴露

android 安全檢驗 android检测中心_返回包禁止返回server_06

Client端实现

·

将服务端的aidl文件copy过来,放在同一个包下 ·

构造intent启动服务端service, 保存服务端返回的Binder ·

通过返回Binder调用服务端方法 整个原理大致如下:

android 安全檢驗 android检测中心_Server_07

总结就是client序列化数据,Binder传输数据, Server反序列化数据,处理完后返回。

FUZZ测试的时候一般拿不到服务端的aidl文件,该怎么处理呢?根据aidl文件生成的代码

android 安全檢驗 android检测中心_android 安全檢驗_08

android 安全檢驗 android检测中心_返回包禁止返回server_09

android 安全檢驗 android检测中心_返回包禁止返回server_10

android 安全檢驗 android检测中心_服务端_11


mRemote是android.os.IBinder类型,调用transact函数,通过构造Parcel类型的参数,实现了对Server端setSystemProperty函数的调用,这提供了fuzz思路。 04

自动化测试工具代码编写逻辑

根据以上的原理,自动化测试工具代码编写逻辑如下:

1. 列出所有注册在ServiceManager中的系统服务名 2. 反射获取android.os.ServiceManager对应类及其getService函数 3. 反射调用getService函数传入1步骤获取的系统服务名获取IBinder 4. 通过IBinder获取接口名,通过反射获取接口中Stub内部类,反射获取Stub类中以TRANSACTION_开头的字段,获取其对应值,记为code, 形如static final int TRANSACTION_setUserName =  10, code 等于 10,setUserName认为是函数名。再通过反射获取接口下的方法名、方法参数类型,返回值类型 5. 构造Parcel类型参数,调用IBinder下transact(int code,Parcel data, Parcel reply,int ) 函数,这个函数中有4个参数,第一个参数就是4步骤中的code,服务端会根据code调用相应处理函数。但是4步骤中有可能获取不到code,这里会默认分别尝试[0,20]区间,和[21,1000]中的一个随机值。 第二个参数data是发送数据,首先需要调用writeInterfaceToken填充一下接口名,接着填充函数参数,参数类型就是4步骤中获取的参数类型,这里做两种fuzz策略: 1)精确识别出code, 构建精确的参数类型与个数,进行精准测试,主要用于测试Server提供的服务函数能否被任意调用。 2)精确识别出code,识别不出使用枚举code或随机code, 每次请求只写入int类型“0”或者”1”, String 空类型或者非空,反序列化的对象等。通过返回值,快速识别FUZZ目标的接口是否有拒绝服务。 第三个参数reply是返回值,结合日志,异常等有利于判断问题类型。第四个通常设置为0 05

总结

一般发现问题如下:

· 系统拒绝服务导致手机重启

· 调用敏感函数,提升权限


但也有如下不足之处: 1. 某些系统服务并不能通过反射的方式获取,比如服务端提供的服务代码在native层 2. 基于日志监测结果的FUZZ方法,对于拒绝服务手机重启的情况,不一定能精确定位到系统服务的某个函数,不过对于单台手机每次测试服务次序是线性不变的,可以通过跳过某些系统服务及其函数,和函数FUZZ后及时刷新日志来减少测试时间和精准定位测试函数。 3. 有些Binder Service 并不在ServiceManager中注册,通过其它注册的Server做为中介,有些书中称呼这种叫匿名Binder Service,上述方法没办法测试到。 4. 工具不是万能的,对于C/C++编写的系统服务,目前主要通过安全设计规范与代码审计规避风险。有些系统服务提供的java层函数要用反射的方式手工调用验证,也有fuzz效果不好的服务需通过构造aidl文件,手工验证。

END


长按关注  最新动态


android 安全檢驗 android检测中心_android 安全檢驗_12

android 安全檢驗 android检测中心_android 安全檢驗_13

好文!在看吗?点一下鸭!