本文大部分内容来自于《android进阶解密》这本书,不同的是书中实现的是android9.0之前的hook,在android9.0中,activity的启动过程会有些不同,因此本文主要是讲解9.0的hook.
在android9.0中,采用handler机制启动activity时,消息标识变为了EXECUTE_TRANSACTION,和之前的LAUNCH_ACTIVITY不同,并且msg携带的内容也不同,从这里可以看到ClientTransaction transaction=msg.obj和之前msg携带的ActivityRecord参数不同,transaction里边并没有Intent这个类型的变量那么我们能像书上一样在此hook吗? 答案是可以的,为什么没有intent也能hook呢?看下边分析
我们沿着调用链一直深入,mTransactionExecutor.execute(transaction)
接着调用executeCallbacks(transaction)方法
在executeCallback方法中,调用item.execute方法,这个item为
final List<ClientTransactionItem> callbacks = transaction.getCallbacks(); ··· final ClientTransactionItem item = callbacks.get(i);那么这个item的类型为ClientTransactionItem,这是个抽象类,必须找到它的一个实现类,还记得这个callback吗?在activity的启动流程中,在ActivityStackSupeisor中的realStartActivityLocked()方法中
clienttransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent).说明上面提到的item为launchActivityItem,同时这个LaunActiviyItem也确实为ClientTransactionItem的一个子类,并且LaunchActivityItem中也存在着Intent这个变量,那么我们的hook点也找到了
transaction中存在变量private List<ClientTransactionItem> mActivityCallbacks;,mActivityCallbacks中的元素为LaunchActivityItem,在LaunchActivityItem中存在变量private int mIdent;因此我们还是在ActivityThread.handleMessage时进行hook,不过要调用两次反射才能找到intent.
AMS动态代理类,IActivityManagerProxy
public class IActivityManagerProxy implements InvocationHandler { private Object activityManager; private static final String TAG="IActivityManagerProxy"; public IActivityManagerProxy(Object activityManager){ this.activityManager=activityManager; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(method.getName().equals("startActivity")){ Intent intent =null; int index=0; for(int i=0;i<args.length;i++){ if(args[i] instanceof Intent){ index=i; break; } } intent = (Intent) args[index]; String packageName = "com.suny.hooktest"; Intent subIntent = new Intent(); //替换activity为已经注册的占坑activity subIntent.setClassName(packageName,packageName+".SubActivity"); //同时将真正的intent保存在subintent中,绕过AMS的检查后,将真正的intent替换回来 subIntent.putExtra("target_intent",intent); args[index]=subIntent; Log.d(TAG, "invoke: subIntent="+subIntent+"inteent="+intent); } return method.invoke(activityManager,args); } }HookerHelp类,主要是替换启动过程中的'IActivityManager'为上边我们自己的代理类,和为ActivityThread中的mH(Handler)添加callbacks;
public class HookHelper { private static final String TAG="HookHelper"; public static void hookAms() throws Exception { Class clazz = ActivityManager.class; Field singletonIAMS = clazz.getDeclaredField("IActivityManagerSingleton"); singletonIAMS.setAccessible(true); Object defultSingleton = singletonIAMS.get(null); Class singletonClazz = Class.forName("android.util.Singleton"); Field mInstance = singletonClazz.getDeclaredField("mInstance"); mInstance.setAccessible(true); Object iAMs = mInstance.get(defultSingleton); Class iAmClazz =Class.forName("android.app.IActivityManager"); Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),new Class[]{iAmClazz},new IActivityManagerProxy(iAMs)); mInstance.set(defultSingleton,proxy); } public static void hookHandler() throws Exception{ Class acThreadClazz = Class.forName("android.app.ActivityThread"); Field currentActivityThread = acThreadClazz.getDeclaredField("sCurrentActivityThread"); currentActivityThread.setAccessible(true); Object currThread = currentActivityThread.get(null); Field mHField = acThreadClazz.getDeclaredField("mH"); mHField.setAccessible(true); Handler mH = (Handler) mHField.get(currThread); Field mCallback = Handler.class.getDeclaredField("mCallback"); mCallback.setAccessible(true); //为mH,添加mCallback,那么mH在handleMessage时,就会走我们自己定义的callback中的handleMessage方法 mCallback.set(mH,new HCallback(mH)); } }HCallbacks类,主要是还原intent
public class HCallback implements Handler.Callback{ private final String TAG="HCallback"; private Handler mHandler; public HCallback(Handler handler){ mHandler=handler; } @Override public boolean handleMessage(Message msg) { //这里为159,是因为EXECUTE_TRANSACTION字段的值为159 if(msg.what==159){ //r实际为clienttransaction Object r= msg.obj; try { Class clientClazz = r.getClass(); Field fCallbacks = clientClazz.getDeclaredField("mActivityCallbacks"); fCallbacks.setAccessible(true); //得到transactionz中的callbacks,为一个list,其中元素为LaunActivityItem List<?> lists = (List) fCallbacks.get(r); for(int i=0;i<lists.size();i++){ Object item = lists.get(i); Class itemClazz = item.getClass(); //拿到LaunActivityItem中的intent,进行替换 Field mIntent = itemClazz.getDeclaredField("mIntent"); mIntent.setAccessible(true); Intent intent = (Intent) mIntent.get(item); Intent target = intent.getParcelableExtra("target_intent"); if(target!=null){ intent.setComponent(target.getComponent()); } } } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } mHandler.handleMessage(msg); return true; } }定义一个自己的Application在attachBaseContext中初始化.
public class MyApplication extends Application { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); try { HookHelper.hookAms(); HookHelper.hookHandler(); } catch (Exception e) { e.printStackTrace(); } } }hook就成功了
其实hookActivity主要就是绕过AMS的验证,因此在调用AMS的startActivity方法之前,都可以进行intent的替换,在AMS过后都可以进行intent的还原,因此有很多种hook方法,比如hook,Instrumatention进行intent的替换,对于intent的还原,目前我只想到在handlerMeassage中进行还原,因为ActivityThread中有一个静态变量sCurrentActivityThread,可以获取activitythread对象,从而可以改变mH这个变量,或许还有更好的hook点。
今年年初我花一个月的时间收录整理了一套知识体系,如果有想法深入的系统化的去学习的,可以私信我【安卓】,我会把我收录整理的资料都送给大家,帮助大家更快的进阶。