自定义ClassLoader如何绕过双亲委派机制

Java安全——JVM类加载器 Java类加载机制在Java安全知识体系中有着非常重要的地位,早在之前分析Shiro反序列化漏洞利用,以及学习蚁剑Java马,都和Java ClassLoader打过交道。笔者打算从把ClassLoader的原理、使用场景、自定义方式等多个方面剖析类加载器在Java安全中设计到的知识。 0x01 ClassLoader 简介 Java语言需要把代码编译成class文件,才能用JVM加载执行,那么ClassLoader就是负责将class文件加载到内存,生成对应的类。 0x1 ClassLoader.. 阅读详情

双亲委派机制指的是加载类时,会首先从其父加载器中去加载类,如果加载不到,再从当前类加载器中去加载类。这样的目的就是为了防止我们自定义的一些类覆盖掉启动时的一些核心类。

不过,有些场景下,我们想要从自定义的类加载器中加载类时(比如自定义加载器和父加载器加载的是磁盘上两个不同目录下的类文件时,如果此时二者目录下都放置着同名的类文件,就会发生覆盖),这个机制就会给我们带来很大的问题。

解决办法:自定义类加载器,开放findClass()方法,直接调用findClass()方法进行加载。

理由:ClassLoader类里面的loadClass()方法实际上是先通过父加载器加载,再通过子加载器加载。

此时,如果我们直接调用子加载器的findClass()方法,就可以绕过ClassLoader类loadClass()方法的双亲委派机制代码逻辑。

自定义加载类:

public class CustomerWebAppClassLoader extends URLClassLoader {
    public CustomerWebAppClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
    }

    public CustomerWebAppClassLoader(URL[] urls) {
        super(urls);
    }

    public CustomerWebAppClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) {
        super(urls, parent, factory);
    }

    /**
     * 将findClass()方法开放(findClass()方法本身是protected类型的,不能在外界直接访问),直接调用以获取class,绕过双亲委派机制。
     * @param name
     * @return
     * @throws ClassNotFoundException
     */
    @Override
    public Class<?> findClass(final String name) throws ClassNotFoundException {
        return super.findClass(name);
    }
}

调用加载:

Class<?> aClass = classLoader.findClass(className);

附录:以下,贴出从某个根路径下加载所有的类文件的代码。

以下代码参考于https://www.cnblogs.com/umgsai/p/11918520.html,在其基础上就绕过双亲委派机制做了一点微调。希望能对大家有所帮助。

public static Set<Class<?>> loadClasses(String rootClassPath, CustomerWebAppClassLoader classLoader) throws Exception {
        Set<Class<?>> classSet = new HashSet();
        // 设置class文件所在根路径
        File clazzPath = new File(rootClassPath);

        // 记录加载.class文件的数量
        int clazzCount = 0;

        if (clazzPath.exists() && clazzPath.isDirectory()) {
            // 获取路径长度
            int clazzPathLen = clazzPath.getAbsolutePath().length() + 1;

            Stack<File> stack = new Stack<>();
            stack.push(clazzPath);

            // 遍历类路径
            while (!stack.isEmpty()) {
                File path = stack.pop();
                File[] classFiles = path.listFiles(new FileFilter() {
                    @Override
                    public boolean accept(File pathname) {
                        //只加载class文件
                        return pathname.isDirectory() || pathname.getName().endsWith(".class");
                    }
                });
                if (classFiles == null) {
                    break;
                }
                for (File subFile : classFiles) {
                    if (subFile.isDirectory()) {
                        stack.push(subFile);
                    } else {
                        if (clazzCount++ == 0) {
                            Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
                            boolean accessible = method.isAccessible();
                            try {
                                if (!accessible) {
                                    method.setAccessible(true);
                                }
                                // 设置类加载器(从外面传入,每一个context应用各自独立一个classLoader)
                                //URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
                                // 将当前类路径加入到类加载器中
                                method.invoke(classLoader, clazzPath.toURI().toURL());
                            } catch (Exception e) {
                                e.printStackTrace();
                            } finally {
                                method.setAccessible(accessible);
                            }
                        }
                        // 文件名称
                        String className = subFile.getAbsolutePath();
                        className = className.substring(clazzPathLen, className.length() - 6);
                        //将/替换成. 得到全路径类名
                        className = className.replace(File.separatorChar, '.');
                        // 加载Class类,此处直接调用findClass()方法,
                        Class<?> aClass = classLoader.findClass(className);
                        classSet.add(aClass);
                    }
                }
            }
        }
        return classSet;
    }

