java Unsafe详细解析

Java Unsafe详细解析

简介

Java Unsafe 是 JDK 提供的一个支持直接操作内存、线程、JVM 的类库。由于 Unsafe 操作的是内存,所以它可以绕过 JVM 的安全检查,说白了就是越过了 Java 的限制,直接操作底层内存。不是直接通过 new 实例化对象进行使用,而是通过反射或本地方法调用获取一个实例。

使用

Unsafe 类主要包含以下方法:

  1. 内存存取操作

    • putXXX():存放基本类型到指定的内存地址;
    • getXXX():从指定地址获取指定类型的值。
  2. 对象创建和销毁

    • allocateInstance(Class cls):实例化一个没有调用构造方法的对象;
    • freeMemory(obj):释放对象空间。
  3. 数组操作

    • arrayBaseOffset(Class<?> arrayClass):获取指定类型数组第一个元素的偏移量;
    • arrayIndexScale(Class<?> arrayClass):获取指定类型数组每个元素占用的空间大小;
    • getObject(Object array, long index):获取指定索引位置的元素;
    • putObject(Object array, long index, Object value):设置指定索引位置的元素值。
  4. 线程和锁操作

    • park(boolean isAbsolute, long time):暂停线程运行指定时间,单位为纳秒;
    • unpark(Object thread):继续运行指定的线程;
    • monitorEnter(Object obj):获取对象锁;
    • monitorExit(Object obj):释放对象锁。

示例1:修改String对象值

public class ChangeStringValue {
    public static void main(String[] args) throws Exception {
        String str = "Hello, World!";
        System.out.println("Original string: " + str);

        // 获取Unsafe实例
        Field field = Unsafe.class.getDeclaredField("theUnsafe");
        field.setAccessible(true);
        Unsafe unsafe = (Unsafe) field.get(null);

        // 获取字符数组的首地址和长度,修改数组中某个字符的值
        long stringBaseOffset = unsafe.arrayBaseOffset(char[].class);
        long addressOfFirstChar = unsafe.getLong(str, stringBaseOffset);
        char[] chars = (char[]) unsafe.getObject(str, stringBaseOffset);
        chars[7] = 'J';

        // 重新构造字符串
        String newStr = (String) unsafe.allocateInstance(String.class);
        unsafe.putLong(newStr, stringBaseOffset, addressOfFirstChar);
        System.out.println("New string: " + newStr);
    }
}

运行结果:

Original string: Hello, World!
New string: Hello, Jorld!

此示例展示了可以使用 Unsafe 遍历并修改字符串的字符,以及如何重新构造一个字符串对象。

示例2:破解懒汉式单例模式

public class LazySingleton {
    private static volatile LazySingleton instance;
    private LazySingleton() {}

    public static LazySingleton getInstance() {
        if (instance == null) {
            synchronized (LazySingleton.class) {
                if (instance == null) {
                    instance = new LazySingleton();
                }
            }
        }
        return instance;
    }
}

通过指针去创建对象的方式可以避免 synchronized 存在的锁消耗,但也会带来多对象被实例化的风险。这种方式并不能保证只会创建一个对象,只是此处概率较小。

public class ReflectionCreateObj implements Serializable {
    private static LazySingleton instance;

    static {
        Field field;
        try {
            field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            Unsafe unsafe = (Unsafe) field.get(null);

            // 获取LazySingleton对象的引用地址
            long instanceOffset = unsafe.objectFieldOffset(
                    ReflectionCreateObj.class.getDeclaredField("instance"));

            // 修改对象引用值
            UnsafeReflectionTest uninstallObj = new UnsafeReflectionTest();
            unsafe.putOrderedObject(uninstallObj, instanceOffset, LazySingleton.getInstance());
        } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    public static LazySingleton getInstance() {
        return instance;
    }
}

此示例展示了通过 Unsafe 修改了 LazySingleton 对象的引用地址,破解了懒汉式单例模式。这种方式可以恶意绕过系统的业务逻辑,窃取并篡改敏感数据。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java Unsafe详细解析 - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • C语言版医院管理系统

    C语言版医院管理系统攻略 介绍 C语言版医院管理系统是一个完整的医院管理系统,可以实现包括病人信息管理、医生信息管理、医院排班管理、医生出诊信息管理、病历管理等多项功能。该系统可以实现对医院各种资源和信息的自由管理,方便医院管理人员的工作。 系统需求 操作系统:Windows或Linux C语言编译器:gcc或VS 操作说明 1. 运行程序 下载并解压缩医院…

