Java反射学习
redpomelo Lv2

前言

早在几个月前在学习Java开发阶段就有了解过一点反射,但最近学习反序列化感觉之前学的还是有点不太够用,基础不牢地动山摇,遂今天跟着Drunkbaby师傅的博客以及参考p牛的Java安全漫谈重新学习一遍反射,也是对自己的一次查缺补漏

image-20241127131500409

反射基础学习

反射是大多数语言都必不可少的组成部分,对象可以通过反射获取他的类,类可以通过反射拿到所有的方法(包括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属性
Class c1 = Person.class;
System.out.println(c1.getName());

// 方法二:对象的getClass()方法
Person p = new Person();
Class c2 = p.getClass();
System.out.println(c2.getName());

// 方法三:Class类的静态方法forName()
Class c3 = Class.forName("com.study.entity.Person");
System.out.println(c3.getName());

}
}

image-20241127134309653

获取类里的属性

在上文中已经学习了如何去通过反射实例化对象,实例化对象的下一步就是要获取类里面的各种属性

1、获取成员变量Field

1
import java.lang.reflect.Field;
  • Field[] getFields() :获取所有 public 修饰的成员变量
  • Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符
  • Field getField(String name) 获取指定名称的 public 修饰的成员变量
  • Field getDeclaredField(String name) 获取指定的成员变量

image-20241127135159211

放个源代码,方便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
Field[] fields = c1.getFields(); //只能找到public成员变量
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) //返回该类所声明的public方法

Method getDeclaredMethod(String name, 类<?>... parameterTypes) //返回该类所声明的所有方法

//第一个参数获取该方法的名字,第二个参数获取标识该方法的参数类型

Method[] getMethods() //获取所有的public方法,包括类自身声明的public方法,父类中的public方法、实现的接口方法

Method[] getDeclaredMethods() // 获取该类中的所有方法

image-20241127140633391

代码:

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;
// System.out.println(c1.getName());

// 获取类的所有方法
Method[] methods = c1.getDeclaredMethods();
// 获取类的所有公共方法,包括类自身声明的 public 方法,父类中的 、实现的接口方法
Method[] methods1 = c1.getMethods();
// 获取public的study方法
Method study = c1.getMethod("Study", String.class);
// 获取private的sleep方法
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) : 匹配和参数配型相符的构造函数

与上面大同小异

反射总结

反射确实就那么点东西,先获取类,并进行实例化对象;

然后获取类里面的属性;调用类里面的方法,就没了。

利用反射弹计算器

方法一:

image-20241127141556697

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");
 评论
评论插件加载失败
正在加载评论插件
由 Hexo 驱动 & 主题 Keep
本站由 提供部署服务
总字数 15.4k 访客数 访问量