Hook簡(jiǎn)介
Android中的系統(tǒng)調(diào)用是無(wú)法直接修改的,如啟動(dòng)PlugActivity時(shí),動(dòng)態(tài)地將它改為啟動(dòng)LocalActivity。這就要用到Hook技術(shù)。
Hook技術(shù)是指當(dāng)A和B交互時(shí),可以通過(guò)劫持A或的B的對(duì)象或方法,通過(guò)代理的方式對(duì)它進(jìn)行功能的擴(kuò)展或刪除等操作,最后再完成交互,
被Hook的對(duì)象或方法稱為Hook點(diǎn),為了保證Hook點(diǎn)穩(wěn)定性,Hook點(diǎn)一般選擇容易找到且不易變化的對(duì)象,靜態(tài)變量和單例是一般常用的Hook點(diǎn)。
Hook實(shí)現(xiàn)示例
如Activity啟動(dòng)另一個(gè)Activity時(shí)會(huì)在Activity里調(diào)用到mInstrumentation.execStartActivity()。這個(gè)mInstrumentation是一個(gè)單例對(duì)象,那么它可以很好地作為一個(gè)hook點(diǎn)。
找好了Hook點(diǎn),然后把mInstrumentation替換為代理對(duì)象。然后啟動(dòng)時(shí)就是執(zhí)行的代理對(duì)象的execStartActivity(),那么就可以在自定義的代理類中先進(jìn)行擴(kuò)展功能或修改的操作,這里就是將要啟動(dòng)的LocalActivity替換為PlugActivity。修改完后再執(zhí)行最初的mInstrumentation.execStartActivity()。
那么就看具體實(shí)現(xiàn)的代碼,第一步先定義一個(gè)代理類:
public class InstrumentationProxy extends Instrumentation {
Instrumentation instrumentation;
private Method method;
//持有真正啟動(dòng)Activity的Instrumentation引用
public InstrumentationProxy(Instrumentation instrumentation) {
this.instrumentation = instrumentation;
}
//重寫(xiě)啟動(dòng)Activity的execStartActivity()
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
//將要啟動(dòng)的PlugActivity修改為L(zhǎng)ocalActivity
intent.setClassName(who,"com.madnessxiong.client.LocalActivity");
//通過(guò)反射獲取Instrumentation的class對(duì)象
Class<? extends Instrumentation> aClass = Instrumentation.class;
try{
//通過(guò)class對(duì)象獲取真正啟動(dòng)Activity的execStartActivities()
method = aClass.getMethod("execStartActivities");
//通過(guò)反射的方式執(zhí)行真正啟動(dòng)Activity的execStartActivities()
ActivityResult invoke = (ActivityResult) method.invoke(instrumentation, who, contextThread, token, target, intent, options);
return invoke;
}catch (Exception e){
}
return null;
}
}
因?yàn)樽罱K要執(zhí)行原方法,所以代理類必須持有原對(duì)象的引用,這里通過(guò)構(gòu)造將原對(duì)象instrumentation傳入。
重寫(xiě)要代理的execStartActivity(),然后修改intent,將要啟動(dòng)的Activity替換為L(zhǎng)ocalActivity。最后通過(guò)反射的方式執(zhí)行真正啟動(dòng)Activity的execStartActivity()。
代理類以及設(shè)置完成,然后就是用代理對(duì)象,替換掉原對(duì)象:
public void replace(Activity activity){
//通過(guò)反射獲取Activity的class對(duì)象
Class<? extends Activity> aClass = activity.getClass();
try {
//獲取Activity的mInstrumentation屬性
Field field= aClass.getDeclaredField("mInstrumentation");
//取消權(quán)限檢查
field.setAccessible(true);
//獲取傳入的activity的mInstrumentation字段
mInstrumentation = (Instrumentation)field.get(activity);
//構(gòu)造InstrumentationProxy,并將獲取到的Activity字段傳入
InstrumentationProxy instrumentationProxy = new InstrumentationProxy(mInstrumentation);
//用構(gòu)造InstrumentationProxy替換掉當(dāng)前Activity的mInstrumentation。
field.set(activity,instrumentationProxy);
}catch (Exception e){
}
}
Hook Activity總結(jié):
由于Activity的啟動(dòng)執(zhí)行了mInstrumentation.execStartActivity(),且它是一個(gè)單例對(duì)象,所以以mInstrumentation為Hook點(diǎn)
定義一個(gè)代理類,代理類持有Instrumentation引用。并重寫(xiě)execStartActivity()。在execStartActivity()中進(jìn)行修改工作。最后通過(guò)持有的Instrumentation引用,執(zhí)行原execStartActivity()。
定義一個(gè)replace(),通過(guò)反射的方式獲取Activity的mInstrumentation,將這個(gè)mInstrumentation傳入InstrumentationProxy中,同時(shí)用InstrumentationProxy對(duì)象替換Activity中的mInstrumentation。這時(shí)當(dāng)發(fā)起一個(gè)啟動(dòng)Activity的請(qǐng)求時(shí),執(zhí)行的就是InstrumentationProxy.execStartActivity()