    C 2023年5月23日
    00
  • 用C语言实现猜数字游戏

    用C语言实现猜数字游戏完整攻略 1. 游戏规则 本猜数字游戏的规则非常简单,系统在1到100之间随机生成一个数字,然后玩家通过输入进行猜测,如果猜中则游戏胜利,若猜测的数字小于或大于目标数字,则系统会提示玩家重新猜测。 2. 程序实现 (1)首先我们需要定义一个目标数字,该数字需要随机生成。使用rand()函数可以生成一个随机数,我们通过加上1的操作让生成的…

    C 2023年5月23日
    00
  • 如何获取PostgreSQL数据库中的JSON值

    如何获取PostgreSQL数据库中的JSON值 在 PostgreSQL 数据库中,我们可以使用 JSON 类型保存数据。如何获取 JSON 类型数据中的值呢?接下来就给出详细的攻略。 先决条件 在执行以下命令之前,请确保已经安装了 PostgreSQL 数据库,并已经对其进行了正确的配置。 示例一:获取单个 JSON 值 可以使用 -> 或者 -&…

    C 2023年5月23日
    00
  • 使用C语言实现扫雷小游戏

    下面我将为你详细讲解使用 C 语言实现扫雷小游戏的完整攻略。 1. 题目描述 这是一个扫雷小游戏,玩家需要在雷区中揭示隐藏的地雷,并且不踩雷,最终揭示出所有非地雷的位置才能胜利。游戏中将提供以下需要的功能: 初始化雷区和地雷 展开被点击的单元格 计算相邻单元格中地雷的数量 判断游戏是否胜利 表示输赢结果 2. 实现思路 游戏思路以及实现可以分为以下几个步骤:…

    C 2023年5月23日
    00
  • 浅析VSCode tasks.json中的各种替换变量的意思 ${workspaceFolder} ${file} ${fileBasename} ${fileDirname}等

    关于VSCode tasks.json中的各种替换变量,我整理了如下攻略: 一、什么是tasks.json tasks.json是Visual Studio Code中用来指定任务的一个配置文件,可以用来运行一些自定义的构建、测试、调试等任务。在这个配置文件中,可以指定任务的执行命令,参数,以及一些特定的配置项。 二、tasks.json中的替换变量 在指定…

    C 2023年5月23日
    00
  • C语言函数调用底层实现原理分析

    C语言函数调用底层实现原理分析,从根本上就是在探究内存是如何管理和运用的。下面我们将介绍在函数调用时,C语言底层的实现原理,并给出两个具体的示例说明。 函数调用栈的实现 在C语言中,函数调用涉及到堆栈的概念。堆栈是一种数据结构,它具有后进先出(LIFO)的特点。当函数被调用时,程序会将当前函数的返回地址(即下一个要执行的指令地址)以及其他一些信息(例如参数值…

    C 2023年5月23日
    00
  • C语言快速实现扫雷小游戏

    C语言快速实现扫雷小游戏攻略 介绍 扫雷是一款经典的小游戏,以其简单的规则和极高的可玩性深受玩家喜爱。在此,将介绍如何使用C语言快速实现扫雷小游戏。 实现思路 扫雷游戏的主要逻辑是实现格子的打开、插旗和计算数字等操作。因此需要设计一个二维数组来表示游戏界面,并将每个格子分成以下几种类型: 雷格:表示该格子下面是一颗地雷; 数字格:表示该格子周围有多少颗地雷;…

    C 2023年5月23日
    00
  • 华硕X550C怎么拆机 华硕X550C清理灰尘与升级SSD图文教程

    华硕X550C是一款经典的笔记本电脑,通常情况下使用时间长了之后就会出现散热问题或者存储容量不足的问题。为了解决这些问题,我们需要拆卸笔记本电脑并进行清理灰尘或者升级SSD。下面我将为大家提供华硕X550C拆机、清理灰尘以及升级SSD的详细攻略。 步骤一:准备工作 首先,我们需要准备以下材料: 十字螺丝刀 塑料卡片 SSD硬盘 硬盘盒 硅脂 清洁剂 清理刷 …

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部