Android Hook简介
程序员文章站
2022-07-13 16:18:03
...
Hook:Hook翻译过来是钩子的意思,无论是手机还是电脑运行的时候都依赖系统各种各样的api,当某些api不能满足我们的要求时,我们就得去需改某些api,使之满足我们的要求。这样api hook就自然而然的出现了。我们可以通过api hook,改变一个系统api的原有功能。基本的方法就是通过hook“接触”到需要修改的api函数入口点,改变它的地址指向新的自定义的函数。当然这种技术同样适用于android系统,在android开发中,我们同样能利用hook的原理让系统某些方法运行时调用的是我们定义的方法,从而满足我们的要求。
下面用java反射实现简单的hook:新建一个android项目时有有一个MainActivity,我们在创建一个TestActivity,不再清单文件中注册,利用hook技术,显示的我们写的TestActivity
流程:Activity启动时候一般都是通过startActivity方式启动的,并没有看到调用new Activity(),其实这都是在系统里完成的,在Instrumentation.java中两个重载的方法来创建Activity实例的
//frameworks/base/core/java/android/app/Instrumentation.java
public Activity newActivity(Class<?> clazz, Context context,
IBinder token, Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
Object lastNonConfigurationInstance) throws InstantiationException,
IllegalAccessException {
Activity activity = (Activity)clazz.newInstance();
ActivityThread aThread = null;
activity.attach(context, aThread, this, token, 0, application, intent,
info, title, parent, id,
(Activity.NonConfigurationInstances)lastNonConfigurationInstance,
new Configuration(), null, null, null);
return activity;
}
//frameworks/base/core/java/android/app/Instrumentation.java
public Activity newActivity(ClassLoader cl, String className,
Intent intent)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
return (Activity)cl.loadClass(className).newInstance();
}
当MainActivity在创建实力时,我们用TestActivity来替换掉,这样应用启动的就是我们用的TestActivity
1,写一个IntrumentationHook继承系统的Intrumentation,并重写父类的new Activity()
//重新Instrumentation的newActivity方法
public class InstrumentationHook extends Instrumentation {
@Override
public Activity newActivity(Class<?> clazz, Context context, IBinder token, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, Object lastNonConfigurationInstance) throws InstantiationException, IllegalAccessException {
return super.newActivity(clazz, context, token, application, intent, info, title, parent, id, lastNonConfigurationInstance);
}
@Override
public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
Activity activity = createActivity(intent);
if (activity != null) {
return activity;
}
return super.newActivity(cl, className, intent);
}
private Activity createActivity(Intent intent) {
//获取组件得类型,当组件类名是MainActivity时返回TestActivity
String component = intent.getComponent().getClassName();
if ("com.example.hooktest.MainActivity".equals(component)) {
try {
Class<? extends Activity> testActivity = (Class<? extends Activity>) Class.forName("com.example.hooktest.TestActivity");
return testActivity.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
}
2,获取当前应用的ActivityThread,并替换系统默认的mIntrumentation实例
public class HookManager {
private static Object activityThreadInstance;
public static void init() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<?> thread = Class.forName("android.app.ActivityThread");//获取ActivityThread.class对象
Method currentActivityThread = thread.getDeclaredMethod("currentActivityThread");//获取ActivityThread类中方法名为currentActivityThread的方法对象
activityThreadInstance = currentActivityThread.invoke(null);//调用方法对象的方法,获取当前应用的ActivityThread实例
}
public static void initmInstrumentation() throws NoSuchFieldException, IllegalAccessException {
Field mInstrumentation = activityThreadInstance.getClass().getDeclaredField("mInstrumentation");//获取ActivityThread实例中mIntrumentation属性对象
mInstrumentation.setAccessible(true);
InstrumentationHook instrumentationHook = new InstrumentationHook();
mInstrumentation.set(activityThreadInstance,instrumentationHook);//用自定义的instrumentionHook替换掉系统的instrumention对象
}
}
3,在MyApplication的onCreate里替换ActivityThread里的mIntrumentation
public class MyApplication extends Application {
@Override
public void onCreate() {
try {
HookManager.init();
HookManager.initmInstrumentation();
} catch (Exception e) {
e.printStackTrace();
}
super.onCreate();
}
}