Java反射:
Java提供了一套反射API,该api由Class类与Java.lang.reflect类库组成,该类库包含了Field,method,Construct等类
对成员变量,成员方法和构造方法的信息进行的编程操作可以理解为反射机制
为什么用反射:
可以动态加载类(需要时再加载类)
而不是编译前加载
**从官方定义中就能找到其存在的价值,运行时获得程序/程序集中每一个类型的成员和成员信息,从而动态创建/修改/调用/获取其属性,而不需要事先知道运行的对象是谁
**重点:运行时,而不是编译时(不改变原有代码逻辑,自行运行时的时候动态创建和编译即可)
安全应用场景:
构造利用链,触发RCE
反序列化链构造
动态获取或执行任意类中的属性/方法
动态代理的底层原理时反射机制
rmi反序列化也涉及到反射操作
反射演示
package org.example.xiaodi_javasec.day03;
public class ReflectDemo {
public String name="root";
public int age = 20;
private String gender = "man";//不是gay
protected String job = "sec";
public ReflectDemo() {
System.out.println("对象被无参创建");
}
public ReflectDemo(String name) {
this.name = name;
System.out.println("有参数"+name);
}
public ReflectDemo(int age, String name) {
this.age = age;
this.name = name;
System.out.println("有参数"+name+"&"+age);
}
public void info(String name, int age, String gender, String job) {
this.name = name;
this.age = age;
this.gender = gender;
this.job = job;
}
}
这是一个很简单的类
info是自定义的函数
ReflectDemo是构造方法

通过forName获取类
通过内置的.class获取类

可以看到,输出的结果都是一样的
根据现有对象获取类

可以看到,三种方式的输出结果都是一样的
package org.example.xiaodi_javasec.day03;
public class Reflect {
public static void main(String[] args) throws ClassNotFoundException {
Class aclass = Class.forName("org.example.xiaodi_javasec.day03.ReflectDemo");//通过forName获取类
System.out.println(aclass);
Class bclass = ReflectDemo.class;
System.out.println(bclass);
ReflectDemo RD = new ReflectDemo();
Class cclass = RD.getClass();
System.out.println(cclass);
}
}
通过类加载器获取
package org.example.xiaodi_javasec.day03;
public class Reflect {
public static void main(String[] args) throws ClassNotFoundException {
Class aclass = Class.forName("org.example.xiaodi_javasec.day03.ReflectDemo");//通过forName获取类
System.out.println(aclass);
Class bclass = ReflectDemo.class;
System.out.println(bclass);
ReflectDemo RD = new ReflectDemo();
Class cclass = RD.getClass();
System.out.println(cclass);
ClassLoader CL = ClassLoader.getSystemClassLoader();
Class dclass = CL.loadClass("org.example.xiaodi_javasec.day03.ReflectDemo");
System.out.println(dclass);
}
}
通过反射获取成员变量
package org.example.xiaodi_javasec.day03;
import java.lang.reflect.Field;
public class Reflect {
public static void main(String[] args) throws ClassNotFoundException {
Class aclass = Class.forName("org.example.xiaodi_javasec.day03.ReflectDemo");//通过forName获取类
System.out.println(aclass);
Class bclass = ReflectDemo.class;
System.out.println(bclass);
ReflectDemo RD = new ReflectDemo();
Class cclass = RD.getClass();
System.out.println(cclass);
ClassLoader CL = ClassLoader.getSystemClassLoader();
Class dclass = CL.loadClass("org.example.xiaodi_javasec.day03.ReflectDemo");
System.out.println(dclass);
Field[] fields = aclass.getFields();
for (Field field : fields) {
System.out.println(field);
}
}
}
获取到类后,通过内置的getFields方法,获取类的所有公共成员变量,以数组形式返回
通过for循环进行遍历输出
如果需要获取全部成员变量(包括private和protected)
使用getDeclaredFields()即可
getField加上参数,例如
**getField(“name”)
**表示获取指定的公共成员变量对象
同理getDeclaredFields加上参数表示
表示获取指定的成员变量对象

