在学习Android插件化的过程当中有用到Hook相关技术,本篇文章对Hook相关技术作也给简单的介绍,并写两个小Demo,当你了解了Hook以后可能会对你之后的碰到问题时多了一个解题思路java
Hook单词的意思就是钩子,那咱们在何时用到这个钩子呢,如上图所示,在一个事件或者动做执行的过程当中,截获相关事件或者动做,加入本身的代码或者替换装本身的代理对象,这就叫Hookandroid
本文主要是采用java反射机制拿到要执行的对象或者方法就行修改或者替换app
**关注点:**在hook的时候咱们首先须要找到要Hook的对象,什么样的对象比较好Hook呢,那就是单例和静态变量,单例和静态变量在进程中不容易发生变化,相对容易被定位到,二普通象则比价容易发生变化(随时有可能被销毁),。咱们根据这个原则找到所谓的Hook点ide
以上就是我对Hook的理解,且是还挺简单的,但实践是检验真理的惟一标准,下面我会写两个小Demo工具
本例子Hook的是一个工具类学习
/** * 打印机工具类,提供黑白打印和彩色打印 */ public class PrintUtil { private static IPrint colorPrint = new ColorPrint(); //彩色打印机 private static IPrint blackWhitePrint = new BlackWhitePrint(); //黑白打印机 public static void colorPrint(String content){ colorPrint.print(content); } public static void blackWhitePrint(String content){ blackWhitePrint.print(content); } }
工具类如上插件
private void operate4(){ // HookHelper.hookPrint(); PrintUtil.blackWhitePrint("黑白内容"); PrintUtil.colorPrint("彩色内容"); }
正常结果如上 ,下面咱们对PrintUtil进行hook ,首先咱们先找Hook点,在PrintUtil中有两个静态变量,这就是咱们要找的Hook点 具体代码以下线程
/** * 对printUtil进行hook处理 */ public static void hookPrint(){ try { Class<?> printClass = Class.forName("com.example.shiyagang.myapplication.util.PrintUtil"); Field colorPrintField= printClass.getDeclaredField("colorPrint"); Field blackWhitePrintField = printClass.getDeclaredField("blackWhitePrint"); colorPrintField.setAccessible(true); blackWhitePrintField.setAccessible(true); colorPrintField.set(null,new BlackWhitePrint()); blackWhitePrintField.set(null,new ColorPrint()); }catch (Exception e){ e.printStackTrace(); } }
咱们经过反射对PrintUtil的两个静态变量进行替换代理
替换完执行结果以下日志
彩色打印机打出了黑白内容,咱们成功了,嘿嘿
这个例子咱们在context.startActivity的调用链,找到相关的hook点进行替换。咱们首先分下context.startActivity的流程,Context.startActivity其实走到了ContextImpl的startActivity
如上图所示最终调用了ActivityThread类的mInstrumentation成员的execStartActivity方法;注意到,ActivityThread 其实是主线程,而主线程一个进程只有一个,所以这里是一个良好的Hook点
经过以上步骤咱们就能进行相关hook了
/** * 对activityThread进行Hook * */ public static void attachContext() throws Exception{ // 先获取到当前的ActivityThread对象 Class<?> activityThreadClass = Class.forName("android.app.ActivityThread"); Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread"); currentActivityThreadMethod.setAccessible(true); Object currentActivityThread = currentActivityThreadMethod.invoke(null); // 拿到mInstrumentation 字段 Field mInstrumentationField = activityThreadClass.getDeclaredField("mInstrumentation"); mInstrumentationField.setAccessible(true); Instrumentation mInstrumentation = (Instrumentation) mInstrumentationField.get(currentActivityThread); // 建立代理对象 Instrumentation evilInstrumentation = new EvilInstrumentation(mInstrumentation); // 偷梁换柱 mInstrumentationField.set(currentActivityThread, evilInstrumentation); }
EvilInstrumentation的代理对象以下:
/** * Instrumentation 的静态代理类 */ public class EvilInstrumentation extends Instrumentation { private static final String TAG = EvilInstrumentation.class.getSimpleName(); // ActivityThread中原始的对象, 保存起来 Instrumentation mBase; public EvilInstrumentation(Instrumentation base) { mBase = base; } public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { Log.e(TAG, "咱们Hook了 Activity的启动流程"); try { Method execStartActivity = Instrumentation.class.getDeclaredMethod( "execStartActivity", Context.class, IBinder.class, IBinder.class, Activity.class, Intent.class, int.class, Bundle.class); execStartActivity.setAccessible(true); return (ActivityResult) execStartActivity.invoke(mBase, who, contextThread, token, target, intent, requestCode, options); } catch (Exception e) { throw new RuntimeException("出问题了,去适配吧"); } } }
下面咱们看下Activity的代码 ,咱们在attachBaseContext中进行Hook
private void operate3(){ Intent intent = new Intent(getApplicationContext(),SecondActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); getApplicationContext().startActivity(intent); } @Override protected void attachBaseContext(Context newBase) { super.attachBaseContext(newBase); try { // 在这里进行Hook HookHelper.attachContext(); } catch (Exception e) { e.printStackTrace(); } }
入上图所示咱们已经成功了,咱们在这只是打印了一个日志,固然你能够干任何事情
到此已经对Hook作了简单的介绍
今年年初我花一个月的时间收录整理了一套知识体系,若是有想法深刻的系统化的去学习的,能够点击传送门,我会把我收录整理的资料都送给你们,帮助你们更快的进阶。