调用时代码:

CustomerWebAppClassLoader customerWebAppClassLoader = new CustomerWebAppClassLoader(new URL[]{});
Set<Class<?>> classes = loadClasses(mergedRootPath,customerWebAppClassLoader);

 

使用URLClassLoader加载本地文件夹c盘下的test.jar文件 立即下载

相关推荐

细说Tomcat如何打破双亲委派(有源码和图)

NULL 博文链接:https://flyfoxs.iteye.com/blog/2114149

4、类加载及双亲委派及如何打破双亲委派

一、概述 1、JVM内存结构 二、类加载器 1、介绍 2、类加载器ClassLoader角色 3、类加载器分类 4、引导、扩展、系统【类加载器】 5、用户自定义类加载器 6、ClassLoader 7、双亲委派机制 8、沙箱安全机制 9、其他 三、类的加载过程 1、加载过程 2、Loaing(加载) 3、Linking(链接) 4、Initialization(初始化)

爱欧米 1069

Android Display Graphics #1 整体框架介绍一

手机屏上显示的内容,2D或3D ,如果是 3D 的,不管是 App 还是游戏,或者简单的图片界面,底层都是通过 GPU、 通过 OpenGL(ES)绘制出来的。是Java层的一个类,提供了一系列API,使用这些API可以实现各种的产品经理要求的效果。显示的不同阶段对这块内存的叫法不同,在上层可以是Window、ANnativeWindow、Surface、SurfaceView、layer、buffer,这些本质上没啥区别,可以广泛意义上理解为用于显示内容的那块内存,只不过各个阶段的操作接口不同。

oDwyane03的博客 1387

一次尝试绕过ClassLoader双亲委派的实验

一、文章来由来阿里玩Java也有一个多月了,一直对Java虚拟机比较感兴趣,而ClassLoader是整个class载入过程中很重要的组件。而classloader有个双亲委派模型,师兄说这个模型不能破坏,于是打赌一试。相信如果问:为什么要双亲委派,可能有人可以侃侃而谈,但是说到为什么要这么分层,为什么要分三层,如何绕过双亲委派模型。。。这就不是那么容易了,这个时候就需要一些专研了。二、classl

This is bill的专属博客 5559

BODAS说明书的中文版与相关资料总结

花了三天时间配了控制器的接线口,找了软件安装的一套东西。 又花了一周时间零零散散在网上只找到关于控制器少得可怜的资料: 1.力士乐控制器RC6系列介绍 2.力士乐控制器手册不完整版 3.RC6-9程序下载 力士乐配套的只有德语和英语两版,人工翻译专业文件的价格太惊人,决定自己写一版方便大家。有不正之处欢迎指出。 For these controllers, in the event of an...

我的技术日常 6495

淘宝电商产品价格官方防爬取采集设计机制,如何破?|淘宝电商API数据采集看完你也会!

然而,随着电子商务的蓬勃发展,涌现出大量的第三方工具和应用,试图通过采集淘宝电商产品价格等信息来进行数据分析和竞争优势的获取。为了维护市场秩序和保护商家权益,淘宝采取了一系列的防爬取设计机制,以阻止非授权的数据采集行为。为了确保数据的准确性和及时性,淘宝采取了多层次的防爬取机制,以限制未经授权的数据采集。其它的情况,比如淘宝首页、淘宝关键词商品搜索结果页面、商品详情页面,都是正常展示,未实现加密;也可以使用【tesseract ocr识别】指令,这个是免费无限使用的;【淘宝商品搜索结果页面-本地截图】

TinagirlAPI的博客 1388

java-如何打破双亲委派机制

在Java虚拟机(JVM)中,双亲委派模型是一种类加载器之间的层次模型,它定义了类加载的规则,即当一个类需要被加载时,JVM默认的行为是首先请求父类加载器加载该类,只有当父类加载器无法加载该类时,才由自己来加载。1. **SPI(Service Provider Interface)**:Java的SPI机制允许第三方为接口提供实现,而这些实现类通常是由不同的类加载器加载的,如果坚持双亲委派模型,将无法加载这些实现类。- **兼容性**:不同类加载器加载的类可能存在版本不兼容的问题。

weixin_41247813的博客 743

