本文大部分内容来自于《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 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
,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;ipublic 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
定义一个自己的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点。
今年年初我花一个月的时间收录整理了一套知识体系,如果有想法深入的系统化的去学习的,可以私信我【安卓】,我会把我收录整理的资料都送给大家,帮助大家更快的进阶。