JAVA 反序列化漏洞入门学习笔记(二)--JAVA反射
参考文章
看完参考后面忽略
定义
Java 反射机制是指在程序运行时,对于任何一个类,都能知道这个类的所有属性和方法,对于任何一个实例对象,都能调用该对象的任何一个属性和方法
Java 中这种 "动态获取信息" 和 "动态调用属性 "方法的机制被称为 Java 反射机制
实例对象可以通过反射机制获取它的类,类可以通过反射机制获取它的所有方法和属性,获取的属性可以设值,获取的方法可以调用
Java 反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。
反射最重要的用途是开发各种通用框架。很多框架都是通过 XML 文件来进行配置的(例如 struts.xml、spring-*.xml 等),即所谓的框架核心配置文件。为了确保框架的通用性,程序运行时需要根据配置文件中对应的内容加载不同的类或对象,调用不同的方法,这也依赖于 Java 反射机制
简单示例:
public class Reflectest{
public static void main(String[] args) throws Exception {
Object runtime = Class.forName("aaa.bbb.ccc").getMethod("ddd", String.class).invoke(null);
}
}
可以看到,在程序编译时并未报错,在执行时才会提示 aaa.bbb.ccc 这个包不存在从而报错
也就是说:反射就是在程序运行的时候才知道要加载哪些类,加载完成后再去调用类中的方法(是不是感觉在 Python 反序列化中也见过)
反射机制步骤
- 获取类
- 获取类中方法及成员变量
- 使用该类实例化一个对象
- 调用实例对象中的方法/修改成员变量的值
获取类
- Class.forName("xxx.xxx.xxx")
- 类.class
- 对象.getClass()
示例:
class Ref{
public Ref(){
String name = "1ndex";
}
}
public class RefTest{
public static void main(String [] args) throws ClassNotFoundException {
//Class.forName
System.out.println("Class.forName(): " + Class.forName("Ref"));
//类.class
System.out.println("类.class: " + Ref.class);
//对象.getClass()
Ref cls = new Ref();
System.out.println("对象.getClass(): " + cls.getClass());
}
}
获取类中方法及成员变量
- className.getMethod(functionName,[parameterType.class]),获取 functionName 对应的特定 public 方法
- className.getMethods(),获取该类所有的 public 方法,包括其继承类的公用方法
- className.getDeclaredMethod(functionName,[parameterType.class]),获取 functionName 对应的特定方法,包括公共、保护、默认(包)访问和私有方法
- className.getDeclaredMethods(),获取某个类或接口声明的所有方法 , 包括公共、保护、默认(包)访问和私有方法,但不包括其继承类的方法
示例:
import java.lang.reflect.Method;
class Ref{
public Ref(){
String name = "1ndex";
}
public void ShowInfo(String name, int age){
System.out.println(name + " is " + age);
}
}
public class RefTest{
public static void main(String [] args) throws ClassNotFoundException, NoSuchMethodException{
Class<?> cls = Class.forName("Ref");
//className.getMethod(functionName,[parameterType.class])
Method method = cls.getMethod("ShowInfo",String.class,int.class);
//className.getMethods()
Method[] methods = cls.getMethods();
//className.getDeclaredMethods()
Method[] declareMethods = cls.getDeclaredMethods();
System.out.println("className.getMethod(functionName,[parameterType.class]):\n" + method);
System.out.println("\nclassName.getMethods():");
for(Method m:methods){
System.out.println(m);
}
System.out.println("\nclassName.getDeclaredMethods():");
for(Method m:declareMethods){
System.out.println(m);
}
}
}
使用该类实例化一个对象
- className.newInstance(),调用无参构造函数
- className.getConstructor(parameterType.class).newInstance("参数值"),调用 public 有参构造函数,之后只用调用实例化后的对象的公有方法
- className.getDeclaredConstructor(parameterType.class).newInstance("参数值"),这个方法会返回指定参数类型的构造方法。包括 public、protected 以及 private 修饰符修饰的
- className.getDeclaredConstructors(parameterType.class).newInstance("参数值"),这个方法会返回指定参数类型的所有构造方法。包括 public、protected 以及 private 修饰符修饰的
示例:
import java.lang.reflect.InvocationTargetException;
class Ref{
public Ref(){
System.out.println("无参构造函数!\n");
}
public Ref(String motto){
System.out.println("有参构造函数!\n" + motto);
}
}
public class RefTest{
public static void main(String [] args) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException{
Class<?> cls = Class.forName("Ref");
//className.newInstance(),调用无参构造函数
Ref obj1 = (Ref)cls.newInstance();
//className.getConstructor(parameterType.class).newInstance("参数值"),调用有参构造函数
Ref obj2 = (Ref)cls.getConstructor(String.class).newInstance("一给我里Giao!");
}
}
调用实例对象中的方法
- Method.invoke(obj , args[]),传入实例对象和参数即可执行目标方法
示例:
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
class Ref{
public Ref(){
String name = "1ndex";
}
public void ShowInfo(String motto){
System.out.println(motto);
}
}
public class RefTest{
public static void main(String [] args) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException{
// 获取类
Class<?> cls = Class.forName("Ref");
//获取类中方法
Method getFunc = cls.getMethod("ShowInfo",String.class);
//实例化对象
Ref obj = (Ref)cls.newInstance();
//调用对象中的方法
getFunc.invoke(obj,"一给我里Giao!");
}
}
tips:
- 如何调用特定的私有方法
实例:
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Constructor;
public class RefTest{
public static void main(String [] args) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException{
Class<?> cls = Class.forName("java.lang.Runtime");
Method getFunc = cls.getMethod("exec",String.class);
Constructor<?> cst = cls.getDeclaredConstructor();
cst.setAccessible(true);
Object obj = cst.newInstance();
getFunc.invoke(obj,"calc");
}
}