创建对象:newInstance 调用方法:invoke() 设置参数:field.set(obj,21);
反射机制
what JAVA反射机制是在运行状态中,对于任意一个类 (class文件),都能够知道这个类的所有属性和方法; 对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。 动态获取类中信息,就是java反射 。可以理解为对类的解剖。
Person
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 public class Person { private int age; private String name; public Person (String name,int age ) { super(); this .age = age; this .name = name; System.out .println("Person param run..." +this .name+":" +this .age); } public Person () { super(); System.out .println("person run" ); } public void show () { System.out .println(name+"...show run..." +age); } private void privateMethod () { System.out .println(" method run " ); } public void paramMethod (String str,int num ) { System.out .println("paramMethod run....." +str+":" +num); } public static void staticMethod () { System.out .println(" static method run......" ); } }
如何获取字节码文件对象呢 要想要对字节码文件进行解剖,必须要有字节码文件对象.
获取Class对象的三种方式
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 public class ReflectDemo { public static void main (String[] args) throws ClassNotFoundException { getClassObject_3(); } public static void getClassObject_1 () { Person p = new Person (); Class clazz = p.getClass(); Person p1 = new Person (); Class clazz1 = p1.getClass(); System.out.println(clazz==clazz1); } public static void getClassObject_2 () { Class clazz = Person.class; Class clazz1 = Person.class; System.out.println(clazz==clazz1); } public static void getClassObject_3 () throws ClassNotFoundException { String className = "cn.test.bean.Person" ; Class clazz = Class.forName(className); System.out.println(clazz); } }
获取 Class 中的构造函数 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 public class ReflectDemo2 { public static void main (String[] args) throws ClassNotFoundException, InstantiationException, Exception { createNewObject_2(); } public static void createNewObject_2 () throws Exception { String name = "cn.test.bean.Person" ; Class clazz = Class.forName(name); Constructor constructor = clazz.getConstructor(String.class,int .class); Object obj = constructor.newInstance("小明" ,38 ); } public static void createNewObject () throws ClassNotFoundException, InstantiationException, IllegalAccessException{ String name = "cn.test.bean.Person" ; Class clazz = Class.forName(name); Object obj = clazz.newInstance(); } }
获取 Class 中的字段 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public static void getFieldDemo () throws Exception { Class clazz = Class.forName("cn.test.bean.Person" ); Field field = null ; field = clazz.getDeclaredField("age" ); field.setAccessible(true ); Object obj = clazz.newInstance(); field.set(obj, 89 ); Object o = field.get(obj); System.out.println(o); }
获取 Class 中的方法 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 public static void getMethodDemo_3() throws Exception { Class clazz = Class .forName("cn.test.bean.Person"); Method method = clazz.getMethod("paramMethod", String.class ,int .class ); Object obj = clazz.newInstance(); method .invoke(obj, "小强",89 ); } public static void getMethodDemo_2() throws Exception { Class clazz = Class .forName("cn.test.bean.Person"); Method method = clazz.getMethod("show", null );//获取空参数一般方法。 // Object obj = clazz.newInstance(); Constructor constructor = clazz.getConstructor(String.class ,int .class ); Object obj = constructor.newInstance("小明",37 ); method .invoke(obj, null ); } public static void getMethodDemo() throws Exception { Class clazz = Class .forName("cn.test.bean.Person"); Method [] methods = clazz.getMethods();//获取的都是公有的方法。 methods = clazz.getDeclaredMethods();//只获取本类中所有方法,包含私有。 for (Method method : methods){ System .out .println(method ); } }
泛型类的真实类型 通过Class类上的 getGenericSuperclass() 或者 getGenericInterfaces() 获取父类或者接口的类型,然后通过ParameterizedType.getActualTypeArguments() Actual Type Arguments 实际的类型参数 get Generic Super class 获取泛型超类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class RealType <T >{ private Class<T> clazz; public Class getRealType(){ ParameterizedType pt = (ParameterizedType) this .getClass().getGenericSuperclass(); this .clazz = (Class<T>) pt.getActualTypeArguments()[0 ]; return clazz; } }
动态代理 通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,扩展目标对象的功能。 代理对象拦截真实对象的方法调用,在真实对象调用前/后实现自己的逻辑调用 这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法。
动态代理的用途与装饰模式很相似,就是为了对某个对象进行增强。所有使用装饰者模式的案例都可以使用动态代理来替换。
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 99 100 101 102 interface Subject { void sellBook () ; }public class RealSubject implements Subject { @Override public void sellBook () { System.out.println("出版社卖书" ); } }public class ProxySubject implements Subject { private RealSubject realSubject; @Override public void sellBook () { if (realSubject == null ) { realSubject = new RealSubject (); } sale(); realSubject.sellBook(); give(); } public void sale () { System.out.println("打折" ); } public void give () { System.out.println("送优惠券" ); } }public class Main { public static void main (String[] args) { ProxySubject proxySubject = new ProxySubject (); proxySubject.sellBook(); RealSubject realSubject = new RealSubject (); MyHandler myHandler = new MyHandler (); myHandler.setProxySubject(realSubject); Subject subject = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), myHandler); subject.sellBook(); } }public class MyHandler implements InvocationHandler { private RealSubject realSubject; public void setProxySubject (RealSubject realSubject) { this .realSubject = realSubject; } @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { sale(); proxy = method.invoke(realSubject, args); give(); return proxy; } public void sale () { System.out.println("打折" ); } public void give () { System.out.println("送优惠券" ); } }
三个参数 接口类型(有一个接口)才能动态代理 第二个参数是,Java 规定必须实现个接口,第三个是代理逻辑,要把要代理的类传进去 InvocationHandler
代理 startActivity
HOOK 理解 Android Hook 技术以及简单实战 - 简书
使用反射修改 Android 系统底层的方法和宇段 Hook ,就是使用反射修改 Android 系统底层的方法和宇段
Hook(钩子): Android 操作系统中系统维护着自己的一套事件分发机制,那么 Hook 就是在事件传送到终点前截获并监控事件的传输,并修改事件流程的过程。其实就是代理模式+反射
1 2 3 4 5 public static void showToast (Context context, CharSequence cs, int length) { Toast toast = Toast.makeText(context,cs,length); hook(toast); toast.show(); }
Hook 的选择点:静态变量和单例 ,因为一旦创建对象,它们不容易变化,非常容易定位。
Hook 过程: 寻找 Hook 点,原则是静态变量或者单例对象,尽量 Hook public 的对象和方法。 选择合适的代理方式,如果是接口可以用动态代理。 偷梁换柱——用代理对象替换原始对象。 Android 的 API 版本比较多,方法和类可能不一样,所以要做好 API 的兼容工作
应用
Hook指定应用注入广告
修复bug
App登录劫持
登录界面上面的用户信息都存储在EditText控件上,然后通过用户手动点击“登录”按钮才会将上面的信息发送至服务器端去验证账号与密码是否正确。这样就很简单了,黑客们只需要找到开发者在使用EditText控件的getText方法后进行网络验证的方法,Hook该方法,就能劫持到用户的账户与密码了
hook练习