Home  >  Article  >  Java  >  Detailed explanation of the reflection mechanism of Java deserialization with examples

Detailed explanation of the reflection mechanism of Java deserialization with examples

WBOY
WBOYforward
2022-03-03 17:45:151848browse

This article brings you relevant knowledge about java, which mainly introduces issues related to the reflection mechanism of java. The function of dynamically obtaining program information and dynamically calling objects is called reflection of the Java language. Mechanism, I hope it will be helpful to everyone.

Detailed explanation of the reflection mechanism of Java deserialization with examples

Recommended study: "java tutorial"

Every time I hear a big guy talking or watch forums and other ways to learn java When deserializing vulnerabilities, there is a word called reflection mechanism. The boss uses this word to create a payload for you. For those of us who have just learned Java deserialization, we may be a little confused. Anyway, I am confused. , so I quickly learned a lesson, otherwise the gap between me and the big guys will become wider and wider. So this article mainly talks about the java reflection mechanism

Java reflection mechanism

Java's reflection (reflection) mechanism means that in the running state of the program, objects of any class can be constructed, and you can understand The class to which any object belongs can understand the member variables and methods of any class, and can call the properties and methods of any object. This function of dynamically obtaining program information and dynamically calling objects is called the reflection mechanism of the Java language. Reflection is seen as the key to dynamic languages.

I’m not very good at expressing myself in words, so let’s use the above picture to illustrate

an example of not using the reflection mechanism

//定义一个animals接口interface animals {
    public abstract void print();}//定义类来实现animals接口的抽象方法class Dog implements animals {
    public void print() {
        System.out.println("Dog");
    }}class Cat implements animals {
    public void print() {
        System.out.println("Cat");
    }}// 构造一个zoo类// 之后如果我们在添加其他的实例的时候只需要修改zoo类class zoo {

    public static animals getInstance(String animalsName) {
        animals a = null;
        if ("Dog".equals(animalsName)) {
            a = new Dog();
        }
        if ("Cat".equals(animalsName)) {
            a = new Cat();
        }
        return a;
    }}public class reflection {
    public static void main(String[] args) {
        //借助zoo类寻找对应的类来实现接口
        animals a=zoo.getInstance("Cat");
        if(a!=null)
            a.print();
    }}

To add animals at this time, just

  • Add class
  • Modify zoo
  • Modify the animal class of the main function

Modify the above to the reflection mechanism

//定义一个animals接口interface animals {
    public abstract void print();}//定义类来实现animals接口的抽象方法class Dog implements animals {
    public void print() {
        System.out.println("Dog");
    }}class Cat implements animals {
    public void print() {
        System.out.println("Cat");
    }}// 构造一个zoo类// 之后如果我们在添加其他的实例的时候只需要修改zoo类class zoo {

    public static animals getInstance(String className) {
        animals a = null;
        try {
            //借助Class.forName寻找类名,并用newInstance实例化类似于new
            a = (animals) Class.forName(className).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return a;
    }}public class reflection {
    public static void main(String[] args) {
        //借助zoo类寻找对应的类来实现接口(classname为当前包名加类名)
        animals a = zoo.getInstance("com.cc1.Dog");
        if (a != null)
            a.print();
    }}

Add animals at this time Just need to

  • Add a class
  • Modify the animal class of the main function

It saves a step, the incoming class name is controllable, and it seems to exist Classes can adjust

Reflection mechanism methods

The ones we use most are probably

  • forName (calling class)
  • getMethod (calling class Method below)
  • invoke (execution)
  • newInstance (instantiated object)
Class.forName(className).getMethod(methodName).invoke(Class.forName(className).newInstance());

Below we use the reflection mechanism to pop up the computer (calc) or notepad ( notepad)

Since there are a lot of pop-ups on the computer, I will just play Notepad this time. All in all, it’s great to be able to pop it up

Runtime.getRuntime().exec("notepad");

Detailed explanation of the reflection mechanism of Java deserialization with examples
Let’s take a look at the getRuntime function
Detailed explanation of the reflection mechanism of Java deserialization with examples
I learned that this function is the way for the Runtime class to obtain objects. Personally, I feel that it is troublesome to call it every time. In order not to call it once to create an object, it is encapsulated into a function

How to obtain class objects

  • Class.forName (obtain class name)
  • zoo.class (already loaded class)
  • obj .class (instance)
    Detailed explanation of the reflection mechanism of Java deserialization with examples

Class initialization

Modify the zoo class, add initial block, static initial block, and constructor

class zoo {
    //初始块
    {
        System.out.println("1  " + this.getClass());
    }

    //静态初始块
    static {
        System.out.println("2  " + zoo.class);
    }

    public zoo() {
        System.out.println("3  " + this.getClass());
    }

