zoukankan      html  css  js  c++  java
  • 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的类,能够非常easy地处理好这个问题,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

  • 相关阅读:
    探讨GTK+应用程序的优化方法
    X Window研究笔记(9)
    X Window研究笔记(10)
    X Window研究笔记(7)
    用gdbserver调试共享库(改进版)
    X Window研究笔记(11)
    Gtkminimo中的几个BUG
    编译基于DirectFB的Phoneme(Advance)
    X Window研究笔记(8)
    X Window研究笔记(12)
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/3992692.html
Copyright © 2011-2022 走看看