CC1中反射调用的构造
距离上次看java,这又过去将近小半年,必须学起来了
上个说反射机制得其实很模糊,但是四种获取class对象得方式还是很有用得
再贴一下
1 | //方法一 |
在这里主要想,重新认识一下反射机制
反射机制认知
定义
java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取类的信息以及动态调用对象的方法的功能称为java语言的反射机制Reflection。
理解
这就说明:Java程序可以加载一个编译期间完全未知的class,获悉其完整构造,并生成其对象实体、或对其fields设值、或唤起其methods。虽然java并不是动态语言。
java.lang.Class是反射入口。java中一切皆对象,继承自object。每一个对象都有自己的类型,通过getClass()得到一个java.lang.Class对象,(基本类型通过字面值.class获得,也叫类标记,如:int.class)这个Class对象中包含了与类型有关的信息,包括其字段、方法、父类或接口等。
Class对象
Class类的实例表示正在运行的Java应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为Class对象的一个类,所有具有相同元素类型和维数的数组都共享该Class对象。基本的Java类型(boolean、byte、char、short、int、long、float 和 double)和关键字void也表示为Class对象。
Class没有公共构造方法。Class对象是在加载类时由Java虚拟机以及通过调用类加载器中的defineClass方法自动构造的。
对于我们编写的每个类,它们都有一个Class对象。(更恰当地说,是保存在一个完全同名的.class文件中)。在运行期,一旦我们想生成那个类的一个对象,用于执行程序的Java虚拟机(JVM)首先就会检查那个类型的Class对象是否已经载入。若尚未载入,JVM就会查找同名的.class文件,并将其载入。所以Java程序启动时并不是完全载入的,这一点与许多传统语言都不同。一旦那个类型的Class对象进入内存,就用它创建那一类型的所有对象。
反射中的API
我们主要从4个方面认识反射的api
- 获取类的基本信息:
java.lang.Class - 获取类的实例:
java.lang.Class和java.lang.reflect.Constructor<T> - 操作实例的属性:
java.lang.reflect.Field - 调用实例的方法:
java.lang.reflect.Method - 要记住一切都是由
Class对象开始,java.lang.Class是反射入口。
上面这段话,我是抄的,
因为我认为比较重要得点是
java.lang.Class是反射入口- 一切皆对象,对象即可调用
getMethod和invoke方法(null除外) - 还有一点就是,之前得四种获取
class的方式都是获取class对象的句柄,并不是java.lang.Class
代码理解
个人目前阶段对此的理解,可能存在错误,更具学习进度,会一一更正
代码案例
1 | //测试class对象句柄,与class对象 |
输出如下

可以看到,实际Runtime.class还是Runtime对象,(说是对象,可能不太准确)
而加上getClass之后就成了Class对象了
那这就导致了一个问题,这个问题也是CC1链最终的命令执行的问题
getMethod和invoke
顾名思义,
getMethod就是获取对象中的方法invoke就是尝试从对象中获取一个函数指针,然后调用。
如何通过这两中方式获取Runtime类得实例呢?
第一种
上文说到,object是可以直接调用getMethod
所以这里可以通过getMethod获取到getRuntime方法,然后调用
测试代码
1 | Class runtime = Runtime.class; |
测试结果

然后再通过对象实例反射调用exec方法即可以实现命令执行
第二种
这也是cc1的调用方式
上文说:*java.lang.Class是反射的入口*
如何通过一个Class对象,实例化一个Runtime类呢?
上文说:每个数组属于被映射为Class对象的一个类,所有具有相同元素类型和维数的数组都共享该Class对象
- 首先通过
Class对象反射一个getMethod方法 - 然后通过此方法,调用
invoke方法获取指定类的指定的方法 - 然后获取
invoke方法 - 执行
invoke方法获取目标类的实例
测试代码
1 | Class cls = Runtime.class.getClass(); |
测试结果

调用exec
1 | Class b1 = b.getClass(); |
这是一次完整的调用

这里还有一个点要注意就是,刚开始获取Class对象的类,不一定非要Runtime.class,这个迷惑了好久,这个Runtime到底在链中起了什么作用?没作用,仅仅是获取Class对象
end
这里可以看的出来
这个写法就是cc1的代码执行的位置,一摸一样的调用
本文主要完成了对代码执行payload的构造,不涉及链的问题












