反射

Chiexf Lv4

0x00 前言

最近在学习Java反序列化漏洞时,发现需要用到反射的知识,所以根据网上师傅们的文章,简单总结下反射的简单利用方法

0x01 什么是反射

  • 加载类,并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等)。

  • 可以破坏封装性

  • 假设有个Person类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class Person {
public String name;
private int age;

public Person(){
System.out.println("调用了无参构造器");
}
private Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("有参构造器执行了");
}

public String getName() {
return name;
}

public int getAge() {
return age;
}

public void setName(String name) {
this.name = name;
}

public void setAge(int age) {
this.age = age;
}

@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

0x02 获取Class类的方法

  • 加载类,获取类的字节码,其实就是操作类的Class对象。

获取Class的方法

类名.class

  • 已经加载的类,可以直接调用其class属性
1
Class<Person> personClass1 = Person.class;

Class.forName(“类名完整路径”)

  • 调用Class提供的方法
1
Class<?> pensonClass2 = Class.forName("org.example.Person");

对象.getClass()

  • Object提供的方法
1
2
Person person = new Person();
Class<? extends Person> personClass3 = person.getClass();

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 获取Class对象
*/
public class Reflection01 {
public static void main(String[] args) throws Exception {
//直接通用该类的Clas方法获取
Class<Person> personClass1 = Person.class;
System.out.println("personClass1 ---> " + personClass1);

//通过Class.forName(“全类名”)获取
Class<?> pensonClass2 = Class.forName("org.example.Person");
System.out.println("pensonClass2 ---> " + pensonClass2);

//通过该类的实例化对象获取
Person person = new Person();
Class<? extends Person> personClass3 = person.getClass();
System.out.println("personClass3 ---> " + personClass3);
}
}

输出结果:

1
2
3
personClass1 ---> class org.example.Person
pensonClass2 ---> class org.example.Person
personClass3 ---> class org.example.Person

0x03 获取类的构造器

获取某个构造器

getConstructor()

  • 只能获取public修饰的构造器
1
Constructor<Person> constructor1 = personClass.getConstructor();

getDeclaredConstructor()

  • 只要存在的构造器就能拿到

  • setAccessible设置为true即表示禁止检查访问控制。

1
2
Constructor<Person> declaredConstructor = personClass.getDeclaredConstructor(String.class, int.class);
declaredConstructor.setAccessible(true);

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* 获取类的构造器
*/
public class Reflection02 {
@Test
public void testReflection02() throws Exception {
//先获取这个类的Class对象
Class<Person> personClass = Person.class;

//获取某个构造器
System.out.println("----------------------getConstructor-------------------------------------------");

Constructor<Person> constructor = personClass.getConstructor();
System.out.println(constructor + "--->" + constructor.getParameterCount());


//获取private构造器
System.out.println("----------------------getDeclaredConstructor-----------------------------------");

Constructor<Person> declaredConstructor = personClass.getDeclaredConstructor(String.class, int.class);
declaredConstructor.setAccessible(true);
System.out.println(declaredConstructor + "--->" + declaredConstructor.getParameterCount());
}
}
  • 输出结果
1
2
3
4
----------------------getConstructor-------------------------------------------
public org.example.Person()--->0
----------------------getDeclaredConstructor-----------------------------------
private org.example.Person(java.lang.String,int)--->2

获取全部构造器

getConstructors()

  • 只能获取public修饰的构造器
1
Constructor<?>[] constructors = personClass.getConstructors();

getDeclaredConstructors()

  • 只要存在就能拿到
1
Constructor<?>[] declaredConstructors = personClass.getDeclaredConstructors();

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
* 获取类的构造器
*/
public class Reflection02 {
@Test
public void testReflection02() throws Exception {
//先获取这个类的Class对象
Class<Person> personClass = Person.class;

//获取全部public构造器
System.out.println("----------------------getConstructors------------------------------------------");

Constructor<?>[] constructors = personClass.getConstructors();
for (Constructor<?> constructor1 : constructors) {
System.out.println(constructor1 + "--->" + constructor1.getParameterCount());
}

//获取全部构造器
System.out.println("----------------------getDeclaredConstructors----------------------------------");

Constructor<?>[] declaredConstructors = personClass.getDeclaredConstructors();
for (Constructor<?> declaredConstructor1 : declaredConstructors) {
System.out.println(declaredConstructor1 + "--->" + declaredConstructor1.getParameterCount());
}
}
}

  • 输出结果
1
2
3
4
5
----------------------getConstructors------------------------------------------
public org.example.Person()--->0
----------------------getDeclaredConstructors----------------------------------
public org.example.Person()--->0
private org.example.Person(java.lang.String,int)--->2

初始化对象

newInstance()

  • class.newInstance() 只能反射无参构造器,且构造器是可见的
  • constructor.newInstance() 没有限制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* 实例化构造器对象