这只是获取类的成员变量名
Field类还可以进行赋值
void set(object obj,Object value)
第一个参数是对象名,第二个是要赋的值
Object get(Object obj)
获取值
ReflectDemo RF = new ReflectDemo();
Field field2 = aclass.getField("age");
Object a = field2.get(RF);
System.out.println(a);
创建一个对象RF
然后通过Field取得它的成员变量age
再通过一个Object类的对象a接收它
然后输出a
修改值,修改完记得重新读取
package org.example.xiaodi_javasec.day03;
import java.lang.reflect.Field;
public class Reflect {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Class aclass = Class.forName("org.example.xiaodi_javasec.day03.ReflectDemo");//通过forName获取类
System.out.println(aclass);
Class bclass = ReflectDemo.class;
System.out.println(bclass);
ReflectDemo RD = new ReflectDemo();
Class cclass = RD.getClass();
System.out.println(cclass);
ClassLoader CL = ClassLoader.getSystemClassLoader();
Class dclass = CL.loadClass("org.example.xiaodi_javasec.day03.ReflectDemo");
System.out.println(dclass);
Field[] fields = aclass.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
Field field = aclass.getField("name");
Field field_1=aclass.getDeclaredField("gender");
System.out.println(field_1);
System.out.println(field);
ReflectDemo RF = new ReflectDemo();
Field field2 = aclass.getField("age");
Object a = field2.get(RF);
System.out.println(a);
field2.set(RF,18);
Object b = field2.get(RF);
System.out.println(b);
}
}
反射获取构造方法

Constructor<?>[] constructors= aclass.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
Constructor<?>[] constructor_all= aclass.getDeclaredConstructors();
for (Constructor<?> constructor : constructor_all) {
System.out.println(constructor);
}
用法和Field类相似
package org.example.xiaodi_javasec.day03;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class Reflect {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException {
Class aclass = Class.forName("org.example.xiaodi_javasec.day03.ReflectDemo");//通过forName获取类
System.out.println(aclass);
Class bclass = ReflectDemo.class;
System.out.println(bclass);
ReflectDemo RD = new ReflectDemo();
Class cclass = RD.getClass();
System.out.println(cclass);
ClassLoader CL = ClassLoader.getSystemClassLoader();
Class dclass = CL.loadClass("org.example.xiaodi_javasec.day03.ReflectDemo");
System.out.println(dclass);
Field[] fields = aclass.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
Field field = aclass.getField("name");
Field field_1=aclass.getDeclaredField("gender");
System.out.println(field_1);
System.out.println(field);
ReflectDemo RF = new ReflectDemo();
Field field2 = aclass.getField("age");
Object a = field2.get(RF);
System.out.println(a);
field2.set(RF,18);
Object b = field2.get(RF);
System.out.println(b);
//获取所有构造方法
Constructor<?>[] constructors= aclass.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
Constructor<?>[] constructor_all= aclass.getDeclaredConstructors();
for (Constructor<?> constructor : constructor_all) {
System.out.println(constructor);
}
//获取指定参数类型的构造方法
Constructor constructors1= aclass.getConstructor(String.class);
System.out.println(constructors1);
}
}
construct类除了可以获取构造方法
还可以通过调用构造方法创建对象
T newinstance(Object… initargs):根据指定的构造方法创建对象
setAccessible(boolean flag):设置为true,表示取消访问权限检查
Constructor constructors1= aclass.getConstructor(String.class);
System.out.println(constructors1);
constructors1.setAccessible(true);//如果构造方法是私有,则需要加上这个,取消访问检查
ReflectDemo RD1 = (ReflectDemo) constructors1.newInstance("root");
反射获取成员方法
//获取&调用成员方法
Method[] methods=aclass.getMethods();//获取所有成员方法,包括继承的
for (Method method : methods) {
System.out.println(method);
}
Method[] methods=aclass.getDeclaredMethods();//获取所有成员方法,不包括继承的
for (Method method : methods) {
System.out.println(method);
}
Method methods=aclass.getMethod('');

通过invoke调用
Method method=aclass.getMethod("info",String.class,int.class,String.class, String.class);
System.out.println(method);
//调用成员方法
method.invoke(RF,"root123",123,"no_gay","no_gay");
反射与安全挂钩

