前言
早在几个月前在学习Java开发阶段就有了解过一点反射,但最近学习反序列化感觉之前学的还是有点不太够用,基础不牢地动山摇,遂今天跟着Drunkbaby师傅的博客以及参考p牛的Java安全漫谈重新学习一遍反射,也是对自己的一次查缺补漏
反射基础学习
反射是大多数语言都必不可少的组成部分,对象可以通过反射获取他的类,类可以通过反射拿到所有的方法(包括private修饰符的方法),总之通过反射我们将Java这种静态语言附加上动态特性
入门:
需要明确的是,反射只是一种手段,并不能直接造成攻击的效果,最后的攻击链还是要我们自己构造的
1 2 3 4 5 6 7 8 9
| public class ReflectionTest {
public static void main(String[] args) throws Exception { Class clazz = Class.forName("com.study.entity.Person"); clazz.getMethod("test").invoke(clazz.newInstance()); } }
|
在上述例子中,有几个在反射里极为重要的方法:
- 获取类的方法:forName
- 实例化类对象的方法:newInstance
- 获取函数的方法:getMethod
- 执行函数的方法:invoke
基本上这几个方法就是Java安全里常用的了
反射的使用方法
使用反射首先要实例化对象,有三种实例化方法
三种实例化方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com.study.entity;
public class ReflectionTest { public static void main(String[] args) throws Exception { Class c1 = Person.class; System.out.println(c1.getName()); Person p = new Person(); Class c2 = p.getClass(); System.out.println(c2.getName()); Class c3 = Class.forName("com.study.entity.Person"); System.out.println(c3.getName()); } }
|
获取类里的属性
在上文中已经学习了如何去通过反射实例化对象,实例化对象的下一步就是要获取类里面的各种属性
1、获取成员变量Field
1
| import java.lang.reflect.Field;
|
- Field[] getFields() :获取所有 public 修饰的成员变量
- Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符
- Field getField(String name) 获取指定名称的 public 修饰的成员变量
- Field getDeclaredField(String name) 获取指定的成员变量
放个源代码,方便Copy~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class ReflectionTest { public static void main(String[] args) throws Exception { Class c1 = Person.class; System.out.println(c1.getName());
Field[] fields = c1.getFields(); for (Field field : fields) { System.out.println("我只能找到public的成员变量:" + field); }
fields = c1.getDeclaredFields(); for (Field field : fields) { System.out.println("我能找到所有成员变量,包括私有的:" + field); }
Field name = c1.getDeclaredField("name"); System.out.println(name); } }
|
2. 获取成员方法 Method
在Person.java 中添加以下方法:
1 2 3 4 5 6 7 8
| Person.java public void Study(String str) { System.out.println("学习喵~" + str); } public String sleep(String str) { return "睡觉喵~" + str; }
|
1 2 3 4 5 6 7 8 9
| Method getMethod(String name, 类<?>... parameterTypes)
Method getDeclaredMethod(String name, 类<?>... parameterTypes)
Method[] getMethods()
Method[] getDeclaredMethods()
|
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public static void main(String[] args) throws Exception { Class c1 = Person.class;
Method[] methods = c1.getDeclaredMethods(); Method[] methods1 = c1.getMethods(); Method study = c1.getMethod("Study", String.class); Method sleep = c1.getDeclaredMethod("sleep", String.class);
for (Method method : methods) { System.out.println("getDeclaredMethods: " + method); } for (Method method : methods1) { System.out.println("getMethods: " + method); } System.out.println("getMethod: " + study); System.out.println("getDeclaredMethod: " + sleep);
}
|
4、获取构造函数
1 2 3 4 5 6 7
| Constructor<?>[] getConstructors() :只返回public构造函数
Constructor<?>[] getDeclaredConstructors() :返回所有构造函数
Constructor<> getConstructor(类<?>... parameterTypes) : 匹配和参数配型相符的public构造函数
Constructor<> getDeclaredConstructor(类<?>... parameterTypes) : 匹配和参数配型相符的构造函数
|
与上面大同小异
反射总结
反射确实就那么点东西,先获取类,并进行实例化对象;
然后获取类里面的属性;调用类里面的方法,就没了。
利用反射弹计算器
方法一:
1 2 3 4 5 6 7
| public static void main(String[] args) throws Exception {
Class c1 = Class.forName("java.lang.Runtime"); Method m = c1.getMethod("getRuntime"); Object runtime = m.invoke(null); c1.getMethod("exec", String.class).invoke(runtime, "calc"); }
|
方法二:(简化)
1 2
| Class c1 = Class.forName("java.lang.Runtime"); c1.getMethod("exec", String.class).invoke(c1.getMethod("getRuntime").invoke(c1), "C:\\WINDOWS\\System32\\calc.exe");
|