Binder Proxy技術方案

來源:互聯網
上載者:User

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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.