对象 A 调用 对象 B 之前做一些处理,起到欺上瞒下的作用,Hook 就是一个钩子,也称 Hook 点,有了 Hook,可以在进程间进行行为更改。
Hook 点一般选择容易并且不易变化的对象,比如静态变量和单例。
- API 语言分类
- Hook Java:反射和代理
- Hook Native
- 进程分类
- 进程 Hook,应用程序进程,只能 Hook 当前的应用程序
- 全局 Hook,Hook Zygote
- 实现方式分类
- 反射和代理实现,只能 Hook 当前的应用程序进程
- Hook 框架,比如 Xposed,实现全局 Hook,需要 root
例子:Hook Activity startActivity
//startActivity 调用到 Activity.class 中下面的方法
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
//Hook 点
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
if (requestCode >= 0) {
mStartedActivity = true;
}
cancelInputsAndStartExitTransition(options);
} else {
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else {
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}
//定义代理类
public class InstrumentationProxy extends Instrumentation {
private Instrumentation mInstrumentation;
private static final String TAG = "InstrumentationProxy";
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);
try {
final Class<Instrumentation> clazz = Instrumentation.class;
final Method method = clazz.getDeclaredMethod("execStartActivity",
Context.class, IBinder.class, IBinder.class, Activity.class, Intent.class, int.class, Bundle.class);
return (ActivityResult) method.invoke(mInstrumentation,who,contextThread,token,target,intent,requestCode,options);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
replaceInstrumentation(this);
final Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://baidu.com"));
startActivity(intent);
}
//替换原来的 Instrumentation
private void replaceInstrumentation(Activity activity){
try {
//反射
final Field field = Activity.class.getDeclaredField("mInstrumentation");
field.setAccessible(true);
final Instrumentation instrumentation = (Instrumentation)field.get(activity);
final InstrumentationProxy proxy = new InstrumentationProxy(instrumentation);
field.set(activity,proxy);
} catch (Exception e) {
e.printStackTrace();
}
}
}
//代理成功了
//out:
//05-12 22:54:10.830 1713-1713/com.test.all D/InstrumentationProxy: 这里是Hook点 who:com.test.all.MainActivity@39b11d7