关于android设备管理器的一些分析

转自http://bbs.pediy.com/showthread.php?t=183692

想必很多人都知道轰动一时android木马OBAD,该木马利用android设备管理器的漏洞,当用户激活设备管理器后,该程序会在setting设备管理器列表隐藏,应用程序激活成设备管理器后,可以实现锁屏、擦除用户数据等功能,并且无法使用常规的卸载方式对其卸载,本文主要和介绍漏洞原理和漏洞补丁分享个人在分析过程中遇到的一些事情。


Android 在实现设备管理器时,需要再manifest.xml中注册一个广播接收者,代码如下
 

 <receiver
       android:name=".MyDeviceAdmin"
       android:permission="android.permission.BIND_DEVICE_ADMIN" > 
       <meta-data
            android:name="android.app.device_admin"
            android:resource="@xml/device_admin" /> 

       <intent-filter>
             <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
       </intent-filter>  
</receiver> 

 

OBAD如何在setting的管理器列表隐藏呢,我们可以通过setting的源码找到答案。相关代码:packages\apps\Settings\src\com\android\settings\DeviceAdminSettings.java
  主要方法:

void updateList() {
        mActiveAdmins.clear();
        List<ComponentName> cur = mDPM.getActiveAdmins();
        if (cur != null) {
            for (int i=0; i<cur.size(); i++) {
                mActiveAdmins.add(cur.get(i));
            }
        }
//获得已经激活设备管理器列表mActiveAdmins
        mAvailableAdmins.clear();
// mAvailableAdmins setting的设备管理器列表
        List<ResolveInfo> avail = getActivity().getPackageManager().queryBroadcastReceivers(
                new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED),
                PackageManager.GET_META_DATA);
//获取所有注册了DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED即android.app.action.DEVICE_ADMIN_ENABLED action的广播接收者列表avail
        int count = avail == null ? 0 : avail.size();
        for (int i=0; i<count; i++) {
            ResolveInfo ri = avail.get(i);
            try {
                DeviceAdminInfo dpi = new DeviceAdminInfo(getActivity(), ri);
               
                if (dpi.isVisible() || mActiveAdmins.contains(dpi.getComponent())) {
                    mAvailableAdmins.add(dpi);
          //如果应用注册了包含该action的广播接受者并且激活了设备管理器,就会在setting的设备管理器列表中显示
                }
            } catch (XmlPullParserException e) {
                Log.w(TAG, "Skipping " + ri.activityInfo, e);
            } catch (IOException e) {
                Log.w(TAG, "Skipping " + ri.activityInfo, e);
            }
        }
               getListView().setAdapter(new PolicyListAdapter());
    }

 


但是没有注册android.app.action.DEVICE_ADMIN_ENABLED action的应用也可以激活为设备管理器。

这就导致了激活后的设备管理器无法在setting的设备管理器列表中显示。

如何解决这种情况呢?下面我们一起来分析一下安全管家的设备管理器补丁。该补丁是一个正常的apk,反编译之,代码结构如下
 
主要类DeviceAdminProxy代码如下:

 //上面方法的主要内容就是对比直接通过DevicePolicyManager获得的已经激活的设备管理器列表a和通过遍历注册了android.app.action.DEVICE_ADMIN_ENABLED action的列表b进行对比,如果发现列表a中的设备管理器没有在列表b中出现,就调用如下代码弹出取消激活的activity,让用户手动取消。

 代码中有一个RootMain的类,这个类在当能获得root权限的时候使用,找到利用这个漏洞的设备管理器后直接调用DevicePolicyManager的removeActiveAdmin方法取消激活,该方法需要system以上权限才能执行。
关于android.app.action.DEVICE_ADMIN_ENABLED引起的漏洞都这里就结束了,下面说一下在分析中遇到的另外一件有趣的事。
前面讲到setting获取管理器列表时,有这么一段代码,如下图
 
代码中实例DeviceAdminInfo对象,DeviceAdminInfo.java在frameworks\base\core\java\android\app\admin\DeviceAdminInfo.java
关键代码:
 
之前我们在manifest的receiver中有如下配置:
 
如果不配置meta-data,DeviceAdminInfo类就会抛出异常,DeviceAdminSettings中获取异常,按照上面图中的代码可以发现,同样setting的设备管理器列表也无法显示。这样setting虽然不显示了,但是,如果不配置meta-data,设备管理器时没办法正常激活的。怎么办呢?用正常的设备管理器程序安装,正常激活,然后删除该程序的meta-data配置,生成apk,以更新安装的形式安装到android设备上。这个时候卸载该程序会发现,该程序已经激活为设备管理器,但是在setting设备管理器列表中找不到。因为设备管理器注册了android.app.action.DEVICE_ADMIN_ENABLED,所以使用上述的设备管理漏洞补丁也是找不到的。
那么如何取消激活呢?从上面对于设备管理器漏洞补丁apk的分析可以得出两种取消激活的方法分析(其实是三种):
一、  DevicePolicyManager获得的已经激活的设备管理器列表,然后使用下面的代码 

启动取消激活的activity。测试结果是行不通的,因为DeviceAdminAdd也需要解析meta-data中的信息。具体参见DeviceAdminAdd.java位于packages\apps\Settings\src\com\android\settings\ DeviceAdminAdd.java。
二、  获取到激活的设备管理器列表后直接调用DevicePolicyManager的removeActiveAdmin方法取消激活,测试结果成功,但是需要system以上的权限。DevicePolicyManager.java位于frameworks\base\core\java\android\app\admin\DevicePolicyManager.java。
问题分析到这里的时候可能有些童鞋已经发现了,使用正常的apk激活设备管理器,然后使用异常的apk避免设备管理器被取消。那如果android设备重启了呢?重启以后还能保持激活吗?答案是否定的,重启设备以后,无法保持激活。原因是什么呢?分析如下:
主要代码frameworks\base\services\java\com\android\server\DevicePolicyManagerService.java
Android设备重启以后,SystemServer启动DevicePolicyManagerService服务同时调用systemReady方法重新初始化设备管理器列表。如下:
 
loadSettingsLocked方法中调用findAdmin
 
代码到这里就可以看到了,在获取meta-data的时候会捕获异常,返回空值。
 
所以第三种方法:重启……
如有不对的地方欢迎指正。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。