java_cc链小结

##前言
感觉自己最近越来越浮躁了,也没有静下心来好好分析点什么,所以这次打算好好整理一下之前学过的CC链

##总览

##CC1
1.适用版本:commons-collections 3.2.1
2.细节描述
在构造链子的过程中一般是倒着来看感觉会比较顺一点,所以我们从InvokeTransform来看:
InvokeTransformtransform方法中实现了getMethod和invoke方法,刚好可以将我们的Runtime.exe那一段进行命令执行

这里用了一个chainedTransform数组进行一个整体的transform起到简化代码的作用,接下来我们只需要寻找哪里调用了transform就可以,
可以看到,在LazyMap中的get方法中调用了transform,接下来关注一下这factory是如何传入的,可以发现,这边是LazyMap的构造方法,由于是protected,还需要使用反射的方式来进行赋值
但是再往下看,发现其decorate方法会直接返回一个LazyMap对象
,所以我们直接调用这个方法进行赋值就行了
具体赋值方式如下:

接下来我们要看一下哪里调用了这个get,在annotationinvocationhandler的invoke方法中就调用了这个get,但是需要思考的是,如何触发这个invoke方法,这里我们回想一下php里面的__call方法,通过调用不存在的方法,就会调用到invoke方法中,那么接下来我们就只需要寻找符合条件的即可这里需要注意的是,我们要使用无参的方法,正好在readObject中就有一个符合条件的,但是要在其他类的内部进行这操作,我们需要借助代理

因此赋值方式如下:
首先关注一下其构造方法,需要传入的类型,直接传入的话就会对我们需要的memberValue赋值了

//反射调用AnnotationInvocationHandler类
Class<?> b= Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
//获取其构造方法
Constructor annotationInvocationhdlconstructor=b.getDeclaredConstructor(Class.class, Map.class);
annotationInvocationhdlconstructor.setAccessible(true);
//实例化对象并进行赋值操作
InvocationHandler handler = (InvocationHandler) annotationInvocationhdlconstructor.newInstance(Override.class,Lazymap);
//实例化一个代理对象
Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},handler);

//在实例化一个annotationInvocationHadnler,里面装的是代理的内容,相当于是套了一个壳
Object o = annotationInvocationhdlconstructor.newInstance(Override.class,mapProxy);


另外一条cc1链比较简单,就不细讲了,

##CC6
1.适用版本:没有版本限制
在CC6中,主要是前半部分有区别,在调用到get部分采用的是TiedMapEntry.hashCode方法,因为在hashcode中会调用到getValue方法

并且在getValue中会调用到get方法

而这里是对map进行调用了,我们看看map是如何赋值的,直接构造方法穿参就可以了

接下来就是寻找哪里有调用这个hashcode了,可以看到在HashMap的readObject中就有调用

那么解析来就来看一下两处是如何赋值的:
TiedMapEntry.hashcode就是采用直接赋值的形式就可以了,因为他有这个构造函数

接下来就是赋值到hashmap里面去,因为,hashmap其实是一个键值对,前面是key,后面是value

然后我们接下来就是对其赋值,但是在hashmap里面,要对其键值对进行赋值需要调用put函数,但是这还不够,由于在put的时候就有hash了

也就是这里

然后接下来他就会走一遍我们之前的链子了,那么这样会造成什么后果呢

我们往下继续看一下,在反序列化的过程中,此时由于我们前面put过一次了,所以此时就contains那个key,那么就进不到这个transform里面,因此我们这条链就断了

所以此时,我们首先需要将这个a给remove掉,在反序列化的时候才能进入

ok,到这里我们捋一下

  • 由于在对map2进行put的赋值操作的时候,走到了get方法,此时说get方法就会判断是否还有key,因为是第一次走到这里,所以肯定是没有这个key的,那么就进入到transform中,并且进行了一个put的操作,此时这个hashmap就有了这个key了
  • 针对以上问题,我们首先要在put以后将这个key给删掉,也就是使用上面的remove操作
    接下来是第二个问题,如何解决序列化过程就命令执行这一问题,那么就是在一开始的先赋值一个不存在命令执行效果的

    然后再利用反射更改值

##cc3
1.invoketransform被过滤、需要调用字节码
2.代码执行—(动态类加载)
我们要使用defineclass调用字节码实现动态类加载以达到命令执行的目的,那么就需要找到一处有调用newinstance
首先,我们找到的是TemplatesImpl.newTransformer里面有一个getTransletInstance

在这里面就有一个newInstance

而这个newInstance前面调用的内容,来源于上面这个函数

可以发现这里就实现了使用defineclass对_class[i]的赋值

首先我们来看这一部分如何赋值:
在上面的代码中,我们发现,要到newInstance的位置,需要对__name 和__bytecodes(传入的字节码)进行赋值

看看构造函数,发现是无参的,所以我们直接利用反射来更改值就行

根据前面的分析,我们进行了一下的赋值

但是此时还是无法成功命令执行

因为在defineclass中,如果没有满足父类是ABSTRACT_TRANSLET则会报错

因此,我们在前面些字节码的类中,还需要加上下面的extends

此时才可以成功执行
而这部分内容,其实是我们为了在序列化的时候测试能否成功命令执行而加上去的

这个_tfactory的属性是transient,是无法被序列化的,但是在readObject中会自动赋值,所以我们可以不用管

前面的部分进行transform方法以后就可以实现命令执行了,接下来就只需要将后面的方法完善好就行,如果invoketansform还能用的话,直接进行以下方法的调用即可

在cc3中,和前面两条链子最大的不同就是后半段,前面是适用invoketransform来进行命令执行的触发,这里需要对invoketransform进行一下解释,这个类,里面的tansform实现了getMethod和invoke方法,那就是可以反射调用任意的方法并执行,所以前面才说调用newTransformer和templatesImple就呼应上了,但是如果过滤了invoketransform,那么此时我们就要另外寻找调用了newTransformer的地方——TrAXFilter这个类
还有一种是利用TrAXFilter的构造方法

在这里调用了newTransformer,所以我们直接对其构造函数进行赋值就行了,接下来就是找哪里有触发获取构造函数的位置,在InstantiateTransformertransform中使用了getConstructor

跟进去可以发现,这里就会调用前面的TrAXFilter的构造方法,并对其赋值为templatesImple

接下来就看看如何对其进行赋值,这里参考一下InstantiateTransformer的构造函数以及参数就可以了

cc3主要是梳理这些即可

##cc4
1.版本:cc4

##cc2
1.这条cc链是没有用到数组的
然后这里的put我们跟一下,连同上面的cc4一起理解

InvokerTransformer<Object,Object> invokerTransformer = new InvokerTransformer<>("newTransformer",new Class[]{},new Object[]{});
TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));

PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);

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

首先size要大于等于2,不然无法进入到siftDown,也就无法执行后续的链条了

接下来是哪个部分放template的问题,可以发现如果是第一个元素是其他值,那么就会造成这里发生错误,因为1.getClass明显是有问题的

##cc5

##cc7
往上调用equals,最后调用到父类的,然后转到get

c

Author

vague huang

Posted on

2023-01-10

Updated on

2023-02-10

Licensed under

Comments