本文大部份內容來自於《android進階解密》這本書,不一樣的是書中實現的是android9.0以前的hook,在android9.0中,activity的啓動過程會有些不一樣,所以本文主要是講解9.0的hook.android
在android9.0中,採用handler機制啓動activity時,消息標識變爲了EXECUTE_TRANSACTION
,和以前的LAUNCH_ACTIVITY
不一樣,而且msg
攜帶的內容也不一樣,從這裏能夠看到ClientTransaction transaction=msg.obj
和以前msg攜帶的ActivityRecord
參數不一樣,transaction
裏邊並無Intent
這個類型的變量
那麼咱們能像書上同樣在此hook嗎?
答案是能夠的,爲何沒有intent也能hook呢?看下邊分析 bash
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()
方法中app
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
.ide
AMS動態代理類,IActivityManagerProxy
ui
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
;this
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
spa
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就成功了code
其實hookActivity主要就是繞過AMS的驗證,所以在調用AMS的startActivity方法以前,均可以進行intent的替換,在AMS事後均可以進行intent的還原,所以有不少種hook方法,好比hook,Instrumatention進行intent的替換,對於intent的還原,目前我只想到在handlerMeassage中進行還原,由於ActivityThread中有一個靜態變量sCurrentActivityThread,能夠獲取activitythread對象,從而能夠改變mH這個變量,或許還有更好的hook點。cdn