反射基本使用

0x01 Preface

Java作为一门静态语言,编译时变量的数据类型已经确定。反射给Java带来了一定的动态性。

“以铜为镜,可以正衣冠”

以反射为镜,照之对象可得类,照之类可得属性方法,皆可访达

0x02 Basic Usage Of Reflect

现有一类Person:

package com.demo;

public class Person {
    public String name;
    private Integer age;

    public Person(){}
    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    private void action(String move) {
        System.out.println(move + ' ' +this.age);
    }

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

获取类

欲获java.lang.Class对象,如下三法:

  • Class.forName:传之类名,无需import

  • obj.getClass():上下文该类实例存矣

  • Person.class:类已加载,直捣class属性

三者hashCode无异,同一Class对象也

获取属性和方法

既获之类,进而获之属性与方法,实例之。

  • getMethod获当前类的public方法(包括从父类继承的方法)

  • getDeclaredMethod获当前类实打实定义的方法,包括private方法(不包括从父类继承的方法)

getFieldgetDeclaredField同理。若加上s 表示获取所有的方法或属性

  • getMethod(String name, Class<?>... parameterTypes)

    面向对象支持重载机制,因此获取方法的时候不仅要指定方法名,还得指定参数的类型 ...表示可变长参数,Java底层会将其封装为一个数组 这边可以传多个参数,也可以直接传数组 如new Class[]{A.class, B.class}

  • method.invoke(Object obj, Object... args) 若method是一个普通方法,则第一个参数是类对象 若method是一个静态方法,则第一个参数是类或null 第二个参数也是可变长参数,传入method所需的参数

修改常量

思路很简单,就是修改modifier,modifier是Field类的属性

成功打印success,不存在Serial VersionID的问题

0x03 Best Practice

下面利用反射来实现命令执行

java.lang.Runtime

这个类是设计为单例模式的。 在Web开发中,数据库只需连接一次,下次需要用到数据库时,为避免重复连接,只要拿到数据库连接对象即可,所以数据库连接类或许是下面这样的(单例模式)

这样类在初始化的时候就执行会建立连接,执行构造函数,我们通过getDBConnector 获取数据库连接对象,避免多次进行连接。

java.lang.Runtime的构造方法是私有的,但是却有一个公开方法getRuntime()来获取Runtime对象。

也可以获取Runtime的私有构造器去构造Runtime对象

java.lang.ProcessBuilder

除了Runtime.exec()ProcessBuilder.start()是另外一种命令执行的方式。

java.lang.ProcessBuilder有两个构造函数

public ProcessBuilder(List command)

public ProcessBuilder(String... command)

由于newInstance接受的是一个可变长的Object类型参数,可以传入无限个参数或者只传一个数组,因此第二个构造中,传入的是new String[][]{{"calc"}},如果传的是new String[]{"calc"},经过newInstance的这层解析后,传入start的就是字符串calc。可以理解为前者传的是new Object[]{new String[]{"calc"}}

0x04 Summary

本文介绍了反射的如下使用

  • 动态实例化对象

  • 动态调用方法

  • 操作类内部私有属性和方法

  • 修饰常量

还提到了java.lang.Runtime的单例设计模式,类对象会在类初始化时创建,类对外提供getXxx的静态方法来获取类对象,因此每次获取到的对象都为同一个,故名为单例模式。并通过反射来调用的RuntimeProcessBuilder的命令执行方法。

反射在反序列化漏洞中的应用

  • 通过invoke调用除了同名函数以外的函数

  • 创建对象,引入不能序列化的类(比如传入Runtime.class)

Last updated

Was this helpful?