两年前写的东西,现在发一下。写了个最简单的fuzz脚本:基于adb的fuzzer,仅供学习,请勿作不良用途。

一、背景知识

二、Fuzz原理

  Android为用户提供的很多功能是通过系统服务实现的。截至Android 6.0,系统服务数量已经达到60多个。系统服务的底层是system_server(以下简称ss),我们知道,Android存在watchdog程序,当系统服务长时间不响应时,watchdog会杀死ss进程,从而导致Android系统的软重启。Android提供的系统服务底层是通过binder进程间通信机制实现的,binder的数据传递过程这不在详解。从Java层传递的数据,最终会在C/C++代码中被使用。不管是java还是c/c++,如果传递了一个null指针引用。将会导致程序的崩溃,Android系统因此也受此影响。本Fuzz测试旨在发现Android系统服务的代码实现中,由于没有null指针做好处理导致的系统奔溃。

  Android对外提供的系统服务,根据提供的功能,实现了不同的函数,以供开发者调用。例如,开发者在上层调用发送短信的API,其底层同样是通过binder调用了短信的系统服务。这些可以通过binder调用的方法一般定义在.aidl文件,一些系统服务定义了多达数百个可调用的方法。这样,可通过binder调用测试的方法多大几千个。所以,通过Fuzz测试这些方法不失为一种好的测试手段。

  在Android Binder机制实现进程间数据交换(不使用aidl实现)中,已经说明了如何利用binder调用系统服务实现发送短信的功能。除了编写本地App通过binder来调用系统服务之外。其实,Android已经给我们留下了“测试后门”。在shell中,通过service指令可以直接对系统服务进行测试,并支持对所有aidl文件中定义的方法的测试。

  其中,service call SERVICE CODE 就是对aidl文件中定义的方法的测试。其中,SERVICE就是对应的service名,code就是在aidl文件中定义的方法,其数值根据定义的方法递增,从1开始。例如,在IAccessibilityManager.aidl文件中,定义了以下方法。

三、测试框架

  了解了以下原理之后,就可以编写Fuzz工具进行测试了。这里工具实现方式有两种,一是编写脚本调用的shell提供的service指令测试,而是编写本地App,通过调用binder来对系统服务进行测试。我们采用第二种,更加有利于我们学习Android系统服务及binder通信机制的相关知识。这里不给出具体的代码,后面会上传的github,只给出一些关键的地方。

  获取所有的系统服务。

    /**     * 获取系统中所有的服务名     * @return 服务名字符串数组     */    public String[] ListService() {        String  SM[]={};        try{            SM=(String [])Class.forName("android.os.ServiceManager").getMethod("listServices").invoke(null);            //  Log.d(tag,"I find there are "+SM.length+" System Services");            for(int i=0;i< SM.length;i++){                //    Log.d(tag,SM[i]);            }        }catch(Exception e){            e.printStackTrace();            Log.e(tag, e.toString());        }        return  SM;    }

  通过反射获取IBinder接口对象。

    /**     * 使用反射机制获取服务的IBinder接口     * @param sername 服务名     * @return 返回服务的IBinder接口     * @throws Exception     */    private static IBinder getIBinder(String sername) throws Exception{        Class smcls = Class.forName("android.os.ServiceManager");        Method mth = smcls.getMethod("getService", String.class);        return (IBinder) mth.invoke(null, sername);    }

  通过binder获取接口名。

    /**     * 获取接口名     * @param serHandle 服务的IBinder接口     * @return 返回接口名字符串     * @throws RemoteException     */    private static String getInterfaceName(IBinder serHandle) throws RemoteException {        Parcel data = Parcel.obtain();        Parcel reply = Parcel.obtain();        serHandle.transact(INTERFACE_TRANSACTION, data, reply, 0);        String interfacename = reply.readString();        data.recycle();        reply.recycle();        return interfacename;    }

  通过binder调用系统服务函数,进行测试。

    void testNUll(String sername, int code) {        for (int i = 0; i < testcaseint.length; i++)            for (int j = 0; j < testcaseint.length; j++) {                try {                    Log.d(tag, "-" + sername + "-" + code + "-arg1-" + testcaseint[i] + "-arg2-" + testcaseint[j]);                    Parcel data = Parcel.obtain();                    Parcel reply = Parcel.obtain();                    IBinder ib = getIBinder(sername);                    String in = getInterfaceName(ib);                    data.writeInterfaceToken(in);                    data.writeInt(testcaseint[i]);                    data.writeInt(testcaseint[j]);                    // data.writeInt(0);                    //  data.writeInt(3);                    ib.transact(code, data, reply, 0);                    //可以读出reply中的数据                    // Log.d(tag, "-" + sername + "-" + code + "-" + "reply is \n" + reply.readString());                    reply.readException();                    data.recycle();                    reply.recycle();                } catch (Exception e) {                }            }    }

  单次调用binder测试系统服务中定义的方法流程如下。

Created with Raphaël 2.1.2 通过反射获取binder对象 填充除code外被写入parcel的参数 调用transact()函数完成对aidl中定义方法的调用 监控系统异常

  整个Fuzz工具的架构如下:


  还有一个问题,要实现整个Fuzz的自动化,还需要自动化监控系统重启事件。

四、DoS的自动化检测

  Android系统开机完成之后,会发出一个BOOT_COMPLETED 系统广播 ,所以通过检测此广播可以监控系统是否发生了重启,从而确定漏洞位置,即哪一个系统服务对应的哪一个方法触发。除此之外,BOOT_COMPLETED 广播是由ActivityManagerService的finishBooting方法发出的,所有可以通过Hook此API完成监测。鉴于Xposed的Hook框架可以很容易的帮助我们做到这点。

更多相关文章

  1. Android(安卓)简单实现倒计时功能
  2. 一篇文章看明白 Android(安卓)图形系统 Surface 与 SurfaceFling
  3. webview的白屏,和硬件加速
  4. Android-工作遭遇-URLConnection原生请求http和https忽略证书
  5. Android(安卓)-- AppWidget 高级篇
  6. 初识android 自定义控件
  7. 用Fragments在Android中进行多窗格开发
  8. 28、compileSdkVersion,minSdkVersion,targetSdkVersion 的区别和
  9. Android(安卓)Handler那些事儿(二)——几个关键类之间的关系

随机推荐

  1. 安卓开发学习之003 LinearLayout之baseLi
  2. Android分享笔记(4) Android的webview加
  3. Android(安卓)UI Event Listener
  4. Android中文API (110) ―― CursorTreeAd
  5. Android(安卓)P专区免费开放 -- 同样的An
  6. Android 6.0权限使用详解
  7. Parcelable
  8. eScan Mobile Security for Android:适用
  9. Android跳转到应用商店详情页面
  10. android体系介绍