Windows 下安装 Hermes Agent 完整教程(含踩坑记录)

不支持原生 Windows,必须通过 WSL2 (Windows Subsystem for Linux 2) 运行。WSL2 是 Windows 内置的 Linux 兼容层,可以在 Windows 上运行完整的 Linux 环境。

weixin_50191542的博客 4280

ClassLoader的理解与双亲委派机制和违反双亲委派

这里大量参考了如下博客 https://blog.youkuaiyun.com/javazejian/article/details/73413292 ClassLoader是一个抽象类,他有很多个实现 BootstrapClassLoader是最顶层的classloader 负责加载jvm需要的类 <JAVA_HOME>/lib路径下的核心类库或-Xbootclasspath参数指定的路径下的j...

一只猪啊啊的博客 727

SAP Ariba Procurement_Catalogs

SAP Ariba Procurement_Catalogs Search Functionality PunchOut Catalogs Spot Buy catalog

CZxx1的博客 1014

vue 获取el-table多选的选中行

<el-table :data='tableData' ref="multipleTable" v-loading='loading' border max-height='700' style='width: 100%' size="mini"> <el-table-column type="selection" width="55"></el-table-column> <el-table-column label

且听风吟的博客 6649

你真的懂Java类加载器吗?图文详解ClassLoader的原理和机制

什么是ClassLoaderClassLoad:类加载器用来加载 Java 类到 Java 虚拟机中。Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class 类的一个实例。jdk中提供了三种类加载器:引导类加载器BootStrap ClassLoader...

yyjava的专栏 851

【大语言模型 37】知识蒸馏深度实战:大模型向小模型迁移

本文深入探讨了知识蒸馏技术在大语言模型领域的应用,详细阐述了如何将庞大复杂的大模型知识有效迁移到轻量级小模型中。文章系统介绍了知识蒸馏的理论基础、多种蒸馏损失函数设计、特征匹配与注意力迁移技术、渐进式蒸馏策略以及全面的效果评估方法。通过实战案例和完整代码实现,读者将掌握从理论到实践的知识蒸馏全流程,了解如何在保持模型性能的同时显著降低计算资源需求,实现大语言模型的高效部署与应用。

熵数实验室 1509

Java Classloader基础及应用介绍

文章目录一 what's Classloader(CL)二 内置CL2.1 Bootstrap CL2.2 ExtCL(ExtClassloader)2.3 本篇系统介绍class loader 及其应用.以下 使用 CL (classloader) 来简写. 一 what’s Classloader(CL) 笔者以为,在讨论计算机(编程) 中的概念时首先一定要确定 概念所在的维度(范畴)是什么,否则会发现,大家说的貌似都对, 但哪里总有点不对. 当我们说 Java Classloader时,我们要搞清楚是

qq_30118563的博客 1007

【DRAM存储器四十六】LPDDR5介绍--基本操作之行操作、读、写

简述LPDDR5的行操作和读写时序

highman110的博客 764

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Java安全之【JVM类加载器】

Java类加载机制在Java安全知识体系中有着非常重要的地位,早在之前分析Shiro反序列化漏洞利用,以及学习蚁剑Java马,都和Java ClassLoader打过交道。笔者打算从把ClassLoader的原理、使用场景、自定义方式等多个方面剖析类加载器在Java安全中设计到的知识。 0x01 ClassLoader 简介 Java语言需要把代码编译成class文件,才能用JVM加载执行,那么ClassLoader就是负责将class文件加载到内存,生成对应的类。 0x1 ClassLoader..

欢迎来到我的博客 152

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

JVM性能调优1

图解说明如下: javac com.tuling.jvm.Math.java java com.tuling.jvm.Math 在windows系统西java.exe调用的jvm.dll文件创建Java虚拟机(C++实现),创建一个引导类加载器实例(C++实现),除了直接C++发起调用,还可以C++调用java代码,创建JVM启动器,实例sun.misc.Launcher该类引导类加载器负责加载创建其他类加载器,通过sun.misc.Launcher.getLauncher()获取运行类自己的加载器Cl.

一个保安的自由之路 254

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

面试官:双亲委派模型你了解吗?