窝趣,弹计算器了,有黑客?
这是一个Java内置类:运行时类
它不能被new,因为它的构造器是私有的
但是可以通过getRuntime获取当前的实例
exec():老朋友了,看到它就能想到命令执行
在Java中,它也是用来执行命令的
exec(“calc”)
执行calc命令(弹出计算器)
package org.example.xiaodi_javasec.day03;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import static java.lang.Class.forName;
public class exp {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, InstantiationException {
Class runtime = forName("java.lang.Runtime");
Constructor constructor = runtime.getDeclaredConstructor();
constructor.setAccessible(true);
Runtime runtime_instance = (Runtime)constructor.newInstance();
Method get_exec= runtime.getMethod("exec", String.class);
get_exec.invoke(runtime_instance,"calc");
}
}
可以直接利用反射调用exec命令实现rce
总结一下,因为边听边写笔记确实有点混乱
forname获取类:
Class reflect = Class.forname("org.example.xiaodi_javasec.day03.ReflectDemo")
ClassLoader类加载器获取类:
ClassLoader CL = ClassLoader.getSystemClassLoader();
Class dclass CL.loadClass("org.example.xiaodi_javasec.day03.ReflectDemo");
通过getclass函数获取到类
ReflectDemo RD = new ReflectDemo();
Class cclass = RD.getClass();
通过现有对象获取对应类
Class bclass = ReflectDemo.class;
以上方式均可获取到类
获取其成员变量以及方法
可以使用Field类
类名.getFields:获取所有公共(pbulic)成员变量
类名.getDeclaredFields:获取所有成员变量,包括私有
它们以数组形式返回
因此需要定义Field[] 数组类型去接收
类名.getField(成员变量名)
获取指定成员变量(public)
类名.getDeclaredField(成员变量名)
获取指定成员变量
Method[] methods = 类名…getMethods()
获取所有成员方法,包括继承的
Method[] methods = 类名.getDeclaredMethods()
获取所有成员方法,不包括继承的
Method method =class_reflect.getMethod("info", String.class,int.class,String.class, String.class)
method.invoke(newinstance,"root123",123,"no_gay","no_gay");
指定参数类型获取并且调用成员方法
Constructor[] Constructors = 类名.getConstructors()
获取公有构造方法
Constructor[] Constructors = 类名.getDeclaredConstructors()
获取所有构造方法
Constructor constructor = 类名.getConstructor()
获取指定构造方法
package org.example.xiaodi_javasec.day03;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import static java.lang.Class.forName;
public class exp {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, InstantiationException {
Class class_reflect = forName("org.example.xiaodi_javasec.day03.ReflectDemo");
//获取类
Field[] class_reflect_Attributes = class_reflect.getDeclaredFields();//获取所有成员变量
for (Field classReflectAttribute : class_reflect_Attributes) {
System.out.println(classReflectAttribute);
}//遍历输出
Field Attribute = class_reflect.getDeclaredField("age");//指定获取age成员变量
ReflectDemo instance_demo = new ReflectDemo();
Object get_Attribute = Attribute.get(instance_demo);//使用get_Attribute接收获取的age值,并且指定对象
System.out.println(get_Attribute);
Attribute.set(instance_demo,19);
System.out.println(instance_demo.age);//输出19,被set修改了
//获取&设置&输出成员变量
System.out.println("获取&设置&输出成员变量");
Constructor[] class_reflect_constructor = class_reflect.getDeclaredConstructors();
for (Constructor class_reflect_constructors : class_reflect_constructor) {
System.out.println(class_reflect_constructors);
}
Constructor class_reflect_constructor_alone = class_reflect.getDeclaredConstructor(String.class);
System.out.println(class_reflect_constructor_alone);
class_reflect_constructor_alone.setAccessible(true);
ReflectDemo newinstance = (ReflectDemo) class_reflect_constructor_alone.newInstance("roottoor");
System.out.println(newinstance.name);
System.out.println("获取&调用构造方法");
Method[] methods=class_reflect.getMethods();//获取所有成员方法,包括继承的
for (Method method : methods) {
System.out.println(method);
}
Method[] methods_Declared =class_reflect.getDeclaredMethods();//获取所有成员方法,不包括继承的
for (Method method : methods_Declared) {
System.out.println(method);
}
Method method =class_reflect.getMethod("info", String.class,int.class,String.class, String.class);//指定参数类型获取成员方法
System.out.println(method);
method.invoke(newinstance,"root123",123,"no_gay","no_gay");
System.out.println("获取&调用成员方法");
}
}
评论(0)
暂无评论