    public static animals getInstance(String className) {
        animals a = null;
        try {
            //借助Class.forName寻找类名,并用newInstance实例化类似于new
            a = (animals) Class.forName(className).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return a;
    }}

Class initialization execution sequence: Static initial block
Detailed explanation of the reflection mechanism of Java deserialization with examples
Class instantiation execution sequence: Static initial block-> Initial block- > Constructor
Detailed explanation of the reflection mechanism of Java deserialization with examples
From this we know that class initialization and class instantiation are different

Next add the zoo1 class to inherit the zoo class

class zoo1 extends zoo{
    //初始块
    {
        System.out.println("11  " + this.getClass());
    }

    //静态初始块
    static {
        System.out.println("12  " + zoo.class);
    }

    public zoo1() {
        System.out.println("13  " + this.getClass());
    }}

Subclass initialization sequence: Parent class static initialization block - > Subclass static initialization block
Detailed explanation of the reflection mechanism of Java deserialization with examples
Subclass instantiation sequence: Parent class Static initialization block - > Subclass static initialization block - > Parent class initialization block - > Parent class constructor - > Subclass initialization block - > Subclass constructor
Detailed explanation of the reflection mechanism of Java deserialization with examples
It can be known from the above that when Class.forName is used and the class static initialization block is controllable, any code can be executed

Call the internal class

Class.forName("java.lang.Runtime") to get the class (java.lang.Runtime is the full path of the Runtime class)

getMethod

The function of getMethod is to obtain a specific public method of the class through reflection.
Java supports class overloading, but a function cannot be determined by just a function name, so when calling getMethod, a list of parameter types needs to be passed to its method
Class.forName("java.lang.Runtime") .getMethod(“exec”, String.class)

invoke

静态和动态方法的区别
Detailed explanation of the reflection mechanism of Java deserialization with examples

invoke方法在getMethod类下,作用时传递参数,执行方法
public Object invoke(Object obj, Object… args)
第一个参数是getMethod获取的方法的类对象(如果方法是静态方法则传类)
获取exec函数的类对象
Class.forName(“java.lang.Runtime”).getMethod(“getRuntime”).invoke(Class.forName(“java.lang.Runtime”))
由于getRuntime是静态方法,所以传类
invoke(Class.forName(“java.lang.Runtime”).getMethod(“getRuntime”).invoke(Class.forName(“java.lang.Runtime”)),“calc.exe”)

最后我们合并一下

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

Detailed explanation of the reflection mechanism of Java deserialization with examples

指定构造方法生成实例

String str="notepad";ProcessBuilder pb = new ProcessBuilder(str);pb.start();

getConsturctor(函数可以选定指定接口格式的构造函数(由于构造函数也可以根据参数来进行重载)
选定后我们可以通过newInstance(),并传入构造函数的参数执行构造函数

ProcessBuilder类有两个构造函数

  • public ProcessBuilder(String… command)(String…变长的字符串数组String[].class)
  • public ProcessBuilder(List command)

分别使用构造方法

  • Class.forName(“java.lang.ProcessBuilder”).getConstructor(String[].class).newInstance(new String[][]{{“notepad”}})
  • Class.forName(“java.lang.ProcessBuilder”).getConstructor(List.class).newInstance(Arrays.asList(“notepad”))

执行完构造方法实例后,在进行强制转化使用start函数即可

( (ProcessBuilder) Class.forName(“java.lang.ProcessBuilder”).getConstructor(List.class).newInstance(Arrays.asList(“notepad”))).start();

实际中,肯定用不了,哪有这么好的事,还是接着反射把

Class.forName(“java.lang.ProcessBuilder”).getMethod(“start”).invoke(clazz.getConstructor(List.class).newInstance(Arrays.asList(“notepad”)));
Detailed explanation of the reflection mechanism of Java deserialization with examples
这里可能有人会好奇我写的里那的另一个构造函数,String…command这个传参为什么用new String[][]{{“notepad”}},不应该是new String[]{“notepad”},现在用应该的

((ProcessBuilder) Class.forName(“java.lang.ProcessBuilder”).getConstructor(String[].class).newInstance(new String[]{“notepad”})).start();

在这行打断点调试
Detailed explanation of the reflection mechanism of Java deserialization with examples
我们传的是一个字符串数组到了实例化的时候变成了一个字符串,再看看另一个构造函数(List)

( (ProcessBuilder) Class.forName(“java.lang.ProcessBuilder”).getConstructor(List.class).newInstance(Arrays.asList(“notepad”))).start();

依旧还是这行打断点

Detailed explanation of the reflection mechanism of Java deserialization with examples
由此可知,List传入时会被当作Object的第一项,而String[]会被当做Object,所以多加一层[]{}

执行私有方法

通过函数getDeclaredConstructor获取私有方法,再利用setAccessible(true)打破私有方法限制

Class cls = Class.forName("java.lang.Runtime"); 
Constructor m = cls.getDeclaredConstructor();
 m.setAccessible(true); 
 cls.getMethod("exec", String.class).invoke(m.newInstance(), "notepad");

 推荐学习:《java视频教程

The above is the detailed content of Detailed explanation of the reflection mechanism of Java deserialization with examples. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:csdn.net. If there is any infringement, please contact admin@php.cn delete