1. 程式人生 > >Android Hook簡介

Android Hook簡介

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();
    }
}