"/>
·设为首页收藏本站📧邮箱修改🎁免费下载专区💎积分✅卡密📒收藏夹👽聊天室
DZ插件网 门户 网站安全 查看内容

原创|java安全-java类加载器

2022-3-7 07:10| 发布者: admin| 查看: 299| 评论: 0|原作者: 白帽子

摘要: 点击上方蓝字关注我吧前言java类加载器是JVM加载类到内存并运行的过程,这个过程有点复杂,除了系统自定义的三类加载器外,...

点击上方蓝字 关注我吧

前言

java类加载器是JVM加载类到内存并运行的过程,这个过程有点复杂,除了系统自定义的三类加载器外,java运行用户编写自定义加载器来完成类的加载过程。java安全中常常需要远程加载恶意类文件来完成漏洞的利用,所以学习类加载器的编写也是很重要的。


类加载器

java系统定义了三类加载器,分别是BootstrapClassLoader,ExtensionClassLoader,AppClassLoader。其中BootstrapClassLoader由 C 语言代码实现,主要负责加载存储在JAVAHOME/jre/lib/rt.jar中的核心Java库,包括JVM本身。

ExtensionClassLoader由sun.misc.LauncherExtClassLoader类实现。负责加载 JVM 扩展类,用来加载\jre\lib\ext的类,这些库名通常以 javax 开头,它们的 jar 包位于JAVAHOME/lib/ext/∗.jar中,有很多jar包。

AppClassLoader由sun.misc.LauncherAppClassLoader实现。是直接面向我们用户的加载器,它会加载 Classpath 环境变量里定义的路径中的 jar 包和目录。

这三类加载器互相配合,完成了类的加载,这个过程比较复杂,而且还有一个比较重要的“双亲委派”机制,想要深入了解的同学可以看下老大难的 Java ClassLoader 再不理解就老了(https://zhuanlan.zhihu.com/p/51374915)。

不过这里我们只需要重点关注下URLClassLoader和如何自定义类加载器就可以了。

URLClassLoader

URLClassLoader扩展了ClassLoader,所以它在ClassLoader的基础上扩展了一些功能,这些扩展的功能中,最主要的一点就是URLClassLoader却可以加载任意路径下的类(ClassLoader只能加载classpath下面的类)。
在上篇的java反射介绍中,要实现动态加载类都是使用用Class.forName()这个方法,但是这个方法只能创建程序中已经引用的类,如果我们需要动态加载程序外的类,Class.forName()是不够的,这个时候就是需要使用URLClassLoader。
1、从本地文件加载外部类
首先先编写一个测试类,并将其编译为class文件。
package com.classloader;

public class test {
public test(){
System.out.println("classloader test");
    }
}
此时会在D:\com\classloader文件夹下生成一个test.class文件。
URLClassLoader本地加载外部类示例:
package com.classloader;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;

public class Demo1 {
public static void main(String[] args) throws Exception {
File file = new File("D:/");
URL url = file.toURI().toURL();
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url});
        //反射调用
        Class<?> Cls = urlClassLoader.loadClass("com.classloader.test");
Cls.newInstance();
}
}

2、远程加载外部类

URLClassLoader远程加载外部类示例:
同上一步,将test.class文件放在远端的一个服务器上,使用http远程访问此文件。
地址为:http://1.14.47.152/test.class
URLClassLoader远程加载外部类示例:
package com.classloader;

import java.net.URL;
import java.net.URLClassLoader;

public class Demo2 {
public static void main(String[] args) throws Exception{
URL url = new URL("http://1.14.47.152/");
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url});
Class<?> test = urlClassLoader.loadClass("com.classloader.test");
test.newInstance();
}
}


自定义类加载器

