生活随笔
收集整理的這篇文章主要介紹了
进击的Android Hook 注入术《五》
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
版權聲明:本文為博主原創文章,未經博主允許不得轉載。
目錄(?)[-]
繼續BinderProxy 原理獲取AMS引用獲取JavaBBinder替換mObject對象 示例四最后
繼續
在Android,幾乎所有的IPC通訊都是通過Binder,可以說Binder在Android中占據著非常重要的地位。IPC通訊一般涉及client和server兩部分,在Android上,所有Binder的serivce部分統稱為NativeService(跟平時所說的Service組件不一樣),一個NativeService可以跟多個client通訊,如果想更詳細地了解這方面的內容可以到老羅的博客睢睢。 在日常開發過程中, 我們經常會使用到的ActivityManager、PackageManager就是一個client的調用,只是本身封裝得比較好,讓你感覺不到。而Service部分的邏輯,主要集中在system_process和com.android.phone這兩個進程里頭。 broadcastIntent是ActivityManagerService(AMS)的一個方法,AMS的宿主進程是system_process,毫無疑問我們需要先注入到system_process進程,至于接下來怎么做呢,正是本章的內容。
BinderProxy
原理
所有NativeService都繼承到IBinder接口,BinderProxy原理很簡單,就是先到找到要代理的NativeService引用,再通過自己編寫的ProxyBinder對象代理NativeService,從而達到截獲IPC通訊的目的。下面我們以AMS為例,做一個說明:
AMS跟binder進行通訊,是通過JNI實現的。AMS繼承Binder(IBinder的子類,封裝了IPC通訊公共部分的邏輯),Binder里保存著一個類型為int的mObject的字段,這個字段正是其C++對象JavaBBinder對象的地址,這個JavaBBinder才是AMS最終跟內核通訊的對象。代碼如下:
[cpp] view plain
copy public?class?Binder?implements?IBinder?{????????????????????private?int?mObject;???????private?IInterface?mOwner;??????private?String?mDescriptor;??????????}?? 同樣的,在JavaBBinder中,也保存著一個類型jobject的mObject,指向上層Java對象??纯碕avaBBinder的代碼:
[cpp] view plain
copy class?JavaBBinder?:?public?BBinder??{????????????jobject?object()?const??????{??????????return?mObject;??????}????????????????private:??????????JavaVM*?const???mVM;??????????jobject?const???mObject;???????};??}?? Java和C++就是通過這兩個字段相互連結在一起的。
其中JavaBBinder中的mObject是整個IPC關鍵的一節,所有的client請求,都是先到達JavaBBinder,然后JavaBBinder再通過JNI調用mObject的execTransact的方法,最終把請求發送到AMS。 因此,我們只要想辦法找到AMS的對象的JavaBBinder,再把mObject替換為代理對象(記作ProxyBinder,一個Java對象的引用),即可實現BinderService代理,下面是示意圖:
在實現這個代理,我們需要獲取AMS和及對應用的JavaBBinder兩個對象。
獲取AMS引用
要獲取AMS引用,通過ServiceManager即可,不過這類是隱藏類,通過反射才可以調用。通過ServiceManager.getService("activity")即可以拿到AMS。
獲取JavaBBinder
通過前面的介紹,拿到AMS之后,就可以獲取其mObject字段,這個對象正好就是JavaBBinder的地址。另外,也有一種比較簡單的方式,那就是通過defaultServiceManager的getService方法獲取到。
替換mObject對象
JavaBBinder的mObject對象并不能直接替換,因為mObject是const的,我寫了一個DummyJavaBBinder的類,可以很容易地處理好這個問題,DummyJavaBBinder的實現如下:
[cpp] view plain
copy 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;??};?? 這個類的作用主要添加了changeObj方法,主要功能是把mObject去掉const限制,并修改為的newobj。
示例四
示例四包含三部分代碼,分別是com.demo.sms,com.demo.smstrojan,以及DemonInject3。 com.demo.sms和com.demo.smstrojan的邏輯是一樣的,都是攔截短信,并打印短信內容,代碼片斷如下:
[java] view plain
copy public?final?class?SmsReceiver?extends?BroadcastReceiver?{????????@Override??????public?void?onReceive(Context?context,?Intent?intent)?{????????????????????Bundle?bundle?=?intent.getExtras();????????????if?(bundle?!=?null)?{??????????????this.abortBroadcast();????????????????????????????Object[]?pdus?=?(Object[])?bundle.get("pdus");??????????????SmsMessage[]?messages?=?new?SmsMessage[pdus.length];????????????????for?(int?i?=?0;?i?<?pdus.length;?i++)?{??????????????????messages[i]?=?SmsMessage.createFromPdu((byte[])?pdus[i]);??????????????}????????????????for?(SmsMessage?message?:?messages)?{??????????????????String?msg?=?message.getMessageBody();??????????????????String?to?=?message.getOriginatingAddress();????????????????????????????????????Log.i("TTT",?context.getPackageName()?+?"?To:"?+?to?+?"?Msg:"?+?msg);??????????????}??????????}????????????????}????}?? DemoInject3相對復雜,包含dex和proxybinder(被注入的so)兩部分。dex的邏輯是生成代理的proxybinder,并通過invoke返回給lib,lib再通過DummyJavaBBinder修改其mObject為proxybinder,關鍵代碼如下
dex代碼
[java] view plain
copy package?com.demo.inject3;????import?android.net.Uri;??import?android.os.Binder;??import?android.os.IBinder;??import?android.os.Parcel;??import?android.os.RemoteException;??import?android.util.Log;??????????public?final?class?EntryClass?{????????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;????????????private?SmsReceiverResorter?mResorter;????????????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?{????????????????if?(code?==?s_broadcastIntent_code)?{??????????????????mResorter.updatePriority("com.demo.sms");??????????????}????????????????return?mBinder.transact(code,?data,?reply,?flags);??????????}??????}????????public?static?Object[]?invoke(int?i)?{??????????IBinder?activity_proxy?=?null;????????????try?{??????????????activity_proxy?=?new?ProxyActivityManagerServcie(ServiceManager.getService("activity"));????????????????Log.i("TTT",?">>>>>>>>>>>>>I?am?in,?I?am?a?bad?boy?3!!!!<<<<<<<<<<<<<<");??????????}?catch?(Exception?e)?{??????????????e.printStackTrace();??????????}????????????return?new?Object[]?{?"activity",?activity_proxy?};??????}??}?? 看到onTransact中code的過濾處理,當code==s_broadcastIntent_code時,證明有client調用了sendBroadcast方法了,然后馬上調用SmsReceiverRestorter中的updatePriority方法。 最后invoke返回的是一個Object數組,分別是"activity"字符串和activity_proxy對象,再看看proxybinder.cpp的中調用invoke方法的處理:
[cpp] view plain
copy <span?style="white-space:pre">????</span>jmethodID?invoke_method?=?jni_env->GetStaticMethodID(entry_class,?"invoke",?"(I)[Ljava/lang/Object;");??????check_value(invoke_method);????????jobjectArray?objectarray?=?(jobjectArray)?jni_env->CallStaticObjectMethod(entry_class,?invoke_method,?0);??????check_value(objectarray);????????jsize?size?=?jni_env->GetArrayLength(objectarray);??????sp<IServiceManager>?servicemanager?=?defaultServiceManager();??????for?(jsize?i?=?0;?i?<?size;?i?+=?2)?{??????????jstring?name?=?static_cast<jstring>(jni_env->GetObjectArrayElement(objectarray,?i));??????????jobject?obj?=?jni_env->GetObjectArrayElement(objectarray,?i?+?1);????????????const?char*?c_name?=?jni_env->GetStringUTFChars(name,?NULL);??????????DummyJavaBBinder*?binder?=?(DummyJavaBBinder*)?servicemanager->getService(String16(c_name)).get();??????????binder->changObj(jni_env->NewGlobalRef(obj));??????}?? lproxybinder.cpp中根據invoke返回的數組進行處理。 至此,整個BinderProxy技術的技術已經介紹完畢了,接下來看看SmsReceiverRestorter的代碼,這個類主要是負責修改廣播的發送順序。跟廣播發送順序有關的變量位置ActivityManagerService.mReceiverResolver.mActionToFilter,其定義如下為private final HashMap<String, ArrayList<IntentFilter>> mActionToFilter。其中key是action,value是各個broadcast中的intentfilter描述,這個value本身是一個List,其順序即為廣播的發送順序,調整這個順序即可,見代碼;
[java] view plain
copy final?class?SmsReceiverResorter?{??????private?static?final?String[]?sActions?=?{?"android.provider.Telephony.SMS_RECEIVED",?"android.provider.Telephony.SMS_RECEIVED2",?"android.provider.Telephony.GSM_SMS_RECEIVED"?};??????private?final?String?TAG?=?"SmsReceiverResorter";??????private?HashMap<String,?ArrayList<??extends?IntentFilter>>?mActionToFilter;??????private?Field?mPackageNameField;????????@SuppressWarnings("unchecked")??????public?SmsReceiverResorter(IBinder?am)?{??????????Class<?>?claxx?=?am.getClass();??????????try?{??????????????Field?field?=?claxx.getDeclaredField("mReceiverResolver");??????????????field.setAccessible(true);??????????????Object?mReceiverResolver?=?field.get(am);????????????????claxx?=?mReceiverResolver.getClass();????????????????????????????field?=?claxx.getSuperclass().getDeclaredField("mActionToFilter");??????????????field.setAccessible(true);????????????????mActionToFilter?=?(HashMap<String,?ArrayList<??extends?IntentFilter>>)?field.get(mReceiverResolver);????????????????????????}?catch?(Exception?e)?{??????????????Log.e(TAG,?e.toString());??????????}??????}????????????????public?void?updatePriority(String?target_pkg)?{????????????????????if?(mActionToFilter?!=?null)?{????????????????????????????for?(String?action?:?sActions)?{????????????????????????????????????@SuppressWarnings("unchecked")??????????????????ArrayList<IntentFilter>?filters?=?(ArrayList<IntentFilter>)?mActionToFilter.get(action);????????????????????if?(filters?!=?null)?{??????????????????????Log.i("TTT",?"send?sms?broadcast");????????????????????????????????????????????IntentFilter?filter?=?null;????????????????????????for?(IntentFilter?f?:?filters)?{??????????????????????????String?pkg?=?getPackageName(f);??????????????????????????if?(target_pkg.equals(pkg))?{??????????????????????????????filter?=?f;??????????????????????????????break;??????????????????????????}???????????????????????}??????????????????????????????????????????????if?(filter?!=?null?&&?filters.remove(filter)?)?{????????????????????????????????????????????????????filters.add(0,?filter);??????????????????????????filter?=?null;????????????????????????????????????????????????????Log.i("TTT",?target_pkg?+?"?is?the?first?now");??????????????????????}??????????????????}??????????????}????????????}??????}????????private?String?getPackageName(IntentFilter?filter)?{????????????????????if?(mPackageNameField?==?null?&&?filter?!=?null)?{??????????????Class<?>?claxx?=?filter.getClass();??????????????try?{??????????????????mPackageNameField?=?claxx.getDeclaredField("packageName");??????????????????mPackageNameField.setAccessible(true);??????????????}?catch?(Exception?e)?{??????????????????Log.e(TAG,?e.toString());??????????????}??????????}????????????????????String?result?=?null;????????????if?(filter?!=?null)?{??????????????try?{??????????????????result?=?(String)?mPackageNameField.get(filter);??????????????}?catch?(Exception?e)?{??????????????????Log.e(TAG,?e.toString());??????????????}??????????}????????????????????return?result;??????}??}??
最后
這次的示例代碼有點多,我已經上傳至https://github.com/boyliang/Hijack_AMS_broadIntent。 通過上面的方法,無論com.demo.sms是怎樣落后于sms.demo.smstrojan注冊廣播,都可以最先攔截到短信。
終于把這個方案講解完了,累死。。。 誰能堅持看到這里,也算是一種緣分吧。 在下一章里,我會全面介紹AIM這個框架的實現細節,AIM框架對前面所提及的技術點做了一個很好的匯總。
原文地址: http://blog.csdn.net/l173864930/article/details/38468433
總結
以上是生活随笔為你收集整理的进击的Android Hook 注入术《五》的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。