目录
Java反射机制
反射机制方法
指定构造方法生成实例
执行私有方法
首页 Java java教程 实例详解Java反序列化之反射机制

实例详解Java反序列化之反射机制

Mar 03, 2022 pm 05:45 PM
java

本篇文章给大家带来了关于java的相关知识,其中主要介绍了java反射机制的相关问题,动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制,希望对大家有帮助。

实例详解Java反序列化之反射机制

推荐学习:《java教程

每次听到大佬在讲或者看论坛等一些方式学java反序列化漏洞时,都会有一个词叫做反射机制,大佬顺势借着这个词,就给你造出一个payload,对于刚学java反序列化的我们,可能有点会懵圈,反正我是懵了,所以就赶紧学了一波,不然和大佬差距越来越大。所以这篇文章主要讲述java反射机制

Java反射机制

Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。

我不太擅长文字表达,还是上图操作把

不用反射机制的例子

//定义一个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();
    }}
登录后复制

这时候添加动物,只需要

  • 添加类
  • 修改zoo
  • 修改main函数的动物类

把上面修改为反射机制

//定义一个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();
    }}
登录后复制

这时候添加动物只需要

  • 添加类
  • 修改main函数的动物类

省了一步,传入类名可控,发现好像是存在的类都可以调

反射机制方法

我们用的最多的可能是

  • forName(调用类)
  • getMethod(调用类下方法)
  • invoke(执行)
  • newInstance(实例化对象)
Class.forName(className).getMethod(methodName).invoke(Class.forName(className).newInstance());
登录后复制

下面我们用反射机制来弹出计算机(calc)或者记事本(notepad)

由于弹出计算机有点多这次我就弹记事本把,总而言之,能弹出来就很美妙

Runtime.getRuntime().exec("notepad");
登录后复制

在这里插入图片描述
我们看下getRuntime函数
在这里插入图片描述
得知,该函数是Runtime类获取对象的方式,个人感觉是每用一次就调一次比较麻烦,为了不调用一次建立一个对象所以封装成了函数

类对象获取方式

  • Class.forName(类名获取)
  • zoo.class(已经加载过的类)
  • obj.class(实例)
    在这里插入图片描述

类初始化

修改zoo类,增加初始块、静态初始块、和构造函数

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;
    }}
登录后复制

类初始化执行顺序:静态初始块
在这里插入图片描述
类实例化执行顺序:静态初始块 - > 初始块 - > 构造函数
在这里插入图片描述
由此得知,类初始化和类实例化不一样

接下来增加zoo1类继承zoo类

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());
    }}
登录后复制

子类初始化顺序:父类静态初始化块 - > 子类静态初始化块
在这里插入图片描述
子类实例化顺序:父类静态初始化块 - > 子类静态初始化块 - > 父类初始化块 - > 父类构造函数 - > 子类初始化块 - >子类构造函数
在这里插入图片描述
以上可以得知,当使用Class.forName时,且类静态初始化块可控,可以执行任意代码

调用内部类

Class.forName(“java.lang.Runtime”)来获取类(java.lang.Runtime是Runtime类的完整路径)

getMethod

getMethod 的作用是通过反射获取类的某个特定的公有方法。
java支持类重载,但不能仅通过一个函数名确定一个函数,所以在调用getMethod时,需要传给它方法的参数类型列表
Class.forName(“java.lang.Runtime”).getMethod(“exec”, String.class)

invoke

静态和动态方法的区别
在这里插入图片描述

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");
登录后复制

在这里插入图片描述

指定构造方法生成实例

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”)));
在这里插入图片描述
这里可能有人会好奇我写的里那的另一个构造函数,String…command这个传参为什么用new String[][]{{“notepad”}},不应该是new String[]{“notepad”},现在用应该的

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

在这行打断点调试
在这里插入图片描述
我们传的是一个字符串数组到了实例化的时候变成了一个字符串,再看看另一个构造函数(List)

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

依旧还是这行打断点

在这里插入图片描述
由此可知,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视频教程

以上是实例详解Java反序列化之反射机制的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

Java 中的完美数 Java 中的完美数 Aug 30, 2024 pm 04:28 PM

Java 完美数指南。这里我们讨论定义,如何在 Java 中检查完美数?,示例和代码实现。

Java中的Weka Java中的Weka Aug 30, 2024 pm 04:28 PM

Java 版 Weka 指南。这里我们通过示例讨论简介、如何使用weka java、平台类型和优点。

Java 中的史密斯数 Java 中的史密斯数 Aug 30, 2024 pm 04:28 PM

Java 史密斯数指南。这里我们讨论定义,如何在Java中检查史密斯号?带有代码实现的示例。

Java Spring 面试题 Java Spring 面试题 Aug 30, 2024 pm 04:29 PM

在本文中,我们保留了最常被问到的 Java Spring 面试问题及其详细答案。这样你就可以顺利通过面试。

突破或从Java 8流返回? 突破或从Java 8流返回? Feb 07, 2025 pm 12:09 PM

Java 8引入了Stream API,提供了一种强大且表达力丰富的处理数据集合的方式。然而,使用Stream时,一个常见问题是:如何从forEach操作中中断或返回? 传统循环允许提前中断或返回,但Stream的forEach方法并不直接支持这种方式。本文将解释原因,并探讨在Stream处理系统中实现提前终止的替代方法。 延伸阅读: Java Stream API改进 理解Stream forEach forEach方法是一个终端操作,它对Stream中的每个元素执行一个操作。它的设计意图是处

Java 中的时间戳至今 Java 中的时间戳至今 Aug 30, 2024 pm 04:28 PM

Java 中的时间戳到日期指南。这里我们还结合示例讨论了介绍以及如何在java中将时间戳转换为日期。

Java程序查找胶囊的体积 Java程序查找胶囊的体积 Feb 07, 2025 am 11:37 AM

胶囊是一种三维几何图形,由一个圆柱体和两端各一个半球体组成。胶囊的体积可以通过将圆柱体的体积和两端半球体的体积相加来计算。本教程将讨论如何使用不同的方法在Java中计算给定胶囊的体积。 胶囊体积公式 胶囊体积的公式如下: 胶囊体积 = 圆柱体体积 两个半球体体积 其中, r: 半球体的半径。 h: 圆柱体的高度(不包括半球体)。 例子 1 输入 半径 = 5 单位 高度 = 10 单位 输出 体积 = 1570.8 立方单位 解释 使用公式计算体积: 体积 = π × r2 × h (4

如何在Spring Tool Suite中运行第一个春季启动应用程序? 如何在Spring Tool Suite中运行第一个春季启动应用程序? Feb 07, 2025 pm 12:11 PM

Spring Boot简化了可靠,可扩展和生产就绪的Java应用的创建,从而彻底改变了Java开发。 它的“惯例惯例”方法(春季生态系统固有的惯例),最小化手动设置

See all articles