本文目录导读:

在Java反序列化案例中还原对象,通常有几种不同的场景和对应方法,我来系统梳理一下:
基本还原方法
标准反序列化(有源码且类可用)
// 假设你有完整的类定义
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
// getters/setters
}
// 反序列化还原
public static Object deserialize(byte[] data) {
try (ByteArrayInputStream bis = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(bis)) {
return ois.readObject();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
只有序列化数据,没有源码
这是CTF和安全分析中的常见情况:
public static void analyzeObject(byte[] data) {
try {
// 先读取数据头
try (ByteArrayInputStream bis = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(bis)) {
// 读取对象类描述
ObjectStreamClass desc = ois.readObject().getClass().getObjectStreamClass();
System.out.println("类名: " + desc.getName());
System.out.println("序列化UID: " + desc.getSerialVersionUID());
// 读取字段信息
ObjectStreamField[] fields = desc.getFields();
for (ObjectStreamField field : fields) {
System.out.println("字段: " + field.getName() + " 类型: " + field.getTypeCode());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
使用第三方工具还原
SerialKiller / Serianalyzer
<!-- Maven依赖 -->
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.12.9</version>
</dependency>
ysoserial的Deserializer工具
# 使用ysoserial分析序列化数据 java -cp ysoserial.jar ysoserial.Deserializer < serialized_data.bin
专业的序列化分析工具
SerializationDumper - 最常用的序列化数据分析工具:
# 下载并运行 java -jar SerializationDumper.jar -r serialized_data.bin
输出示例:
STREAM_MAGIC: 0xac ed
STREAM_VERSION: 5
TC_OBJECT: 0x73
TC_CLASSDESC: 0x72
className: "com.example.User"
serialVersionUID: 0x1234567890abcdef
...
动态生成类来还原
当没有原始类时,可以用字节码工具动态生成:
import javassist.*;
public class DynamicClassLoader {
public static Class<?> createDynamicClass(String className,
Map<String, Class<?>> fields) throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass(className);
// 实现Serializable接口
ctClass.addInterface(pool.get("java.io.Serializable"));
// 添加字段
for (Map.Entry<String, Class<?>> entry : fields.entrySet()) {
CtField field = new CtField(pool.get(entry.getValue().getName()),
entry.getKey(), ctClass);
field.setModifiers(Modifier.PRIVATE);
ctClass.addField(field);
}
return ctClass.toClass();
}
}
实战案例:还原恶意序列化数据
场景:分析反弹Shell的序列化payload
public class PayloadAnalyzer {
public static void analyzePayload(byte[] payload) {
try {
// 1. 尝试安全反序列化(不执行恶意代码)
SafeObjectInputStream sois = new SafeObjectInputStream(
new ByteArrayInputStream(payload));
// 2. 记录对象图结构
ObjectGraphBuilder builder = new ObjectGraphBuilder();
Object obj = sois.readObject();
// 3. 分析对象链
analyzeObjectChain(obj);
} catch (Exception e) {
// 4. 如果失败,使用hex分析
analyzeHexPayload(payload);
}
}
private static void analyzeObjectChain(Object obj) {
// 递归分析对象引用链
System.out.println("根对象类: " + obj.getClass().getName());
// 使用反射查看字段
for (Field field : obj.getClass().getDeclaredFields()) {
field.setAccessible(true);
try {
Object value = field.get(obj);
System.out.println("字段: " + field.getName() +
" = " + (value != null ? value.getClass().getName() : "null"));
} catch (Exception e) {
System.out.println("无法访问字段: " + field.getName());
}
}
}
}
特殊场景处理
处理自定义readObject
// 如果类有自定义readObject,需要模拟执行
public class CustomDeserializer {
public static Object deserializeWithCustom(byte[] data) {
// 创建自定义ClassLoader
URLClassLoader classLoader = new URLClassLoader(new URL[]{});
try (ObjectInputStream ois = new ObjectInputStream(
new ByteArrayInputStream(data)) {
// 重写resolveClass来加载动态类
@Override
protected Class<?> resolveClass(ObjectStreamClass desc)
throws ClassNotFoundException {
// 可以在这里加载从网络下载的类
return classLoader.loadClass(desc.getName());
}
}) {
return ois.readObject();
}
}
}
处理代理对象
// 分析动态代理对象
public static void analyzeProxy(Object obj) {
if (Proxy.isProxyClass(obj.getClass())) {
InvocationHandler handler = Proxy.getInvocationHandler(obj);
System.out.println("代理接口: " +
Arrays.toString(obj.getClass().getInterfaces()));
// 获取InvocationHandler的内部状态
if (handler instanceof AnnotationInvocationHandler) {
// 特定处理
}
}
}
最佳实践建议
- 安全第一:在分析未知序列化数据时,使用隔离环境(沙箱或虚拟机)
- 逐步还原:从数据结构分析开始,到字段提取,最后才是对象重建
- 工具辅助:优先使用SerializationDumper等专业工具
- 记录日志:详细记录还原过程中的异常和特殊行为
常见问题:
- 序列化版本不一致:可以尝试修改serialVersionUID
- 类在classpath中不存在:使用动态生成类或自定义ClassLoader
- 嵌套对象复杂:使用递归分析,建立对象图
需要我详细解释某个具体场景吗?比如处理特定的CTF题目或安全分析案例?
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播