【java编程】Unsafe 类

news/2024/11/28 21:41:38/文章来源:https://www.cnblogs.com/o-O-oO/p/18575306

Unsafe 类不是一个 ClassLoader, 但是为什么要在本篇文章提起, 其实是因为该类可以进行注入恶意类到 JVM 中.

Unsafe 类简介

sun.misc.Unsafe 类是一个提供底层、不安全的操作,比如直接内存访问、线程调度、原子操作等功能的工具类。

这个类主要被Java内部库使用,比如Java的NIO、并发包等,因为它允许绕过Java的内存管理模型,直接进行内存操作,这可能导致程序崩溃、数据损坏等严重后果。因此,它被认为是"不安全"的,并且不建议在常规的应用程序开发中使用。

Unsafe 类详解

我们可以看到图中的定义, theUnsafe成员属性的定义在static代码块中进行初始化了。 所以我们可以通过Unsafe.getUnsafe来得到该对象, 但是这里有一个限制。
根据下图进行代码分析:

Unsafe的构造方法为private修饰符, 所以我们无法在程序中直接new Unsafe()进行实例化生成, 否则程序将报错:

这里的话我们可以通过反射进行暴破获取该类的theUnsafe属性, 当然也可以通过反射暴破该类的构造方法, 都可以进行获取到Unsafe类, 代码测试如下:

