Binder Proxy技术方案

Binder Proxy技术方案

作者 低端码农

时间 2014.08.23

0x0

看到有多朋友尝试通过hook系统进程system_process的ioctl,以企图截获系统的IPC通讯。这个方案的弊端是太偏低层了,当截获成功了之后,要解析其中的通讯数据是比较麻烦了. 另外,其中还涉及一堆兼容性的问题,由于不同的Android固件版本,有好些Parcelable结构的字段是有所改动,这些变化如果ioctl里做解析,都需要一一顾及到才行,因此这个方案我认为距离产品化还有一段距离。

0x1

在Android上,所有系统的NativeService主要保存在system_process和com.android.phone这两个进程,比如我们经常看到的ActivityManagerService(AMS)。这些NativeService大部分都是继承自Binder的Java对象,没错,他们是Java对象。

我们知道,Android上的大部分IPC通讯都是通过其特有的binder模块进行的,因此上述的Java的NativeService要跟内核进行通讯,因为只有c/c++才能直接跟内核交互,因此这里必然存在JNI通讯。比如AMS的设计:

AMS继承Binder(IBinder的子类,封装了IPC通讯公共部分的逻辑),Binder里保存着一个类型为int的mObject的字段,这个字段正是其C++对象JavaBBinder对象的地址,这个JavaBBinder才是AMS最终跟内核通讯的对象。代码如下:

public class Binder implements IBinder {
    //...

    /* mObject is used by native code, do not remove or rename */
    private int mObject; //这个对象保存的就是JavaBBinder的指针
    private IInterface mOwner;
    private String mDescriptor;

    //...
}

同样的,在JavaBBinder中,也保存着一个类型jobject的mObject,指向上层Java对象。看看JavaBBinder的代码:

class JavaBBinder : public BBinder
{
//...

    jobject object() const
    {
        return mObject;
    }

    //...

    private:
        JavaVM* const   mVM;
        jobject const   mObject; //这个保存的是AMS的引用
    };
}

Java和C++就是通过这两个字段相互连结在一起的。

其中JavaBBinder中的mObject是整个IPC关键的一节,所有的client请求,都是先到达JavaBBinder,然后JavaBBinder再通过JNI调用mObject的execTransact的方法,最终把请求发送到AMS。

因此,我们只要想办法找到AMS的对象的JavaBBinder,再把mObject替换为代理对象(记作ProxyBinder,这个对象是我们实现的Java对象),就可以实现Binder Proxy了,下面是示意图:

0x2

在Java层,要获取AMS引用,通过ServiceManager即可,不过这类是隐藏类,通过反射才可以调用。通过ServiceManager.getService("activity")即可以拿到AMS。

在Native,要获取AMS所对应的JavaBBinder地址,defaultServiceManager的getService方法获取到。

接下来就是要替换mObject对象了,JavaBBinder的mObject对象并不能直接替换,因为mObject是const的,我写了一个DummyJavaBBinder的类,可以很容易地处理好这个问题,DummyJavaBBinder的实现如下:

class DummyJavaBBinder : public BBinder{
public:
    virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) {
        return NO_ERROR;
    }

    jobject object() const {
        return mObject;
    }

    JavaVM* javaVM() const {
        return mVM;
    }

    void changeObj(jobject newobj){
        const jobject* p_old_obj = &mObject;
        jobject* p_old_obj_noconst = const_cast<jobject *>(p_old_obj);
        *p_old_obj_noconst = newobj;
    }

private:
    JavaVM* const   mVM;
    jobject const   mObject;
};

0x3

由于BinderProxy截获的层次比较高,因此请求数据结构的解析都非常方便,所使用接口大部都是Framework的接口,兼容性也不存在,下面是我写的一个示例,示例主要是实现如何让某个pkg免杀:

private static final class ProxyActivityManagerServcie extends Binder {
    private static final String CLASS_NAME = "android.app.IActivityManager";
    private static final String DESCRIPTOR = "android.app.IActivityManager";
    private static final int s_broadcastIntent_code;

    static {
        if (ReflecterHelper.setClass(CLASS_NAME)) {
            s_broadcastIntent_code = ReflecterHelper.getStaticIntValue("BROADCAST_INTENT_TRANSACTION", -1);
        } else {
            s_broadcastIntent_code = -1;
        }
    }

    private IBinder mBinder;

    public ProxyActivityManagerServcie(IBinder binder) {
        mBinder = binder;
        mResorter = new SmsReceiverResorter(binder);
    }

    @Override
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        /**
         *
         *  public int broadcastIntent(IApplicationThread caller,
         *    Intent intent, String resolvedType,  IIntentReceiver resultTo,
         *    int resultCode, String resultData, Bundle map,
         *    String requiredPermission, int appOp, boolean serialized,
         *    boolean sticky, int userId) throws RemoteException
         */
        if (code == s_broadcastIntent_code) {
            pos = data.dataposition();

            data.enforceInterface(DESCRIPTOR);
            IBinder caller = data.readStrongBinder();
            Intent intent = Intent.CREATOR.createFromParcel(data);
            String resolvedType = data.readString();
            IBinder resultTo = data.readStrongBinder();
            int resultCode = data.readInt();
            String resultData = data.readString();
            Bundle map = data.readBundle();
            String requiredPermission = data.readString();
            int appOp = data.readInt();
            boolean serialized = data.readInt() != 0;
            boolean sticky = data.readInt() != 0;
            int userId = data.readInt();

            //TODO 获取到所有的参数,根据参数做各种截获

            //FINAL
            data.setDataPosition(pos);
        }

        return mBinder.transact(code, data, reply, flags);
    }
}