*/
public class Reflection03 {
@Test
public void testReflection() throws Exception {
//先获取这个类的Class对象
Class<Person> personClass = Person.class;

//获取某个构造器
System.out.println("----------------------getConstructor-------------------------------------------");

Constructor<Person> constructor1 = personClass.getConstructor();
System.out.println(constructor1 + "--->" + constructor1.getParameterCount());

//初始化对象
Person person = constructor1.newInstance();
System.out.println(person);

//获取private构造器
System.out.println("----------------------getDeclaredConstructor-----------------------------------");

Constructor<Person> declaredConstructor = personClass.getDeclaredConstructor(String.class, int.class);
declaredConstructor.setAccessible(true);
System.out.println(declaredConstructor + "--->" + declaredConstructor.getParameterCount());

//初始化对象
Person person1 = declaredConstructor.newInstance("小明", 12);
System.out.println(person1);
}
}
  • 输出结果
1
2
3
4
5
6
7
8
----------------------getConstructor-------------------------------------------
public org.example.Person()--->0
调用了无参构造器
Person{name='null', age=0}
----------------------getDeclaredConstructor-----------------------------------
private org.example.Person(java.lang.String,int)--->2
有参构造器执行了
Person{name='小明', age=12}

0x04 获取成员变量

获取某个成员变量

getField()

  • 只能获取public修饰的
1
Field field = personClass.getField("name");

getDeclaredField()

  • 只要存在就能获取
1
2
Field declaredField = personClass.getDeclaredField("age");
declaredField.setAccessible(true);

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* 获取Class对象的成员变量
*/
public class Reflection04 {
@Test
public void testReflection() throws Exception {
//获取类的Class对象
Class<Person> personClass = Person.class;

//获取类的某个成员变量
System.out.println("----------------------getField-------------------------------------------");

Field field = personClass.getField("name");
System.out.println(field);

//获取private的成员变量
System.out.println("----------------------getDeclaredField-------------------------------------------");

Field declaredField = personClass.getDeclaredField("age");
declaredField.setAccessible(true);
System.out.println(declaredField);
}
}

  • 输出结果
1
2
3
4
----------------------getField-------------------------------------------
public java.lang.String org.example.Person.name
----------------------getDeclaredField-------------------------------------------
private int org.example.Person.age

获取全部成员变量

getFields()

  • 只能获取public修饰的
1
Field[] fields = personClass.getFields();

getDeclaredFields()

  • 只要存在就能获取
1
Field[] declaredFields = personClass.getDeclaredFields();

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* 获取Class对象的成员变量
*/
public class Reflection04 {
@Test
public void testReflection() throws Exception {
//获取类的Class对象
Class<Person> personClass = Person.class;

//获取全部public修饰的成员变量
System.out.println("----------------------getFields-------------------------------------------");

Field[] fields = personClass.getFields();
for (Field field1 : fields) {
System.out.println(field1);
}

//获取全部的成员变量
System.out.println("----------------------getDeclaredFields-------------------------------------------");

Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField1 : declaredFields) {
System.out.println(declaredField1);
}
}
}
  • 输出
1
2
3
4
5
----------------------getFields-------------------------------------------
public java.lang.String org.example.Person.name
----------------------getDeclaredFields-------------------------------------------
public java.lang.String org.example.Person.name
private int org.example.Person.age

赋值和取值

  • set(Object obj, Object value)
  • get(Object obj)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
* 赋值和取值
*/
public class Reflection05 {
@Test
public void testReflection() throws Exception {
//获取类的Class对象
Class<Person> personClass = Person.class;

//获取类的某个成员变量
Field name = personClass.getField("name");
// System.out.println(field);

//获取private的成员变量
Field age = personClass.getDeclaredField("age");
age.setAccessible(true);
// System.out.println(declaredField);

//赋值
Person person = new Person();
name.set(person,"小明");

age.set(person,12);
age.setAccessible(true);
System.out.println(person);

//取值
Object name1 = name.get(person);
System.out.println(name1);
Object age1 = age.get(person);
System.out.println(age1);
}
}
  • 输出结果
1
2
3
4
调用了无参构造器
Person{name='小明', age=12}
小明
12

0x05 获取成员方法

  • 在Person类中添加
1
2
3
4
5
6
7
private void run(){
System.out.println("喜欢跑步");
}

public String eat(String foodname){
return "喜欢吃" + foodname ;
}

获取某个方法

getMethod()

  • 只能获取public修饰恶毒成员方法

getDeclaredMethod()

  • 只要存在就能拿到

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 获取成员方法
*/
public class Reflection06 {
@Test
public void testReflction() throws Exception {
//获取Class对象
Class<Person> personClass = Person.class;

//获取某个public成员方法
System.out.println("----------------------getMethod---------------------------------------------------");

Method eat = personClass.getMethod("eat",String.class);
System.out.println(eat);

//获取private成员方法
System.out.println("----------------------getDeclaredMethod-------------------------------------------");

Method run = personClass.getDeclaredMethod("run");
System.out.println(run);
}
}
  • 输出结果
