作者:Oz
版权声明:本文图文为博主原创,转载请注明出处。
概述 对于插件化框架 Hook
机制是一个核心,那到底 Hook
是什么呢?怎么去理解插件化中的 Hook
呢?在我看来插件化中的 Hook
机制就是通过反射注入
和动态代理
来实现的。
先来说说何为反射注入
,大家都知道依赖注入,其实反射注入算是依赖注入的一种,顾名思义,通过反射的方式将依赖对象注入目标对象。举个例子,想要替换掉 ActivityThread
中的 mInstrumentation
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public final class ActivityThread { Instrumentation mInstrumentation; public static ActivityThread currentActivityThread () { return sCurrentActivityThread; } ... } public class InstrumentationDelegate extends Instrumentation { private Instrumentation base; public InstrumentationDelegate (Instrumentation base) { this .base = base; } } public class ReflectInject { public void reflectInject () throws Exception { Class<?> activityThreadClass = Class.forName("android.app.ActivityThread" ); Method currentActivityThreadMethod = activityThreadClass.getMethod("currentActivityThread" ); currentActivityThreadMethod.setAccessible(true ); Object currentActivityThreadObject = currentActivityThreadMethod.invoke(null ); Field instrumentationField = activityThreadClass.getDeclaredField("mInstrumentation" ); instrumentationField.setAccessible(true ); Object instrumentationObject = instrumentationField.get(currentActivityThreadObject); if (!(instrumentationObject instanceof InstrumentationDelegate)) { instrumentationField.set(activityThreadClass, new InstrumentationDelegate ((Instrumentation)instrumentationObject)); } } }
以上就是对于 mInstrumentation
的反射注入,当然凭借封装可以有更优雅的实现,这里为了方便展示过程粗暴直接。
关于动态代理
大家可以参考彻底理解 Java 动态代理 这篇文章,写得十分清晰。文章最后也提到了动态代理的局限性,动态代理无法支持对于非接口的类进行代理,所以在 Hook
时一般结合静态代理来特殊处理需要代理的类,比较典型的例子是 android.app.Instrumentation
的代理。好在 Android 系统服务大都通过 Binder
机制来实现的,而 Binder
机制的 C/S 架构对于接口的支持天然的好,这对于整个 Hook
框架中代理类实现的工作量来说就大大的减少了。
Hook 框架 我们知道 Hook 本身依赖反射机制,从上面示例上也可以看出,直接使用大量反射导致代码可读性、维护性变得非常差,从代码美观可读性、易维护性上来看,一个可读性强易维护的 Hook 框架显得尤为重要,目前众多开源的插件化框架中 VirtualApp 的 Hook 框架是最优秀的。为什么这么说呢,作者使用了基于注解的反射注入技术,合理的框架设计使得虽然 Hook 的对象非常多,代码却井井有条,不得不赞叹作者 lody 的巧妙构思,让人受益良多。
以下分析基于 master 分支 c493161 版本。
设计类图 又到了祭出法宝的时候了,废话不多说先看设计类图:
点击放大查看高清无码大图
类图解析 首先作者设计了两个接口,一个是 Injectable
,这个接口比较简单,使实现这个接口的类都具备的注入的能力;
1 2 3 4 5 6 7 public interface Injectable { void inject () throws Throwable; boolean isEnvBad () ; }
另一个是 IHookObject
,使实现这个接口的类具备管理代理类的 Hook 函数
能力。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public interface IHookObject { void copyHooks (IHookObject from) ; Map<String, Hook> getAllHooks () ; Hook addHook (Hook hook) ; Hook removeHook (String hookName) ; void removeHook (Hook hook) ; void removeAllHook () ; <H extends Hook > H getHook (String name) ; Object getProxyInterface () ; Object getBaseInterface () ; int getHookCount () ; }
上面我们提到了 Hook 函数
这个概念,怎么理解这个概念呢,因为动态代理的调用是函数级别的,所以 Hook 相当于替换函数实现。再来看 Hook
这个抽象类,这个类定义了 Hook 的处理时机,以及提供一些 Hook 环境的依赖,实现类通过指定代理函数名,可以根据需要在 beforeCall
、call
、 afterCall
执行逻辑处理。所以, Hook
的实现类可以理解为代理函数的类象化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public abstract class Hook { private boolean enable = true ; public abstract String getName () ; public boolean beforeCall (Object who, Method method, Object... args) { return true ; } public Object call (Object who, Method method, Object... args) throws Throwable { return method.invoke(who, args); } public Object afterCall (Object who, Method method, Object[] args, Object result) throws Throwable { return result; } public boolean isEnable () { return enable; } public void setEnable (boolean enable) { this .enable = enable; } ... @Override public String toString () { return "Hook${ " + getName() + " }" ; } }
来看看抽象类 HookDelegate
,它是 IHookObject
的接口实现,在构造中通过 HookHandler
完成了动态代理,内部维护了 Hook
集合,代码如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 public abstract class HookDelegate <T> implements IHookObject { private static final String TAG = HookDelegate.class.getSimpleName(); private T mBaseInterface; private T mProxyInterface; private Map<String, Hook> internalHookMapping = new HashMap <String, Hook>(); @Override public Map<String, Hook> getAllHooks () { return internalHookMapping; } public HookDelegate (Class<?>... proxyInterfaces) { mBaseInterface = createInterface(); if (mBaseInterface != null ) { if (proxyInterfaces == null ) { proxyInterfaces = HookUtils.getAllInterface(mBaseInterface.getClass()); } mProxyInterface = (T) Proxy.newProxyInstance(mBaseInterface.getClass().getClassLoader(), proxyInterfaces, new HookHandler ()); } else { VLog.d(TAG, "Unable to build HookDelegate: %s." , getClass().getName()); } } public HookDelegate () { this ((Class[]) null ); } protected abstract T createInterface () ; @Override public void copyHooks (IHookObject from) { this .internalHookMapping.putAll(from.getAllHooks()); } @Override public Hook addHook (Hook hook) { if (hook != null && !TextUtils.isEmpty(hook.getName())) { if (internalHookMapping.containsKey(hook.getName())) { VLog.w(TAG, "Hook(%s) from class(%s) have been added, can't add again." , hook.getName(), hook.getClass().getName()); return hook; } internalHookMapping.put(hook.getName(), hook); } return hook; } ... @Override public T getProxyInterface () { return mProxyInterface; } @Override public T getBaseInterface () { return mBaseInterface; } ... private class HookHandler implements InvocationHandler { @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { Hook hook = getHook(method.getName()); try { if (hook != null && hook.isEnable()) { if (hook.beforeCall(mBaseInterface, method, args)) { Object res = hook.call(mBaseInterface, method, args); res = hook.afterCall(mBaseInterface, method, args, res); return res; } } return method.invoke(mBaseInterface, args); } catch (InvocationTargetException e) { Throwable cause = e.getTargetException(); if (cause != null ) { throw cause; } throw e; } } } }
对于 HookBinderDelegate
这个类,继承自 HookDelegate
扩展了 IBinder
接口,借此方便处理系统 Binder
服务的代理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 public abstract class HookBinderDelegate extends HookDelegate <IInterface> implements IBinder { private IBinder mBaseBinder; public HookBinderDelegate (Class<?>... proxyInterfaces) { super (proxyInterfaces); init(); } public HookBinderDelegate () { super (); init(); } private void init () { mBaseBinder = getBaseInterface() != null ? getBaseInterface().asBinder() : null ; addHook(new AsBinder ()); } public void replaceService (String name) { if (mBaseBinder != null ) { ServiceManager.sCache.get().put(name, this ); } } private final class AsBinder extends Hook { @Override public String getName () { return "asBinder" ; } @Override public Object call (Object who, Method method, Object... args) throws Throwable { return HookBinderDelegate.this ; } } ... public Context getContext () { return VirtualCore.get().getContext(); } ... @Override public IInterface queryLocalInterface (String descriptor) { return getProxyInterface(); } ... public IBinder getBaseBinder () { return mBaseBinder; } }
接在在来看 PatchDelegate
这个抽象类,它是 Injectable
的接口实现,依赖 @Patch
及 @ApiLimit
注解将 Hook
类的添加进 Hook
集合;它的泛型为 IHookObject
,这就意味着 HookDelegate
HookBinderDelegate
的实现类很容易通过泛型约束,并通过 inject
接口完成注入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 public abstract class PatchDelegate <T extends IHookObject > implements Injectable { protected T hookDelegate; protected Object baseObject; public PatchDelegate () { this (null ); } public PatchDelegate (Object baseObject) { attachInterface(baseObject); } protected void attachInterface (Object baseObject) { this .baseObject = baseObject; this .hookDelegate = createHookDelegate(); onBindHooks(); afterHookApply(hookDelegate); } protected abstract T createHookDelegate () ; protected void onBindHooks () { if (hookDelegate == null ) { return ; } Class<? extends PatchDelegate > clazz = getClass(); Patch patch = clazz.getAnnotation(Patch.class); int version = Build.VERSION.SDK_INT; if (patch != null ) { Class<?>[] hookTypes = patch.value(); for (Class<?> hookType : hookTypes) { ApiLimit apiLimit = hookType.getAnnotation(ApiLimit.class); boolean needToAddHook = true ; if (apiLimit != null ) { int apiStart = apiLimit.start(); int apiEnd = apiLimit.end(); boolean highThanStart = apiStart == -1 || version > apiStart; boolean lowThanEnd = apiEnd == -1 || version < apiEnd; if (!highThanStart || !lowThanEnd) { needToAddHook = false ; } } if (needToAddHook) { addHook(hookType); } } } } private void addHook (Class<?> hookType) { try { Constructor<?> constructor = hookType.getDeclaredConstructors()[0 ]; if (!constructor.isAccessible()) { constructor.setAccessible(true ); } Hook hook; if (constructor.getParameterTypes().length == 0 ) { hook = (Hook) constructor.newInstance(); } else { hook = (Hook) constructor.newInstance(this ); } hookDelegate.addHook(hook); } catch (Throwable e) { throw new RuntimeException ("Unable to instance Hook : " + hookType + " : " + e.getMessage()); } } public Hook addHook (Hook hook) { return hookDelegate.addHook(hook); } protected void afterHookApply (T delegate) { } @Override public abstract void inject () throws Throwable; public Context getContext () { return VirtualCore.get().getContext(); } public T getHookDelegate () { return hookDelegate; } }
最后再来说说 PatchManager
,这个类顾名思义就知道是补丁的管理类,在这里将各个 Patch
完成注入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 public final class PatchManager { private static final String TAG = PatchManager.class.getSimpleName(); private Map<Class<?>, Injectable> injectTable = new HashMap <>(12 ); private PatchManager () { } public static PatchManager getInstance () { return PatchManagerHolder.sPatchManager; } void injectAll () throws Throwable { for (Injectable injectable : injectTable.values()) { injectable.inject(); } addPatch(AppInstrumentation.getDefault()); } public boolean isInit () { return PatchManagerHolder.sInit; } public void init () throws Throwable { if (PatchManagerHolder.sInit) { throw new IllegalStateException ("PatchManager Has been initialized." ); } injectInternal(); PatchManagerHolder.sInit = true ; } private void injectInternal () throws Throwable { if (VirtualCore.get().isMainProcess()) { return ; } if (VirtualCore.get().isServerProcess()) { addPatch(new ActivityManagerPatch ()); addPatch(new PackageManagerPatch ()); return ; } if (VirtualCore.get().isVAppProcess()) { addPatch(new LibCorePatch ()); addPatch(new ActivityManagerPatch ()); addPatch(new PackageManagerPatch ()); addPatch(HCallbackHook.getDefault()); ... } } private void addPatch (Injectable injectable) { injectTable.put(injectable.getClass(), injectable); } public <T extends Injectable > T findPatch (Class<T> clazz) { return (T) injectTable.get(clazz); } public <T extends Injectable > void checkEnv (Class<T> clazz) { Injectable injectable = findPatch(clazz); if (injectable != null && injectable.isEnvBad()) { try { injectable.inject(); } catch (Throwable e) { e.printStackTrace(); } } } public <T extends Injectable , H extends IHookObject > H getHookObject (Class<T> patchClass) { T patch = findPatch(patchClass); if (patch != null && patch instanceof PatchDelegate) { return (H) ((PatchDelegate) patch).getHookDelegate(); } return null ; } private static final class PatchManagerHolder { private static PatchManager sPatchManager = new PatchManager (); private static boolean sInit; } }
过程梳理 如果感觉以上内容不好理解的话,下面的这幅图,可能会缓解这种不适感。
以 AccountManagerService
Hook 为例,①、② 两步将 AccountBinderDelegate
等 Binder 代理注入至 ServiceManager
,假设触发 ③ getService 获取 AccountManagerService
后,调用 ④ getPwd ,这时 ⑤ getPwd 将通过 HookHandler
动态代理调用到代理类 ⑥ getHook 查找到函数代理对象,然后 ⑦ invoke 完成 Hook 函数
即 getPassword 代理调用。
到这里,整个 Hook 框架大致上就说完了。当然诸多版本的 Rom(官方、第三方)适配还是一个庞大的工作量,这就体现了作者对整个 Android Framework 掌握的功力了,这里额外提一下,作者对于Framework 镜像的处理,也是相当的精妙,这也为整个 Hook 框架的代码可读性贡献了相当一部分的力量,详见项目的 mirror
包 。
最后的闲扯 在阅读源码以及优秀开源项目的时候,大多数人都会感到很难读的通,我的一个看法和切身体会是,就像你第一眼看到一个人,肯定感觉十分陌生,而相处过一段时间后,这种陌生感就会慢慢消失,进而你反而会很了解她,知道她的爱好,知道她喜欢吃什么。阅读源码也是这样,短时间内如果无法拿下,又很想理解它,那么就要多花些时间,去读,不断的读和理解,了解源码所涉及的知识,尝试去用自己的理解去揣摩作者的思路,这个期间你需要用适合自己学习的方式(比如画类图,流程图、时序图,只要这种方式对你是有效的不必拘泥于形式)去记录修正你的理解,不断的去逼近作者的想法和思路,这也是一个学习成长的过程。
道阻且长,行则将至。that’s all.