JAVA 反序列化学习之反射
字数 1207 2025-08-07 08:22:25
Java反序列化之反射机制深入解析
反射机制概述
Java反射机制允许程序在运行时动态获取类的信息并操作类或对象的属性和方法。Oracle官方定义:
Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions.
反射核心功能:
- 运行时判断任意对象所属类
- 运行时构造任意类的对象
- 运行时获取类的成员变量和方法
- 运行时调用任意对象的方法
反射关键方法
1. Class.forName()
作用:加载指定类并返回Class对象
方法签名:
public static Class<?> forName(String className)
public static Class<?> forName(String name, boolean initialize, ClassLoader loader)
特点:
- 无需import即可加载任意类
- 当initialize=true时(默认),会执行类初始化(static代码块)
- 可用于加载内部类(使用
$符号,如C1$C2)
初始化顺序:
- 类实例化:
static{} -> {} -> 构造函数 - 类初始化:仅执行
static{} - 有父类时:父类静态块 -> 子类静态块 -> 父类初始块 -> 父类构造函数 -> 子类初始块 -> 子类构造函数
安全利用:
// 恶意类
public class EvilClass {
static {
// 恶意代码
Runtime.getRuntime().exec("calc.exe");
}
}
// 触发点
public void ref(String name) throws Exception {
Class.forName(name); // 传入"EvilClass"即可触发
}
2. newInstance()
作用:创建类的新实例
方法签名:
Object java.lang.Class.newInstance()
限制:
- 只能调用无参构造函数
- 构造函数必须是public的
替代方案:使用Constructor.newInstance()
Constructor<?> constructor = clazz.getDeclaredConstructor(parameterTypes);
constructor.setAccessible(true); // 突破private限制
Object instance = constructor.newInstance(args);
单例模式绕过:
对于Runtime等单例类,不能直接newInstance,需通过:
Class clazz = Class.forName("java.lang.Runtime");
Method getRuntime = clazz.getMethod("getRuntime");
Object runtime = getRuntime.invoke(clazz);
3. getMethod()
作用:获取类的指定方法
方法签名:
public Method getMethod(String name, Class<?>... parameterTypes)
获取方法信息:
getName()- 方法名getReturnType()- 返回类型getParameterTypes()- 参数类型数组getModifiers()- 修饰符
注意:
- 需考虑方法重载情况
- 获取私有方法使用
getDeclaredMethod()
4. invoke()
作用:调用方法
方法签名:
public Object invoke(Object obj, Object... args)
调用规则:
- 实例方法:第一个参数为实例对象
- 静态方法:第一个参数可为类或null
完整利用链:
Class clazz = Class.forName("java.lang.Runtime");
Method execMethod = clazz.getMethod("exec", String.class);
Method getRuntimeMethod = clazz.getMethod("getRuntime");
Object runtime = getRuntimeMethod.invoke(clazz);
execMethod.invoke(runtime, "calc.exe");
安全应用场景
- 绕过沙盒限制:
1.getClass().forName("java.lang.Runtime")
- 动态调用任意方法:
public void execute(String className, String methodName) throws Exception {
Class clazz = Class.forName(className);
clazz.getMethod(methodName).invoke(clazz.newInstance());
}
- 突破访问控制:
// 调用私有方法
Method privateMethod = clazz.getDeclaredMethod("privateMethod");
privateMethod.setAccessible(true);
privateMethod.invoke(target);
防御建议
- 限制反射调用权限
- 对反序列化操作进行白名单控制
- 使用SecurityManager限制敏感操作
- 避免将用户输入直接用于反射操作
反射是Java安全研究的核心基础,后续还需结合ClassLoader、动态代理等机制深入理解各类漏洞原理。