Android Hook簡介
阿新 • • 發佈:2019-02-13
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();
}
}