前言

不得不开始系统化的学习一下java了,之前搞过java的简单开发,也零散的学了一些java的漏洞,但终究不够系统。综合网上的资料,进行一个系统的学习还是很有必要的。

java反射机制

反射允许java在运行期间借助ReflectionAPI取得任何类的内部消息,并能直接操作任意对象的内部属性和方法。
正常方式:

反射:

java中获取类的方法:

  1. 直接通过一个class的静态变量class获取:
    Class cls = String.class;
  2. 通过该实例变量提供的getClass()方法获取
    String s = "eval";
    Class cls = s.getClass();
  3. 知道一个class的完整类名,可以通过静态方法Class.forName()获取
    Class cls = Class.forName("java.lang.String");

java.lang.Runtime因为有一个exec方法可以执行本地命令,我们常使用反射去获取exec方法来执行命令

正常使用:

// 输出命令执行结果
System.out.println(IOUtils.toString(Runtime.getRuntime().exec("whoami").getInputStream(), "UTF-8"));

使用反射:

// 获取Runtime类对象
Class runtimeClass1 = Class.forName("java.lang.Runtime");

// 获取构造方法
Constructor constructor = runtimeClass1.getDeclaredConstructor();
constructor.setAccessible(true);

// 创建Runtime类示例,等价于 Runtime rt = new Runtime();
Object runtimeInstance = constructor.newInstance();

// 获取Runtime的exec(String cmd)方法
Method runtimeMethod = runtimeClass1.getMethod("exec", String.class);

// 调用exec方法,等价于 rt.exec(cmd);
Process process = (Process) runtimeMethod.invoke(runtimeInstance, cmd);

// 获取命令执行结果
InputStream in = process.getInputStream();

// 输出命令执行结果
System.out.println(IOUtils.toString(in, "UTF-8"));

简化一下:

Class.forName("java.lang.Runtime").getMethod("exec", String.class).invoke(Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(Class.forName("java.lang.Runtime")),"calc");

反射调用类方法

Class对象提供了一个个获取某个类的所有的成员方法的方法,也可以通过方法名和方法参数类型来获取指定成员方法。

  • Method getMethod(name, Class...):获取某个public的Method(包括父类)
  • Method getDeclaredMethod(name, Class...):获取当前类的某个Method(不包括父类)
  • Method[] getMethods():获取所有public的Method(包括父类)
  • Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)

获取到java.lang.reflect.Method对象以后我们可以通过Method的invoke方法来调用类方法。

method.invoke(方法实例对象, 方法参数值,多个参数值用","隔开);

如果调用static方法,那第一个参数传null,因为在 java 中调用静态方法是不需要有类实例的,可以直接类名.方法名(参数)的方式调用

// 获取Integer.parseInt(String)方法,参数为String:
Method m = Integer.class.getMethod("parseInt", String.class);
// 调用该静态方法并获取结果:
Integer n = (Integer) m.invoke(null, "23333");
System.out.println(n);

第二个参数,若该方法无参,可以不传

例子:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class test {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        String name = "Kitsch";
        Method substring = String.class.getMethod("substring", int.class);
        System.out.println(substring.invoke(name,4));
    }
}

反射调用成员变量

  • Field fields = clazz.getDeclaredFields(); : 获取当前类所有成员变量
  • Field field = clazz.getDeclaredField("变量名"); : 获取当前类的制定成员变量
  • Object obj = field.get(类实例对象); : 获取成员变量值
  • field.set(类实例对象, 修改后的值); : 修改成员变量值
  • field.setAccessible(true) : 反射时访问私有变量

如果我们要修改修饰词为final的成员变量

// 反射获取Field类的modifiers
Field modifiers = field.getClass().getDeclaredField("modifiers");

// 设置modifiers修改权限
modifiers.setAccessible(true);

// 修改成员变量的Field对象的modifiers值
modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);

// 修改成员变量值
field.set(类实例对象, 修改后的值);

"孓然一身 , 了无牵挂"