文章目錄
- 1 Hook Activity的startActivity方法
- 2 Hook Context 的 startActivity 方法
- 3 Hook startActivity 總結
startActivity 方法的兩種形式:
-
startActivity 有兩種寫法, 最常見的是下面這種, 使用 Activity 自帶的 startActivity
方法:
//第一個是Activity的startActivity方法
Intent intent= new Intent(MainActivity.this ,,SecondActivity.class) ;
startActivity(intent);
- 還有一種寫法是使用Context的startActivity 方法,我們使用 getApplicationContext方法擷取Context 對象,如下所示:
第二個是Context的startActivity方法
Intent intent= new Intent(MainActivity.this ,,SecondActivity.class) ;
getApplicationContext() .startActivity(intent );
兩種寫法殊途同歸,它們都是在App 程序中通知AMS要啟動哪個Activity。Context 内部的 startActivity 方法,其實也是在調用 Instrumentation 的execStartActivity 方法,後面的流程,兩種方式就都是一樣的了 。
1 Hook Activity的startActivity方法
public class InstrumentationProxy extends Instrumentation {
private static final String TAG = "InstrumentationProxy";
Instrumentation mInstrumentation;
public InstrumentationProxy(Instrumentation instrumentation) {
mInstrumentation = instrumentation;
}
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
Log.d(TAG, "Hook 成功" + " who :" + who);
// 開始調用原始的方法, 調不調用随你,但是不調用的話, 所有的startActivity都失效了.
// 由于這個方法是隐藏的,是以需要使用反射調用;首先找到這個方法
Class[] pareTyples = {Context.class, IBinder.class, IBinder.class,
Activity.class, Intent.class, int.class, Bundle.class};
Object[] pareVaules = {who, contextThread, token, target,
intent, requestCode, options};
String methodName = "execStartActivity";
try {
Method execStartActivity = mInstrumentation.getClass().getDeclaredMethod(methodName, pareTyples);
execStartActivity.setAccessible(true);
return (ActivityResult) execStartActivity.invoke(mInstrumentation, pareVaules);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public class Hook51MainActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hook51_main);
Class clazz = Activity.class;
try {
Field field = clazz.getDeclaredField("mInstrumentation");
field.setAccessible(true);
Instrumentation mInstrumentation = (Instrumentation) field.get(this);
Instrumentation instrumentationProxy = new InstrumentationProxy(mInstrumentation);
field.set(this, instrumentationProxy);
} catch (Exception e) {
e.printStackTrace();
}
}
public void toHook51SecondActivity(View view) {
Intent intent = new Intent(Hook51MainActivity.this,Hook51SecondActivity.class);
startActivity(intent);
}
}
調用toHook51SecondActivity()方法後,輸出:
InstrumentationProxy: Hook 成功 who :[email protected]
2 Hook Context 的 startActivity 方法
public class Hook51MainActivity extends AppCompatActivity {
@Override
protected void attachBaseContext(Context context) {
super.attachBaseContext(context);
try {
// 在這裡進行Hook
String className = "android.app.ActivityThread";
String methodName = "currentActivityThread";
Class[] pareTyples = new Class[]{};
Object[] pareVaules = new Object[]{};
Class clazz = Class.forName(className);
Method method = clazz.getDeclaredMethod(methodName, pareTyples);
method.setAccessible(true);
Object currentActivityThread = method.invoke(null, pareVaules);// 先擷取到目前的ActivityThread對象
String filedName = "mInstrumentation";
Field field = clazz.getDeclaredField(filedName);
field.setAccessible(true);
Instrumentation mInstrumentation = (Instrumentation) field.get(currentActivityThread); // 拿到原始的 mInstrumentation字段
// 建立代理對象
Instrumentation instrumentationProxy = new InstrumentationProxy(mInstrumentation);
// 偷梁換柱
field.set(currentActivityThread, instrumentationProxy);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hook51_main);
}
public void toHook51SecondActivity(View view) {
Intent intent = new Intent(Hook51MainActivity.this,Hook51SecondActivity.class);
intent.addFlags(Intent . FLAG_ACTIVITY_NEW_TASK) ;
getApplicationContext (). startActivity (intent );
}
}
輸出:
InstrumentationProxy: Hook 成功 who :[email protected]
3 Hook startActivity 總結
Hook Context 的 startActivity 方法和 Hook Activity 的 startActivity 方法最大的差別就是替換的 Instrumentation 不同 , 前者是 ActivityThread 中的 Instrumentation ,後者是 Activity中的Instrumentation。另外有一點需要注意的是,在 MainActivity 的onCreate 方法中進行Instrumentation替換的,未必是最佳的替換時間點 ,是以在 Activity 的 attachBaseContext 方法中進行Instrumentation 替換,因為這個方法要先于 Activity 的 onCreate 方法被調用。講到這裡,我們知道了如何使用代理來 Hook startActivity 方法,簡單說就是找到 Hook 點,再用代理對象來替換 Hook 點 。