public class Main {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {Class<?> clazz = Class.forName("sun.misc.Unsafe");Constructor<?> declaredConstructor = clazz.getDeclaredConstructor();declaredConstructor.setAccessible(true);Unsafe unsafe = (Unsafe) declaredConstructor.newInstance();System.out.println(unsafe); // sun.misc.Unsafe@4554617c}
}

以及:

public class Main {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {Class<?> clazz = Class.forName("sun.misc.Unsafe");Field theUnsafe = clazz.getDeclaredField("theUnsafe"); // 因为 theUnsafe 使用 static 进行修饰, 在 static 代码块中进行初始化, 所以这里无需创建 Unsafe 对象, 静态调用就可以得到.theUnsafe.setAccessible(true);Unsafe o = (Unsafe) theUnsafe.get(null);System.out.println(o); // sun.misc.Unsafe@74a14482}
}

Unsafe 类利用

我们可以通过反射得到 Unsafe 对象, 那么我们如何利用呢?

我们在Unsafe 类详解中图中已经看到了, 该类定义了三个native定义的方法, 这些方法都是由C/C++底层实现的, 如下:

public native Class<?> defineClass(String var1, byte[] var2, int var3, int var4, ClassLoader var5, ProtectionDomain var6);
// 可以加载字节码
public native Class<?> defineAnonymousClass(Class<?> var1, byte[] var2, Object[] var3); // 可以加载字节码
public native Object allocateInstance(Class<?> var1) throws InstantiationException; // 实例化任意类

defineClass 案例

public class Main {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException {Class<?> clazz = Class.forName("sun.misc.Unsafe");Field theUnsafe = clazz.getDeclaredField("theUnsafe"); // 因为 theUnsafe 使用 static 进行修饰, 在 static 代码块中进行初始化,// 所以这里无需创建 Unsafe 对象, 静态调用就可以得到.theUnsafe.setAccessible(true);Unsafe o = (Unsafe) theUnsafe.get(null);System.out.println(o); // sun.misc.Unsafe@74a14482byte[] poc = new BASE64Decoder().decodeBuffer("yv66vgAAADQAKAoACQAYCgAZABoIABsKABkAHAcAHQcAHgoABgAfBwAgBwAhAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAVMQ01EOwEACDxjbGluaXQ+AQABZQEAFUxqYXZhL2lvL0lPRXhjZXB0aW9uOwEADVN0YWNrTWFwVGFibGUHAB0BAApTb3VyY2VGaWxlAQAIQ01ELmphdmEMAAoACwcAIgwAIwAkAQAEY2FsYwwAJQAmAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAGmphdmEvbGFuZy9SdW50aW1lRXhjZXB0aW9uDAAKACcBAANDTUQBABBqYXZhL2xhbmcvT2JqZWN0AQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAGChMamF2YS9sYW5nL1Rocm93YWJsZTspVgAhAAgACQAAAAAAAgABAAoACwABAAwAAAAvAAEAAQAAAAUqtwABsQAAAAIADQAAAAYAAQAAAAgADgAAAAwAAQAAAAUADwAQAAAACAARAAsAAQAMAAAAZgADAAEAAAAXuAACEgO2AARXpwANS7sABlkqtwAHv7EAAQAAAAkADAAFAAMADQAAABYABQAAAAsACQAOAAwADAANAA0AFgAPAA4AAAAMAAEADQAJABIAEwAAABQAAAAHAAJMBwAVCQABABYAAAACABc=");/*该 Base64 值是如下类的字节码 Base64 后的值public class CMD {static {try {Process exec = Runtime.getRuntime().exec("calc");} catch (IOException e) {throw new RuntimeException(e);}}} */Class<?> evilClazz = o.defineClass("CMD", poc, 0, poc.length, ClassLoader.getSystemClassLoader(),new ProtectionDomain(new CodeSource(null, (Certificate[]) null), null, ClassLoader.getSystemClassLoader(), null));System.out.println(evilClazz); // class CMDevilClazz.newInstance();}
}

运行完毕后, 将弹出计算器。

Java 11开始Unsafe类已经把defineClass方法移除了(defineAnonymousClass方法还在)。

defineAnonymousClass 案例

public class Main {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException {Class<?> clazz = Class.forName("sun.misc.Unsafe");Field theUnsafe = clazz.getDeclaredField("theUnsafe"); // 因为 theUnsafe 使用 static 进行修饰, 在 static 代码块中进行初始化,// 所以这里无需创建 Unsafe 对象, 静态调用就可以得到.theUnsafe.setAccessible(true);Unsafe o = (Unsafe) theUnsafe.get(null);System.out.println(o); // sun.misc.Unsafe@74a14482byte[] poc = new BASE64Decoder().decodeBuffer("yv66vgAAADQAKAoACQAYCgAZABoIABsKABkAHAcAHQcAHgoABgAfBwAgBwAhAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAVMQ01EOwEACDxjbGluaXQ+AQABZQEAFUxqYXZhL2lvL0lPRXhjZXB0aW9uOwEADVN0YWNrTWFwVGFibGUHAB0BAApTb3VyY2VGaWxlAQAIQ01ELmphdmEMAAoACwcAIgwAIwAkAQAEY2FsYwwAJQAmAQATamF2YS9pby9JT0V4Y2VwdGlvbgEAGmphdmEvbGFuZy9SdW50aW1lRXhjZXB0aW9uDAAKACcBAANDTUQBABBqYXZhL2xhbmcvT2JqZWN0AQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAGChMamF2YS9sYW5nL1Rocm93YWJsZTspVgAhAAgACQAAAAAAAgABAAoACwABAAwAAAAvAAEAAQAAAAUqtwABsQAAAAIADQAAAAYAAQAAAAgADgAAAAwAAQAAAAUADwAQAAAACAARAAsAAQAMAAAAZgADAAEAAAAXuAACEgO2AARXpwANS7sABlkqtwAHv7EAAQAAAAkADAAFAAMADQAAABYABQAAAAsACQAOAAwADAANAA0AFgAPAA4AAAAMAAEADQAJABIAEwAAABQAAAAHAAJMBwAVCQABABYAAAACABc=");/*该 Base64 值是如下类的字节码 Base64 后的值public class CMD {static {try {Process exec = Runtime.getRuntime().exec("calc");} catch (IOException e) {throw new RuntimeException(e);}}} */Class<?> evilClazz = o.defineAnonymousClass(Class.class, poc, null);System.out.println(evilClazz); // class CMD/356573597evilClazz.newInstance();}
}

运行弹出计算器.

allocateInstance 案例

定义如下类:

public class Cat {private Cat(){}
}

测试程序:

public class Main {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException, IOException {Class<?> clazz = Class.forName("sun.misc.Unsafe");Field theUnsafe = clazz.getDeclaredField("theUnsafe"); // 因为 theUnsafe 使用 static 进行修饰, 在 static 代码块中进行初始化,// 所以这里无需创建 Unsafe 对象, 静态调用就可以得到.theUnsafe.setAccessible(true);Unsafe o = (Unsafe) theUnsafe.get(null);System.out.println(o); // sun.misc.Unsafe@74a14482Cat cat = (Cat) o.allocateInstance(Cat.class);System.out.println(cat); // com.heihu577.Cat@1540e19d}
}

最终可以实例化Cat类。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/843096.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

山体落石泥石流自动监测摄像机

山体落石泥石流自动监测摄像机捕获的图像数据将对图像进行分析,山体落石泥石流自动监测摄像机识别出山体的位移、裂缝、滑坡等异常现象。算法的训练需要大量的山体图像数据,包括正常和异常状态的图像,以确保其识别的准确性。一旦AI系统识别出山体失稳的迹象,它会立即触发报…

【java编程】Xalan ClassLoader

Xalan 是 Java 中用于操作 XML 的一个库,它是 Apache XML 项目的一部分,主要用于将 XSLT(Extensible Stylesheet Language Transformations)转换为可执行代码,从而实现XML文档的转换。 XSLT 的理解 当然了, 我们先理解该模块如何使用之后, 我们再研究它的妙用, XSLT 说白了…

[游记]CSP2024 游记

这是一篇迟到的游记,为什么呢?因为作者已经成为文化课选手了。 Day-1 晚上 \(6:00\) 到了宾馆,在路上准备了一下面基事宜。在车上昏昏沉沉,结果下了车精神抖擞了。 简单布置之后开始摆烂,这是符合考前规范的好事。某游戏连跪十五局。rp -- 。我希望这是给我第二天攒 rp。 …

[笔记]动态规划优化(斜率优化,决策单调性优化)

本文主要记录某些动态规划思路及动态规划优化。 首先先把以前写过的斜率优化祭出来。 斜率优化 \(\text{P5017 [NOIP2018 普及组] 摆渡车}\) 经典例题。 设 \(f_i\) 表示最后班车在 \(i\) 时刻发车,所有人等待时间和的最小值。(这里的所有人是指到达时刻小于等于 \(i\) 的所有…

基于Java+SpringBoot+Mysql实现的点卡各种卡寄售平台功能设计与实现一

后台功能:寄售管理、提现管理、订单管理、认证管理、公告管理、用户管理等。 该系统总共21张表,代码整洁,每个功能、接口上都有注释说明。 部分功能:前台用户信息实体类Entity、实名认证信息实体类Entity、银行卡类型信息实体类Entity、寄售卡类型信息实体类Entity、寄售卡…

【java编程】BCEL ClassLoader

BCEL 介绍 BCEL的全名应该是Apache Commons BCEL,属于Apache Commons项目下的一个子项目。Apache Commons大家应该不陌生,反序列化最著名的利用链就是出自于其另一个子项目——Apache Commons Collections。 BCEL库提供了一系列用于分析、创建、修改Java Class文件的API。就…

借助电脑探究双变量函数问题侧记

记录一次借助电脑探究双变量函数问题的全过程前情概要 偶尔看到下面的习题,想到以前自己整理的双变量函数问题,尝试练手时发现,寻找思路不是很简单的问题,探索一番,对整个过程作以记录,成篇为一侧记 . 典型案例 【2025届高三数学月考3第12题】对于函数 \(f(x)=e^x-x^2+a\…

Paypal最新版本 paypal-server-sdk 使用案例(前端 Vue3 + 后端Spring Boot )

背景 在项目中对接Paypal支付,一开始在网上查了好久,发现资料少,而且陈旧,甚至我都没弄清楚我应该哪个SDK。 我到 maven 中央仓库中,搜索 com.paypal.sdk,能查出不少结果,据我所知,至少有三个sdk可以从后端访问到Paypal:paypal-core:非常陈旧,2016年就停止更新了,但…

【java编程】URLClassLoader

从上面我们研究【java编程】双亲委派模式时进行Debug了源代码, 可以发现的是, URLClassLoader是ExtClassLoader && AppClassLoader的父类(不是父亲), public class Launcher {static class ExtClassLoader extends URLClassLoader {}static class AppClassLoader exten…

秒杀系统

前言 秒杀大家都不陌生。自2011年首次出现以来,无论是双十一购物还是 12306 抢票,秒杀场景已随处可见。简单来说,秒杀就是在同一时刻大量请求争抢购买同一商品并完成交易的过程。从架构视角来看,秒杀系统本质是一个高性能、高一致、高可用的三高系统。而打造并维护一个超大…

.NET周刊【11月第4期 2024-11-24】

国内文章 C# 入门深度学习:万字长文讲解微积分和梯度下降 https://www.cnblogs.com/whuanle/p/18551532 这篇文章主要介绍了使用 C# 进行深度学习的方法,特别是微积分在此领域的应用。作者简要讲解了极限、导数等基本概念,并展示了如何在 C# 中实现这些数学运算,例如将一个…

高级程序语言第九次作业

这个作业属于哪个课程:https://edu.cnblogs.com/campus/fzu/2024C 这个作业要求在哪里:https://edu.cnblogs.com/campus/fzu/2024C/homework/13311 学号:102400204 姓名:刘嘉奕不太理解10题a,b两个题目的要求有何不同,一个把值返回该结构,不运用指针,而b要把值赋给合适…