Android hook技术之小试牛刀

一、了解Hook概念

Hook是钩子的意思。我们知道应用运行依赖系统各种各样的API。当某些API不能满足我们的要求时,如果想修改它的功能,使之能满足我们的要求。就要用到Hook技术。

在Android开发中,我们同样能利用Hook的原理让系统某些方法运行时,实际调用的是我们自己定义的方法,从而满足我们的要求。


二、利用java反射实现简单的Hook——将在Manifest中注册的MainActivity替换成没在Manifest中注册过的TestActivity。

2.1)新建一个Android项目,创建MainActivity和TestActivity,TestActivity不在AndroidManifest.xml中配置。

2.2)写一个InstrumentationHook继承系统的Instrumentation,并重写父类的newActivity方法


  1. public class InstrumentationHook extends Instrumentation {  
  2.   
  3.     @Override  
  4.     public Activity newActivity(Class<?> clazz, Context context, IBinder token,  
  5.                                 Application application, Intent intent, ActivityInfo info,  
  6.                                 CharSequence title, Activity parent, String id,  
  7.                                 Object lastNonConfigurationInstance) throws InstantiationException,  
  8.             IllegalAccessException {  
  9.         Log.d(this" CustomInstrumentation#newActivity call 1");  
  10.         return super.newActivity(clazz, context, token, application, intent, info,  
  11.                 title, parent, id, lastNonConfigurationInstance);  
  12.     }  
  13.   
  14.     @Override  
  15.     public Activity newActivity(ClassLoader cl, String className, Intent intent)  
  16.             throws InstantiationException, IllegalAccessException,  
  17.             ClassNotFoundException {  
  18.         Log.d(this" CustomInstrumentation#newActivity call 3 parmas className:" + className + " intent:" + intent.toString());  
  19.         Activity activity = createActivity(intent);  
  20.         if (activity != null) {  
  21.             return activity;  
  22.         }  
  23.         return super.newActivity(cl, className, intent);  
  24.     }  
  25.   
  26.     /*可以在createActivity拦截替换某个activity,下面自是一个简单例子*/  
  27.     protected Activity createActivity(Intent intent) {  
  28.         String className = intent.getComponent().getClassName();  
  29.         Log.d(this"createActivity className=" + className);  
  30.         if ("hook.jason.com.androidhook.MainActivity".equals(className)) {  
  31.             try {  
  32.                 Class<? extends Activity> PluginActivity = (Class<? extends Activity>) Class  
  33.                         .forName("hook.jason.com.androidhook.TestActivity");  
  34.                 return PluginActivity.newInstance();  
  35.             } catch (Exception e) {  
  36.                 e.printStackTrace();  
  37.             }  
  38.         }  
  39.         return null;  
  40.     }  
  41. }  


2.3)获取当前应用的ActivityThread,并替换系统默认定义的mInstrumentation实例


[java]
 view plain copy
  1. /** 
  2.  * Created by zeyu,Jia
  3.  */  
  4.   
  5. public class HookManager {  
  6.     static Object activityThreadInstance;  
  7.   
  8.     public static void init() throws ClassNotFoundException,  
  9.             NoSuchMethodException, IllegalAccessException,  
  10.             IllegalArgumentException, InvocationTargetException {  
  11.         Class<?> activityThread = Class.forName("android.app.ActivityThread");  
  12.         Method currentActivityThread = activityThread  
  13.                 .getDeclaredMethod("currentActivityThread");  
  14.         activityThreadInstance = currentActivityThread.invoke(null);  
  15.     }  
  16.   
  17.     public static void injectInstrumentation() throws NoSuchFieldException,  
  18.             IllegalAccessException, IllegalArgumentException {  
  19.         Log.i(HookManager.class" start injectInstrumentation");  
  20.         Field field_instrumentation = activityThreadInstance.getClass()  
  21.                 .getDeclaredField("mInstrumentation");  
  22.         field_instrumentation.setAccessible(true);  
  23.         InstrumentationHook instrumentationHook = new InstrumentationHook();  
  24.         field_instrumentation.set(activityThreadInstance, instrumentationHook);  
  25.     }  
  26. }  


2.4)在MyApplication的onCreate里替换ActivityThread里的mInstrumentation变量

  1. public class MyApplication extends Application {  
  2.     @Override  
  3.     public void onCreate() {  
  4.         try {  
  5.             Log.d(this" onCreate starting init");  
  6.             HookManager.init();  
  7.             HookManager.injectInstrumentation();  
  8.         } catch (Exception e) {  
  9.             Log.d(this" onCreate e:" + e.toString());  
  10.         }  
  11.         super.onCreate();  
  12.     }  
  13. }  


2.5)运行后界面如下:

Android hook技术之小试牛刀


2.6)具体log如下:

03-18 17:28:55.621 436-436/hook.jason.com.androidhook D/AndroidHook: MyApplication :  onCreate starting init
03-18 17:28:55.623 436-436/hook.jason.com.androidhook I/AndroidHook: Class :  start injectInstrumentation
03-18 17:28:55.633 436-436/hook.jason.com.androidhook D/AndroidHook: InstrumentationHook :  CustomInstrumentation#newActivity call 3 parmas className:hook.jason.com.androidhook.MainActivity intent:Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=hook.jason.com.androidhook/.MainActivity }
03-18 17:28:55.633 436-436/hook.jason.com.androidhook D/AndroidHook: InstrumentationHook : createActivity className=hook.jason.com.androidhook.MainActivity
03-18 17:28:55.674 436-436/hook.jason.com.androidhook D/AndroidHook: TestActivity : onCreate
03-18 17:28:55.752 436-436/hook.jason.com.androidhook D/AndroidHook: TestActivity : onResume
03-18 17:28:55.775 436-436/hook.jason.com.androidhook D/AndroidHook: TestActivity : onPause
03-18 17:28:55.789 436-436/hook.jason.com.androidhook D/AndroidHook: TestActivity : onAttachedToWindow
03-18 17:39:55.838 436-436/hook.jason.com.androidhook D/AndroidHook: TestActivity : onRestart
03-18 17:39:55.855 436-436/hook.jason.com.androidhook D/AndroidHook: TestActivity : onResume
03-18 17:40:26.044 436-436/hook.jason.com.androidhook D/AndroidHook: TestActivity : onPause

从log中可以看出MainActivity的onCreate方法根本没有运行,走的是没有配置的TestActivity类