0x00. 前言
CC链1已有很多前辈分析,刚开始还好,到了后面,总觉得学的迷迷糊糊,从各类资料中所学也是一知半解。有很多问题对于Java基础不扎实的我或类似朋友,可能比较吃力。索性,我记录一下除常规链子分析外,一些疑惑的点,以供后续新入学的伙伴参考,因此本篇文章适合于面向刚开始分析CC链1的朋友。如有错误,也烦请大佬指点,不胜感激。
0x01. 完整exp
这里直接贴代码感觉很不美观所以上的图,各位也可以去其它师傅的文章获取exp。
0x02. hashmap.put("value",....)
1. 为何要调用hashmap.put()
因为链子在反序列化时,是从AnnotationInvocationHandler的readObject方法入手,目的是想调用readObject方法中的memberValue.setValue()方法。但是,这个方法是在for-each循环中,而我们通过反射得到AnnotationInvocationHandler对象时,要往构造方法中传入map值,而这个map传入进去后,也就对应for循环体内所对应的memberValues,如果memberValues为空,那么for循环就为空,会直接跳出循环体而不执行里面的代码,因此我们为了进入for循环,map中就必须有值,所以我们需要调用hashmap.put()向其中放入数据。
2. 为什么hashmap.put()的第一个位置必须为value?
因为我们传入map之后,for循环体内会通过Class<?> memberType = memberTypes.get(name);这条语句来获得name的memberType,我们提到,AnnotationInvocationHandler反射时,第二个参数是map,第一个参数被设定为Target.class注解,这是因为注解Target.class里面包含有value键,所以可以让memberType不为空,进而满足memberType!=null这个条件。当然,只要给的注解里面不为空,你设置其它注解都行,比如Repeatable.class,Retention.class都行。
所以前面给出的那条语句的memberTypes中就包含了注解里面的内容value
那么,在执行Class<?> memberType = memberTypes.get(name);的时候,这个name又是由第一句String name = memberValue.getKey();得来,进而可见name就来自于我们所给出的memberValues,通过memberValue.getKey()获得了map的键value。也因此,第二条语句在执行.get(name)的时候,才不会导致memberType为null,从而进入if循环。
0x03. AbstractInputCheckedMapDecorator中的setValue()方法
原谅新人菜,分析别的文章的时候实在不能理解为何寻找TransformedMap的checkSetValue方法时,会去到AbstractInputCheckedMapDecorator中的setValue方法。在问AI和分析下继承关系之后,我发现了以下几点:
1. TransformedMap并没有setValue()方法
因为memberValue的类型,是根据memberValues来的,我们传入的对应的memberValues就是TransformedMap,而TransformedMap类中并没有setValue方法,所以这个时候会顺着往TransformedMap的父类去找这个方法。而TransformedMap又继承自AbstractInputCheckedMapDecorator(这里是重点)
在AbstractInputCheckedMapDecorator类中,存在以下代码:
这三图的代码,可以理解为重写了for-each函数的逻辑(具体做了什么我们就不深究,只需明白其是改了以下for循环的底层逻辑代码),我通过箭头标出部分可以知道,map通过了MapEntry类来生成,而我们再看向MapEntry类,就会发现该类中存在setValue函数,也就是链子中提到的一环。
所以当我们在AnnotationInvocationHandler中进行for循环时,memberValue会因为TransformedMap的父类AbstractInputCheckedMapDecorator中的循环改写,从而去执行了MapEntry里面的setValue。
2. setValue时,parent是如何可控为我们想要的Map类型的?
同样,通过上面分析,我们可以发现TransformedMap是因为找不到setValue,所以会去父类AbstractInputCheckedMapDecorator寻找setValue。所以当进行循环的时候,在entrySet()这个函数内,为我们传递了this值EntrySet构造方法中去,这里的this,就是TransformedMap,而EntrySet构造方法里的parent,就是this所表示的TransformedMap,进而,我们最后setValue的时候,是通过TransformedMap来setValue。
debug便可看到parent和this的变化情况。
以上便是我在遇到CC链1中的疑惑,道友们如果有疑惑可以留下一同讨论,大佬如果发现错误,还烦请执正,不胜感激。
4A评测 - 免责申明
本站提供的一切软件、教程和内容信息仅限用于学习和研究目的。
不得将上述内容用于商业或者非法用途,否则一切后果请用户自负。
本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。
如果您喜欢该程序,请支持正版,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。敬请谅解!
程序来源网络,不确保不包含木马病毒等危险内容,请在确保安全的情况下或使用虚拟机使用。
侵权违规投诉邮箱:4ablog168#gmail.com(#换成@)