0x4

这个技术方案,涉及到注入和dex加载,这方面网上教程非常多,so注入可以参考古河大神的LibInject, 而Java注入可以参考malokch的《注入安卓进程,并hook java世界的方法》.

另外也可以参考我之前写的系列文章《进击的Android注入术》。这个系列详细讲述了so注入,dex注入到binder proxy的整个技术细节。

示例的源码我已经上传到https://github.com/boyliang/Hijack_AMS_broadIntent

时间: 2024-08-27 16:27:46

Binder Proxy技术方案的相关文章

基于IOS和Android设备MDM技术方案服务价格

导读:前段时间 www.mbaike.net 博客被恶意攻击,导致程序崩溃,目前已经替换了以前的Wordpress程序,现提供IOS和Android版本MDM的代码和相关文档咨询服务. 一.IOS版MDM服务内容及价格: 套餐一:IOS端MDM Server代码(提供MDM Server端的代码和部署文档,不含后期技术支持) 3000元套餐二:IOS端MDM开发技术顾问(提供MDM开发的顾问服务,协助理解MDM原理流程及搭建MDM Server工作的咨询) 1500元套餐三:IOS端MDM全部服

Python web实时消息服务器后台推送技术方案---GoEasy

Goeasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送!个人感觉goeasy推送更稳定,推送速度快,代码简单易懂上手快浏览器兼容性:GoEasy推送支持websocket 和polling两种连接方式,从而可以支持IE6及其以上的所有版本,同时还支持其它浏览器诸如Firefox, Chrome, Safari 等等.支 持不同的开发语言:   GoEasy推送提供了Restful API接口,无论你的后台程序用的是哪种语言都可以通过RestfulAPI来实现后台实时推送.

C(++) web实时消息服务器后台推送技术方案---GoEasy

Goeasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送!个人感觉goeasy推送更稳定,推送速度快,代码简单易懂上手快浏览器兼容性:GoEasy推送支持websocket 和polling两种连接方式,从而可以支持IE6及其以上的所有版本,同时还支持其它浏览器诸如Firefox, Chrome, Safari 等等.支 持不同的开发语言:   GoEasy推送提供了Restful API接口,无论你的后台程序用的是哪种语言都可以通过RestfulAPI来实现后台实时推送.

node.js web实时消息服务器后台推送技术方案---GoEasy

Goeasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送!个人感觉goeasy推送更稳定,推送速度快,代码简单易懂上手快浏览器兼容性:GoEasy推送支持websocket 和polling两种连接方式,从而可以支持IE6及其以上的所有版本,同时还支持其它浏览器诸如Firefox, Chrome, Safari 等等.支 持不同的开发语言:   GoEasy推送提供了Restful API接口,无论你的后台程序用的是哪种语言都可以通过RestfulAPI来实现后台实时推送.

Websocket web实时消息服务器后台推送技术方案---GoEasy

Goeasy, 它是一款第三方推送服务平台,使用它的API可以轻松搞定实时推送!个人感觉goeasy推送更稳定,推送速度快,代码简单易懂上手快浏览器兼容性:GoEasy推送支持websocket 和polling两种连接方式,从而可以支持IE6及其以上的所有版本,同时还支持其它浏览器诸如Firefox, Chrome, Safari 等等.支 持不同的开发语言:   GoEasy推送提供了Restful API接口,无论你的后台程序用的是哪种语言都可以通过RestfulAPI来实现后台实时推送.

iOS开发--四种多线程技术方案

iOS 多线程的四种技术方案 image pthread 实现多线程操作 代码实现: void * run(void *param) { for (NSInteger i = 0; i < 1000; i++) { NSLog(@"---buttonclick---%zd---%@", i, [NSThread currentThread]); } return NULL; } @implementation ViewController - (IBAction)clickBut

分布式锁1 Java常用技术方案

前言:       由于在平时的工作中,线上服务器是分布式多台部署的,经常会面临解决分布式场景下数据一致性的问题,那么就要利用分布式锁来解决这些问题.所以自己结合实际工作中的一些经验和网上看到的一些资料,做一个讲解和总结.希望这篇文章可以方便自己以后查阅,同时要是能帮助到他人那也是很好的. ===============================================================长长的分割线===================================

在线客服系统 开发实战系列(一:需求分析及技术方案初步选型)

在这个系列的文章里,我将尝试一步一步开发一套功能完备的在线客服系统,并最终将其开源在 Git 上,欢迎关注. 鉴于水平限制,难免有所疏漏,欢迎批评指正. 文章将分为几个部分 一.需求分析及技术方案初步选型 二.技术方案选型,验证 三.底层框架设计,开发 四.服务器设计开发 五.客户端设计开发 六.Web端设计开发 在这个系列的文章中,您将了解并学习到以下技术知识: MSMQ.YUI.WebSocket.WinForms 如果这些技术对您有用,还请您 推荐 一下本文章,谢谢! 首先我们大概看看什么

安卓推送技术方案实现探讨

背景介绍 随着苹果产品的风靡,推送技术在国内也越来越热门.推送最开始用于邮件系统.随着iPhone 和 Android 手机的风靡,逐渐在手机上也越来越常见.不少手机客户端也时常推送一些消息. 推送技术的应用 推送技术在手机上的应用主要有两块:广告推送.SNS信息推送. l  广告推送:给目前有一定安装量但没有盈利模式的手机应用开发者带来了一定希望,但要注意推送的频度和内容选中,不然会因为推送的东西用户不感兴趣造成打扰. l  SNS信息推送:主要用于QQ空间.人人网.微博和天涯论坛等web2.