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
的构造,不涉及链的问题