VirtualApp Java层Hook基础
来源:互联网 发布:java底层源代码 编辑:程序博客网 时间:2024/06/13 18:20
VirtualApp Java层Hook基础-反射注入
Hook技术是VirtualApp(后续简称VA)的核心实现原理之一。
0x00. 什么是Hook
Hook是Windows中提供的一种用以替换DOS下“中断”的系统机制,中文译为“挂钩”或“钩子”。在对特定的系统事件进行hook后,一旦发生已hook事件,对该事件进行hook的程序就会收到系统的通知,这时程序就能在第一时间对该事件做出响应。 – 来自百度百科
在Android插件化中的Hook机制一般是通过反射注入和动态代理来实现的。
0x01. Hook实现
Android中的Hook本身依赖反射机制,VA的Hook框架基于注解的反射注入技术实现的极为优雅,初看源码可能会不知所云,深入研究就会发现VA虽然模拟了整个AndroidFramework,Hook了大量对象,代码却依然井井有条。
基于VA,研究注解的反射注入技术,相关源码:
mirror/ - RefClass.java - RefConstructor.java - RefStaticMethod.java - RefStaticObject.java - RefStaticInt.java - RefMethod.java - RefObject.java - RefBoolean.java - RefDouble.java - RefFloat.java - RefInt.java - RefLong.java - MethodParams.java - MethodReflectParams.javamirror/android/app/ - ActivityThread.java// Android Frameworkframeworks/base/core/java/android/app/ - ActivityThread.java
ActivityThread的反射注入-普通实现
public class PluginInstrumentation extends Instrumentation { private final Instrumentation mBase; public PluginInstrumentation(Instrumentation base) { mBase = base; }}public class HookHelper { public static void inject() throws Exception { Class<?> activityThreadClass = Class.forName("android.app.ActivityThread"); Method currentActivityThreadMethod = activityThreadClass.getMethod("currentActivityThread"); currentActivityThreadMethod.setAccessible(true); Object currentActivityThread = currentActivityThreadMethod.invoke(null); Field instrumentationField = activityThreadClass.getDeclaredField("mInstrumentation"); instrumentationField.setAccessible(true); Instrumentation instrumentation = (Instrumentation) instrumentationField.get(currentActivityThread); // HookHelper: 反射注入前 instrumentation = android.app.Instrumentation@3520a6d Log.e("HookHelper", "反射注入前 instrumentation = " + instrumentationField.get(currentActivityThread)); if(!(instrumentation instanceof PluginInstrumentation)) { instrumentationField.set(currentActivityThread, new PluginInstrumentation(instrumentation)); } // HookHelper: 反射注入后 instrumentation = com.ximsfei.kotlin.hook.PluginInstrumentation@669d6a2 Log.e("HookHelper", "反射注入后 instrumentation = " + instrumentationField.get(currentActivityThread)); }}
ActivityThread的反射注入-VA实现
原理介绍
mirror/MethodParams.java
@Target({ElementType.FIELD})@Retention(RetentionPolicy.RUNTIME)public @interface MethodParams { Class<?>[] value();}
该注解MethodParams用于标注某个方法(包括构造方法)包含哪些参数。eg: @MethodParams({IBinder.class, List.class})
, 参数为Class
@Target({ElementType.FIELD})@Retention(RetentionPolicy.RUNTIME)public @interface MethodReflectParams { String[] value();}
该注解MethodReflectParams用于标注某个方法(包括构造方法)包含哪些参数。eg: @MethodReflectParams({"android.content.pm.PackageParser$Package", "int"})
, 参数为字符串对象(全类名),最终通过Class.forName(params);
获取对应的Class
public final class RefClass { private static HashMap<Class<?>,Constructor<?>> REF_TYPES = new HashMap<Class<?>, Constructor<?>>(); static { try { REF_TYPES.put(RefObject.class, RefObject.class.getConstructor(Class.class, Field.class)); REF_TYPES.put(RefMethod.class, RefMethod.class.getConstructor(Class.class, Field.class)); REF_TYPES.put(RefInt.class, RefInt.class.getConstructor(Class.class, Field.class)); REF_TYPES.put(RefLong.class, RefLong.class.getConstructor(Class.class, Field.class)); REF_TYPES.put(RefFloat.class, RefFloat.class.getConstructor(Class.class, Field.class)); REF_TYPES.put(RefDouble.class, RefDouble.class.getConstructor(Class.class, Field.class)); REF_TYPES.put(RefBoolean.class, RefBoolean.class.getConstructor(Class.class, Field.class)); REF_TYPES.put(RefStaticObject.class, RefStaticObject.class.getConstructor(Class.class, Field.class)); REF_TYPES.put(RefStaticInt.class, RefStaticInt.class.getConstructor(Class.class, Field.class)); REF_TYPES.put(RefStaticMethod.class, RefStaticMethod.class.getConstructor(Class.class, Field.class)); REF_TYPES.put(RefConstructor.class, RefConstructor.class.getConstructor(Class.class, Field.class)); } catch (Exception e) { e.printStackTrace(); } } public static Class<?> load(Class<?> mappingClass, String className) { try { return load(mappingClass, Class.forName(className)); } catch (Exception e) { return null; } } public static Class load(Class mappingClass, Class<?> realClass) { Field[] fields = mappingClass.getDeclaredFields(); for (Field field : fields) { try { if (Modifier.isStatic(field.getModifiers())) { Constructor<?> constructor = REF_TYPES.get(field.getType()); if (constructor != null) { field.set(null, constructor.newInstance(realClass, field)); } } } catch (Exception e) { // Ignore } } return realClass; }}
mirror/RefObject.java
Field类封装了Java反射中java.lang.reflect.Field的field.get()和field.set()方法;其他Field类类似。
public class RefObject<T> { private Field field; public RefObject(Class<?> cls, Field field) throws NoSuchFieldException { this.field = cls.getDeclaredField(field.getName()); this.field.setAccessible(true); } public T get(Object object) { try { return (T) this.field.get(object); } catch (Exception e) { return null; } } public void set(Object obj, T value) { try { this.field.set(obj, value); } catch (Exception e) { //Ignore } }}
mirror/RefMethod.java
方法类封装了Java反射中java.lang.reflect.Method的method.invoke()方法;在RefMethod构造方法中,会根据不同的注解MethodParams, MethodReflectParams获取对应的方法参数,从而获取对应的Method。如果没有注解,表明对应方法没有参数。
public class RefMethod<T> { private Method method; public RefMethod(Class<?> cls, Field field) throws NoSuchMethodException { if (field.isAnnotationPresent(MethodParams.class)) { Class<?>[] types = field.getAnnotation(MethodParams.class).value(); for (int i = 0; i < types.length; i++) { Class<?> clazz = types[i]; if (clazz.getClassLoader() == getClass().getClassLoader()) { try { Class.forName(clazz.getName()); Class<?> realClass = (Class<?>) clazz.getField("TYPE").get(null); types[i] = realClass; } catch (Throwable e) { throw new RuntimeException(e); } } } this.method = cls.getDeclaredMethod(field.getName(), types); this.method.setAccessible(true); } else if (field.isAnnotationPresent(MethodReflectParams.class)) { String[] typeNames = field.getAnnotation(MethodReflectParams.class).value(); Class<?>[] types = new Class<?>[typeNames.length]; for (int i = 0; i < typeNames.length; i++) { Class<?> type = getProtoType(typeNames[i]); if (type == null) { try { type = Class.forName(typeNames[i]); } catch (ClassNotFoundException e) { e.printStackTrace(); } } types[i] = type; } this.method = cls.getDeclaredMethod(field.getName(), types); this.method.setAccessible(true); } else { for (Method method : cls.getDeclaredMethods()) { if (method.getName().equals(field.getName())) { this.method = method; this.method.setAccessible(true); break; } } } if (this.method == null) { throw new NoSuchMethodException(field.getName()); } } public T call(Object receiver, Object... args) { try { return (T) this.method.invoke(receiver, args); } catch (InvocationTargetException e) { if (e.getCause() != null) { e.getCause().printStackTrace(); } else { e.printStackTrace(); } } catch (Throwable e) { e.printStackTrace(); } return null; } public T callWithException(Object receiver, Object... args) throws Throwable { try { return (T) this.method.invoke(receiver, args); } catch (InvocationTargetException e) { if (e.getCause() != null) { throw e.getCause(); } throw e; } } public Class<?>[] paramList() { return method.getParameterTypes(); }}
mirror/RefConstructor.java
构造方法类封装了Java反射中java.lang.reflect.Constructor的ctor.newInstance()方法。
public class RefConstructor<T> { private Constructor<?> ctor; public RefConstructor(Class<?> cls, Field field) throws NoSuchMethodException { if (field.isAnnotationPresent(MethodParams.class)) { Class<?>[] types = field.getAnnotation(MethodParams.class).value(); ctor = cls.getDeclaredConstructor(types); } else if (field.isAnnotationPresent(MethodReflectParams.class)) { String[] values = field.getAnnotation(MethodReflectParams.class).value(); Class[] parameterTypes = new Class[values.length]; int N = 0; while (N < values.length) { try { parameterTypes[N] = Class.forName(values[N]); N++; } catch (Exception e) { e.printStackTrace(); } } ctor = cls.getDeclaredConstructor(parameterTypes); } else { ctor = cls.getDeclaredConstructor(); } if (ctor != null && !ctor.isAccessible()) { ctor.setAccessible(true); } } public T newInstance() { try { return (T) ctor.newInstance(); } catch (Exception e) { return null; } } public T newInstance(Object... params) { try { return (T) ctor.newInstance(params); } catch (Exception e) { return null; } }}
VA实例
对应ActivityThread的反射注入-普通实现,在VA中的反射注入实现:
mirror/android/app/ActivityThread.java
在mirror.android.app.ActivityThread
类加载时,会调用RefClass.load(ActivityThread.class, "android.app.ActivityThread");
方法,遍历mirror.android.app.ActivityThread
的成员变量,并从android.app.ActivityThread
中获取对应的Field封装成上述类赋给mirror.android.app.ActivityThread
。
public class ActivityThread { public static Class<?> TYPE = RefClass.load(ActivityThread.class, "android.app.ActivityThread"); public static RefStaticMethod currentActivityThread; public static RefMethod<String> getProcessName; public static RefMethod<Handler> getHandler; public static RefMethod<Object> installProvider; public static RefObject<Object> mBoundApplication; public static RefObject<Handler> mH; public static RefObject<Application> mInitialApplication; public static RefObject<Instrumentation> mInstrumentation; public static RefObject<Map<String, WeakReference<?>>> mPackages; public static RefObject<Map> mProviderMap; @MethodParams({IBinder.class, List.class}) public static RefMethod<Void> performNewIntents; public static RefStaticObject<IInterface> sPackageManager; @MethodParams({IBinder.class, String.class, int.class, int.class, Intent.class}) public static RefMethod<Void> sendActivityResult; public static RefMethod<Binder> getApplicationThread;}
注: 在mirror.android.app.ActivityThread中的成员变量必须与framework中android.app.ActivityThread中对应的成员变量名相同,因为在RefClass.load()方法中是通过遍历mirror.android.app.ActivityThread中的Fields来获取对应的android.app.ActivityThread中的Fields的
com/lody/virtual/client/hook/delegate/AppInstrumentation.java
在业务层使用的时候,只需要调用ActivityThread.mInstrumentation.get(VirtualCore.mainThread());
方法就可以获取当前android.app.ActivityThread
中mInstrumentation的值,调用ActivityThread.mInstrumentation.set(VirtualCore.mainThread(), this);
就可以通过反射注入业务层自己实现的AppInstrumentation了。
public final class AppInstrumentation extends InstrumentationDelegate implements IInjector { ... private AppInstrumentation(Instrumentation base) { super(base); } @Override public void inject() throws Throwable { base = ActivityThread.mInstrumentation.get(VirtualCore.mainThread()); ActivityThread.mInstrumentation.set(VirtualCore.mainThread(), this); } ...}
0x02. 总结
对比ActivityThread的反射注入-普通实现和ActivityThread的反射注入-VA实现,初一看,可能觉得VA实现多了很多代码,还有些绕;但是普通方法实现,每对一个属性进行反射注入都需要写下方流程中的所有代码,或者部分代码;通过VA的实现方法,只需要在对应的类中(例如: mirror.android.app.ActivityThread
)写上需要反射注入的属性,业务层代码也更简洁可读性更高。
反射注入的一般流程
- 获取需要注入的类的Class对象
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
- 获取Class对象中需要注入的Field
Field instrumentationField = activityThreadClass.getDeclaredField("mInstrumentation");
- 通过Field的set方法注入业务层已实现的对象
instrumentationField.set(currentActivityThread, new PluginInstrumentation(instrumentation));
反射调用方法的一般流程
- 获取需要注入的类的Class对象
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
- 获取Class对象中需要调用的Method
Method currentActivityThreadMethod = activityThreadClass.getMethod("currentActivityThread");
- 通过Method的invoke方法调用
Object currentActivityThread = currentActivityThreadMethod.invoke(null);
Github地址: https://github.com/ximsfei/RefInject
- VirtualApp Java层Hook基础
- 对 VirtualApp hook过程的理解
- JNI Hook java层方法
- JNI Hook java层方法
- Hook基础
- 应用层InLine Hook
- 驱动层IAT HOOK
- Java HOOK
- Anroid HOOK Method(Native 层)
- Android Java层的hook检测(Cydia Substrate或者Xposed框架)
- HOOK基础(一)
- HOOK基础(二)
- Hook基础 C++篇
- 转-hook基础操作
- Java Web表示层技术:Servlet基础
- VirtualApp沙盒基本原理
- VirtualApp 中的进程
- linux netfilter IP层的HOOK点
- Linux i2c_client和i2c_driver的创建与绑定
- sql语句中having count 和group by的使用
- unity3d调用另一个脚本组件的方法
- CTF中Web找Flag题目(1)
- 内部类及base调用子类方法
- VirtualApp Java层Hook基础
- spring注入properties类型的配置文件信息
- integral_constant定义编译期常量
- Python的时间字符串,不同格式,时间戳之间转换
- C#创建Windows Service(Windows 服务)基础教程
- Android客户端消息推送的原理和方式
- 通知与消息机制
- Python分割字符串split()
- 1556 Color the ball(分块)