首页
社区
课程
招聘
[原创]BinderProxy技术方案
发表于: 2014-8-23 11:35 17836

[原创]BinderProxy技术方案

2014-8-23 11:35
17836
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](http://www.kanxue.com/bbs/showthread.php?t=141355), 而Java注入可以参考malokch的[《注入安卓进程,并hook java世界的方法》](http://www.kanxue.com/bbs/showthread.php?t=186054).

另外也可以参考我之前写的系列文章[《进击的Android注入术》](http://blog.csdn.net/l173864930/article/details/38468433)。这个系列详细讲述了so注入,dex注入到binder proxy的整个技术细节。

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

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 3
支持
分享
最新回复 (17)
雪    币: 62
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
不错,前排就坐学习
2014-8-23 12:18
0
雪    币: 101
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
mark
2014-8-23 12:47
0
雪    币: 370
活跃值: (1176)
能力值: ( LV9,RANK:310 )
在线值:
发帖
回帖
粉丝
4
mark,不错!
2014-8-23 14:07
0
雪    币: 76
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
学习了!
2014-8-23 20:57
0
雪    币: 19
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
mark
2014-8-25 21:46
0
雪    币: 37
活跃值: (28)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
看起来是markdown转的pdf?
怎么转的?
2014-8-25 22:40
0
雪    币: 85
活跃值: (51)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
8
mark
2014-8-25 23:06
0
雪    币: 233
活跃值: (148)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
9
我是用Mou先写的,先用markdown,之后可以转html和pdf,写博客比较方便
2014-8-26 10:11
0
雪    币: 76
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
poison 在windows中ndk+CYG环境,报错 jni/ptrace_utils.c:12:28: fatal error: cutils/sockets.h: No such file or directory
在Linux的Android内核里面编译成功。
2014-8-27 23:14
0
雪    币: 49
活跃值: (40)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
mark
2014-8-28 15:17
0
雪    币: 30
活跃值: (37)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
好文~~
2014-9-1 10:18
0
雪    币: 6
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
XUEXI
2014-9-1 16:41
0
雪    币: 29
活跃值: (499)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
14
顶!梁哥内功太深了!
2014-9-7 13:16
0
雪    币: 76
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
liang兄:想深入了解下面这段内容有什么学习资料介绍不?
譬如  apk免杀要看哪部分的东西?

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);
2014-10-25 20:07
0
雪    币: 34
活跃值: (45)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
16
楼主,我把4.0框架下的include和lib放到我本地JNI下编译,用你的git上的项目,错误提示:
/root/android/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: ./obj/local/armeabi/objs/proxybinder/proxyBinder/proxybinder.o: in function Main():jni/proxyBinder/proxybinder.cpp:68: error: undefined reference to 'android::defaultServiceManager()'
/root/android/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: ./obj/local/armeabi/objs/proxybinder/proxyBinder/proxybinder.o: in function Main():jni/proxyBinder/proxybinder.cpp:74: error: undefined reference to 'android::String16::String16(char const*)'
/root/android/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: ./obj/local/armeabi/objs/proxybinder/proxyBinder/proxybinder.o: in function Main():./jni/include/utils/StrongPointer.h:149: error: undefined reference to 'android::RefBase::decStrong(void const*) const'
/root/android/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: ./obj/local/armeabi/objs/proxybinder/proxyBinder/proxybinder.o: in function Main():jni/proxyBinder/proxybinder.cpp:74: error: undefined reference to 'android::String16::~String16()'
/root/android/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: ./obj/local/armeabi/objs/proxybinder/proxyBinder/proxybinder.o: in function Main():./jni/include/utils/StrongPointer.h:149: error: undefined reference to 'android::RefBase::decStrong(void const*) const'
/root/android/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: ./obj/local/armeabi/objs/proxybinder/proxyBinder/proxybinder.o: in function Main():jni/proxyBinder/proxybinder.cpp:79: error: undefined reference to 'android::AndroidRuntime::mJavaVM'
请教一下,这个错误要怎么解决。
2014-10-27 12:08
0
雪    币: 34
活跃值: (45)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
17
问题解决了,现在已经成功的通过java拦截了ActivityManagerServcie和PackageManagerServcie。
不过有个疑问,proxybinder.cpp里面用到的DummyJavaBBinder对象,适用在Android的任何固件版本吗?
2014-10-28 23:44
0
雪    币: 233
活跃值: (148)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
18
只要前几个字段的结构不变,就可以了
2014-10-29 09:20
0
游客
登录 | 注册 方可回帖
返回
//