面试官:要不你今天来详细讲讲双亲委派机制? 候选者:嗯,好的。 候选者:上次提到了:class文件是通过「类加载器」装载至JVM中的 候选者:为了防止内存中存在多份同样的字节码,使用了双亲委派机制(它不会自己去尝试加载类,而是把请求委托给父加载器去完成,依次向上) 候选者:JDK 中的本地方法类一般由根加载器(Bootstrp loader)装载,JDK 中内部实现的扩展类一般由扩展加载器(ExtClassLoader )实现装载,而程序中的类文件则由系统加载器(AppClassLoader )实现装载。

m0_66876551的博客 203

自定义 ClassLoader 绕过双亲委派的实验

1.对于任意一个类,由加载它的ClassLoader和它本身决定了在java虚拟机中的唯一性。 也就是说比较2个类,只有它们都是由同一个ClassLoader加载,那么比较才有意义。否则,即使是同一个类文件,如果加载它们的ClassLoader不同,那么这2个类必定不相等。 2.类加载的双亲委派机制是可以破坏的,通过改变CallClassLoader和ContextClassLoader。 被当前类引用的类的加载也是由加载当前类的ClassLoader加载,子线程的ContextClassLoader是.

zhaofuqiangmycomm的博客 453

创建自定义ClassLoader,绕过双亲委派

MyClassLoader.java 中定义了两个加载class的方法,其中findClass(String name)实现双亲委派逻辑,createClass(String name)绕过双亲委派逻辑

qq_26182553的博客 2453

ClassLoader,你学会了吗?

ClassLoader(类加载器)是 Java 虚拟机(JVM)的一部分,负责将 Java 类的字节码加载到内存中,并将其转换为 java.lang.Class 类的实例。Java 类的加载是 Java 运行时环境的基础,它使得程序能够动态地加载、链接和运行 Java 类。1. 模块化应用程序:可以使用自定义 ClassLoader 实现模块化的应用程序架构,动态地加载和卸载模块,实现更灵活的应用部署和管理。2. 热部署。

良月柒 1012

Java 底层知识 --- ClassLoader的双亲委派机制

什么是 ClassLoader 的双亲委派机制? 不同的ClassLoader 加载类的和路径有所不同,为了实现分工,各自负责各自的区块,使得逻辑更加的明确,所以才有这么多相互共存的ClassLoader 。加载类的时候根据管理的区域各司其职,所以存在了这个机制,让他们相互协作,形成一个整体 为什么要通过双亲委派来加载类? 1、避免多份同样字节码的加载 ...

xinbumi的博客 284

JVM实战:ClassLoader的原理及应用

ClassLoader(类加载器) 是 JVM(Java 虚拟机)的核心组件之一。它的核心职责只有一件事:将内存外部的 .class 字节码文件,加载到 JVM 的方法区中,并转为 java.lang.Class 对象// null= null) {Java提供了抽象类java.lang.ClassLoader,所有用户自定义的类加载器都应该继承ClassLoader类,所以我们先看一下ClassLoader的逻辑,看一下它加载类的主要逻辑我截取了3个重要的方法。

小识的博客 691

深入解析双亲委派机制:安全机制还是性能瓶颈?

摘要: Java的双亲委派模型通过"先问父加载器"机制确保核心类安全加载,防止类冲突。其优点是安全性高、内存占用低,但可能导致SPI加载失败和热更新问题。常见解决方案包括使用ThreadContextClassLoader或自定义ClassLoader(需谨慎)。框架如Tomcat、SpringBoot会调整该机制以平衡安全性与扩展性。实践中需注意类卸载机制和内存泄漏风险,合理判断何时打破委派。掌握双亲委派原理及灵活运用方案,有助于构建安全可扩展的系统架构

小健学Java的博客 693

打破双亲委派机制

由于委派机制会先委派给父类加载器,因此当一个类被父类加载器加载后,即使该类被更新了,自定义类加载器也无法重新加载此类(与类加载冲突有相似之处),从而阻止了自定义类的动态更新。通过继承ClassLoader类并重写其loadClass方法,可以实现自定义的类加载器。在重写loadClass方法时,可以修改双亲委派逻辑,从而打破双亲委派机制。例如,在Tomcat中,为了支持多个Web应用程序之间的类隔离(每个类加载器都有自己的命名空间,用于存放各自的全限定类名),Tomcat使用了自定义的类加载器。

2401_83176717的博客 691
上一篇: 一个简单的全排列算法
下一篇: InnoDB架构(8.0)
GetterAndSetter
博客等级 码龄9年 17粉丝 6原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值