1
2
3
4
----------------------getMethod---------------------------------------------------
public java.lang.String org.example.Person.eat(java.lang.String)
----------------------getDeclaredMethod-------------------------------------------
private void org.example.Person.run()

获取全部方法

getMethods()

  • 只能获取public修饰的成员方法

getDeclaredMethods()

  • 只要存在都能拿到

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* 获取成员方法
*/
public class Reflection06 {
@Test
public void testReflction() throws Exception {
//获取Class对象
Class<Person> personClass = Person.class;

//获取全部public成员方法
System.out.println("----------------------getMethods--------------------------------------------------");

Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}

//获取全部成员方法
System.out.println("----------------------getDeclaredMethods------------------------------------------");

Method[] declaredMethods = personClass.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
}
}
  • 输出结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
----------------------getMethods--------------------------------------------------
public java.lang.String org.example.Person.toString()
public java.lang.String org.example.Person.getName()
public void org.example.Person.setName(java.lang.String)
public java.lang.String org.example.Person.eat(java.lang.String)
public int org.example.Person.getAge()
public void org.example.Person.setAge(int)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
----------------------getDeclaredMethods------------------------------------------
private void org.example.Person.run()
public java.lang.String org.example.Person.toString()
public java.lang.String org.example.Person.getName()
public void org.example.Person.setName(java.lang.String)
public java.lang.String org.example.Person.eat(java.lang.String)
public int org.example.Person.getAge()
public void org.example.Person.setAge(int)

执行成员方法

invoke()

  • 调用某个类中的方法
  • 如果这个方法是一个普通方法,那么第一个参数是类对象
  • 如果这个方法是一个静态方法,那么第一个参数是
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* 执行成员方法
*/
public class Reflection07 {

@Test
public void testReflction() throws Exception {
//获取Class对象
Class<Person> personClass = Person.class;

//获取某个public成员方法
Method eat = personClass.getMethod("eat",String.class);
// System.out.println(eat);

//获取private成员方法
Method run = personClass.getDeclaredMethod("run");
// System.out.println(run);

Person person = new Person();

run.setAccessible(true);
Object run1 = run.invoke(person,null);
System.out.println(run1);

Object eat1 = (Object) eat.invoke(person, "鱼");
System.out.println(eat1);
}
}
  • 输出结果
1
2
3
4
调用了无参构造器
喜欢跑步
null
喜欢吃鱼

0x06 Runtime命令执行

普通调用

1
2
3
4
5
6
7
public class Exec {
public static void main(String[] args) throws Exception {
Runtime.getRuntime().exec("calc");
}
}

//弹出计算机

反射调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Exec {
public static void main(String[] args) throws Exception {
// Runtime.getRuntime().exec("calc");

//得到 Class 对象
Class<?> runtimeClass = Class.forName("java.lang.Runtime");
//得到 getRuntime 方法
Method getRuntime = runtimeClass.getMethod("getRuntime");
//调用 Runtime.getRuntime() 方法,得到 Runtime 对象
Object Runtime = getRuntime.invoke(runtimeClass);
//得到 exec 方法
Method exec = runtimeClass.getMethod("exec", String.class);
exec.invoke(Runtime,"calc.exe");

}
}

//弹出计算机

0x07 ProcessBuilder命令调用

普通调用

1
2
3
4
5
6
7
8
9
public class ProcessBuilder {
public static void main(String[] args) throws Exception {
//利用 ProcessBuilder 进行命令执行
java.lang.ProcessBuilder processBuilder = new java.lang.ProcessBuilder("calc.exe");
Process start = processBuilder.start();
}
}

//弹出计算机

反射调用

  • ProcessBuilder(List command)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ProcessBuilder {
public static void main(String[] args) throws Exception {
//利用 ProcessBuilder 进行命令执行
//获取 Class 对象
Class<?> ProcessBuilder = Class.forName("java.lang.ProcessBuilder");
//获取构造器方法
Constructor<?> constructor = ProcessBuilder.getConstructor(List.class);

//Arrays.asList()用于将一个数组转换成List对象
Object calc = constructor.newInstance(Arrays.asList("calc"));

//获取成员方法
Method start = ProcessBuilder.getMethod("start");

start.invoke(calc);
}
}

//弹出计算机
  • public ProcessBuilder(String… command)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class ProcessBuilder {
public static void main(String[] args) throws Exception {
//利用 ProcessBuilder 进行命令执行
//获取 Class 对象
Class<?> processBuilder = Class.forName("java.lang.ProcessBuilder");

//获取构造器方法
Constructor<?> constructor = processBuilder.getConstructor(String[].class);

//可变长参数在编译时会编译成一个数组
//newInstance也是接受一个可变长参数
//二者叠加为一个二维数组
Object calc = constructor.newInstance(new String[][]{{"calc"}});

//获取start方法
Method start = processBuilder.getMethod("start");

//执行方法
start.invoke(calc);
}
}

//弹出计算机