前言
因为对Java Web安全这一块没有做过研究,所以趁着时间比较空闲学习一下Java Web安全的知识。
Java反射机制
什么是Java反射机制?
Java反射机制是一种间接操作目标对象的一种机制。其核心在于JVM在运行的时候再动态加载类。并且对于任意一个类,只要知道它的名称,都能知道它的所有属性和方法。对于任意一个对象,都能调用它的任意方法和属性。
Java反射机制是Java动态特性的体现,利用反射机制我们可以轻松实现对Java类的动态调用。
Java反射常用类
Java.lang.Class;
Java.lang.ClassLoader;
Java.lang.reflect.Constructor;
Java.lang.reflect.Field;
Java.lang.reflect.Method;
Java.lang.reflect.Modifier;
Java反射常用方法
- forName() 获取类
- newInstance() 初始化类
- getMethod() 获取类的方法
- invoke() 执行类的方法
Java反射的实现
- Object.getClass() 如:String.getClass()
- Test.class() 如:xxx.class()
- Class.forName 如:class.forName(“java.lang.Runtime”)
实验 - 反射调用类方法
单例实例
Runtime类的构造方法是私有的,只能通过单例模式用静态方法获取对象,即我们只能通过Runtime().getRuntime()获取Runtime对象。
所以,对Runtime的反射代码如下:
Class class1 = Class.forName("java.lang.Runtime");
class1.getMethod("exec",String.class).invoke(class1.getMethod("getRuntime").invoke(class1),"calc.exe");
反射的执行流程如下:
Class class1 = Class.forName("java.lang.Runtime");
Method method1 = class1.getMethod("exec", String.class);
Method method2 = class1.getMethod("getRuntime");
Object run = method2.invoke(class1);
method1.invoke(run,"calc.exe");
这里对invoke()函数做一点解释:
invoke的功能是执行方法,第一个参数根据方法的不同而不同
- 普通方法,则第一个参数为类的对象
- 静态方法,则第一个参数为类
有参构造的反射
针对有参数的构造函数,需要引入一个新的反射方法getConstructor
getConstructor(),参数为目标类的构造函数参数,返回的是目标类的构造函数。
因为Runtime的构造方法是私有的,这里用ProcessBuilder来实现
Class class1 = Class.forName("java.lang.ProcessBuilder");
class1.getMethod("start").invoke(class1.getConstructor(List.class).newInstance(Arrays.asList("calc.exe")));
用上强制转化的代码(实际环境不一定存在)
Class class1 = Class.forName("java.lang.ProcessBuilder");
((ProcessBuilder)class1.getConstructor(List.class).newInstance(Arrays.asList("calc.exe"))).start();
私有构造函数
针对私有构造函数,我们可以通过getDeclared系列的函数进行反射。
getDeclaredMethod()可以返回目标类的所有方法,包括私有的方法。
这里用Runtime举例(因为它的构造方法是私有的)
Class class1 = Class.forName("java.lang.Runtime");
Constructor a = class1.getDeclaredConstructor();
a.setAccessible(true);
class1.getMethod("exec", String.class).invoke(a.newInstance(),"calc.exe");
在这里面新出现了个setAccessible,它的作用是修改私有方法的作用域。获取私有方法后必须修改,否则无法成功调用
实验 - 反射调用类成员
调用公有变量
Class class1 = Class.forName("com.javavuln.demo.Person");
Field f1 = class1.getField("a");
System.out.println(f1.get(class1.newInstance()));
调用所有变量
Class class1 = Class.forName("com.javavuln.demo.Person");
Field f1 = class1.getDeclaredField("b");
f1.setAccessible(true);
System.out.println(f1.get(class1.newInstance()));