除了系统内置的类加载器,我们还可以自定义类加载器,自定义的类加载器需要继承java.lang.ClassLoader,通过重写其中的findClass()方法来达到想要的功能。
这里引用JAVA安全基础(一)--类加载器(ClassLoader)(https://xz.aliyun.com/t/9002)这篇文章中加密 java 类字节码例子来讲解。
首先创建CypherTest.java文件并生成CypherTest.class
package com.classloader;

public class CypherTest{
public static void main(String[] args) {
System.out.println("This experiment test is successful");
}
}
之后我们编写一个加密类 Encryption,使用简单的逐位取反进行加密操作。
package com.classloader;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Encryption {
public static void main(String[] args) {
encode(new File("D:\\Code\\java\\test\\src\\com\\classloader\\CypherTest.class"), // 获取路径CypherTest.class文件
new File("D:\\Code\\java\\temp\\src\\com\\classloader\\CypherTest1.class")); // 为了保持一致,创建了一个空的temp目录
}
public static void encode(File src, File dest) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(src);
fos = new FileOutputStream(dest); // 逐位取反操作 int temp = -1;
while ((temp = fis.read()) != -1) {// 读取一个字节
fos.write(temp ^ 0xff);// 取反输出
}
} catch (IOException e) {
} finally { // 关闭数据流
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println("This experiment test is successful");
}
}

运行后生成了加密后的CypherTest.class文件

因为这个是自定义加密后,我们无法使用工具直接进行反编译操作和直接使用 jvm 默认类加载器去使用它。

那此时就需要自定义类加载器去加载了。
自定义解密类加载器示例:
package com.classloader;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class Decryption extends ClassLoader { // 继承ClassLoader类

private String rootDir;

public Decryption(String rootDir) {
this.rootDir = rootDir;
}

@Override // 重写覆盖findClass
protected Class<?> findClass(String className) throws ClassNotFoundException {
byte[] classData = getClassData(className);
return defineClass(className, classData, 0, classData.length);
}

public byte[] getClassData(String className) {
String path = rootDir + File.separator + className.replace(".", File.separator) + ".class"; // 将流中的数据转换为字节数组
InputStream is = null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
is = new FileInputStream(path);
byte[] buffer = new byte[1024];
int temp = -1;
while ((temp = is.read()) != -1) {
                baos.write(temp ^ 0xff);
}
return baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (baos != null) {
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
                }
            }
}
}
}
然后调用自定义的类加载器去加载加密后的class文件即可。
package com.classloader;

import java.lang.reflect.Method;

public class Demo3 {
public static void main(String[] args) throws Exception {
Decryption dloader = new Decryption("D:/Code/java/test/src/temp");
        Class<?> aClass = dloader.loadClass("com.classloader.CypherTest");
Method main = aClass.getMethod("main",String[].class);
//反射调用main方法 main.invoke(null,(Object)new String[]{});
}
}

相关推荐




原创 | java安全-java RMI

原创 | java安全-java反射

原创 | 内网渗透之隐藏隧道搭建(下)

原创 | 内网渗透之隐藏隧道搭建(上)

你要的分享、在看与点赞都在这儿~


上一篇:Swoole的底层架构和实现原理
下一篇:如何隐藏shell脚本内容

鲜花

握手

雷人

路过

鸡蛋

评论

您需要登录后才可以发表言论 登录立即注册
创宇盾启航版免费网站防御网站加速服务
投诉/建议联系

discuzaddons@vip.qq.com

未经授权禁止转载,复制和建立镜像,
如有违反,按照公告处理!!!
  • 联系QQ客服
  • 添加微信客服

联系DZ插件网微信客服|最近更新|Archiver|手机版|小黑屋|DZ插件网! ( 鄂ICP备20010621号-1 )|网站地图 知道创宇云防御

您的IP:3.149.240.101,GMT+8, 2024-12-25 22:11 , Processed in 0.115147 second(s), 47 queries , Gzip On, Redis On.

Powered by Discuz! X5.0 Licensed

© 2001-2024 Discuz! Team.

关灯
扫一扫添加微信客服
QQ客服返回顶部
返回顶部