📒博客主页:开心星人的博客主页
🔥系列专栏:Try to Hack
🎉欢迎关注🔎点赞👍收藏⭐️留言📝
📆首发时间:🌴2023年10月16日🌴
🍭作者水平很有限,如果发现错误,还望告知,感谢!
https://xz.aliyun.com/t/6787
https://xz.aliyun.com/t/7029
https://www.cnblogs.com/wglIT/p/7590468.html
对于任意一个类,都能够得到这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
其实在Java中定义的一个类本身也是一个对象,即java.lang.Class类的实例,这个实例称为类对象
类对象表示正在运行的 Java 应用程序中的类和接口
类对象没有公共构造方法,由 Java 虚拟机自动构造
类对象用于提供类本身的信息,比如有几种构造方法, 有多少属性,有哪些普通方法
要得到类的方法和属性,首先就要得到该类对象
Java反射(Reflection)是Java非常重要的动态特性,通过使用反射我们不仅可以获取到任何类的成员方法(Methods)、成员变量(Fields)、构造方法(Constructors)等信息,还可以动态创建Java类实例、调用任意的类方法、修改任意的类成员变量值等。Java反射机制是Java语言的动态性的重要体现,也是Java的各种框架底层实现的灵魂。
要获取该类对象一般有三种方法
class.forName("reflection.User")
User.class
new User().getClass()
最常用的是第一种,通过一个字符串即类的全路径名就可以得到类对象,另外两种方法依赖项太强
1、使用IDE时,我们输入一个对象或类并想调用它的属性或方法时,编译器会自动列出它的属性或方法,这就是通过反射实现的。
2、JavaBean和JSP之间的调用也是通过反射实现的。反射最重要的用途是开发各种通用框架,Spring框架以及ORM框架,都是通过反射机制来实现的。
3、在实际利用场景当中,我们利用Java反射机制来绕过一些安全权限机制检查,如获取private权限的方法和属性。本质就是我们绕过访问安全检查。所以通过java反射机制的学习,能够为我们为我们后面的java漏洞分析调试,java漏洞poc测试和服务端模板引擎注入等有着十分重要的意义。
与new直接创建对象不同,反射是先拿到类对象,然后通过类对象获取构造器对象,再通过构造器对象创建一个对象
package reflection;
import java.lang.reflect.*;
public class CreateObject {
public static void main(String[] args) throws Exception {
Class UserClass=Class.forName("reflection.User");
Constructor constructor=UserClass.getConstructor(String.class);
User user=(User) constructor.newInstance("happycoder");
System.out.println(user.getName());
}
}
package reflection;
import java.lang.reflect.*;
public class CallMethod {
public static void main(String[] args) throws Exception {
Class UserClass=Class.forName("reflection.User");
Constructor constructor=UserClass.getConstructor(String.class);
User user=(User) constructor.newInstance("happycoder");
Method method = UserClass.getDeclaredMethod("setName", String.class);
method.invoke(user, "Bob");
System.out.println(user.getName());
}
}
package reflection;
import java.lang.reflect.*;
public class AccessAttribute {
public static void main(String[] args) throws Exception {
Class UserClass=Class.forName("reflection.User");
Constructor constructor=UserClass.getConstructor(String.class);
User user=(User) constructor.newInstance("happycoder");
Field field= UserClass.getDeclaredField("name");
field.setAccessible(true);// name是私有属性,需要先设置可访问
field.set(user, "Wisdom");
System.out.println(user.getName());
}
}
setAccessible(true)暴力访问权限
在一般情况下,我们使用反射机制不能对类的私有private字段进行操作,绕过私有权限的访问。但一些特殊场景存在例外的时候,比如我们进行序列化操作的时候,需要去访问这些受限的私有字段,这时我们可以通过调用AccessibleObject上的setAccessible()方法来允许访问。
package reflection;
public class Exec {
public static void main(String[] args) throws Exception {
//java.lang.Runtime.getRuntime().exec("calc.exe");
Class runtimeClass=Class.forName("java.lang.Runtime");
Object runtime=runtimeClass.getMethod("getRuntime").invoke(null);// getRuntime是静态方法,invoke时不需要传入对象
runtimeClass.getMethod("exec", String.class).invoke(runtime,"calc.exe");
}
}
利用了Java的反射机制把我们的代码意图都利用字符串的形式进行体现,使得原本应该是字符串的属性,变成了代码执行的逻辑