• 『Java安全』Unsafe类


    前言

    jdk版本基于8u111

    简介

    https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/jdk/internal/misc/Unsafe.java

    Unsafe类提供一些低级、不安全的操作,调用前必须确保安全。使用Unsafe可以进行类定义、类实例化、修改内存等操作。

    在这里插入图片描述

    警告

    Unsafe抛出的任何错误都是jvm级别,会导致JVM崩溃的错误,而不是普通异常

    在这里插入图片描述

    unsafe类的获取

    Unsafe的自动实例化在自身的静态代码块

    在这里插入图片描述
    仅拥有一个private构造器,getter有严格验证:只允许根加载器调用该方法

    在这里插入图片描述
    因此可以考虑反射获取,常规两种方式:调构造器或者调getter

            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            Unsafe unsafe1 = (Unsafe) f.get(null);
    
            Constructor constructor = Unsafe.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            Unsafe unsafe2 = (Unsafe) constructor.newInstance();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    常用方法

    不调用构造器实例化类

    Unsafe.allocateInstance(Class cls)方法提供绕过任意构造器实例化的功能
    在这里插入图片描述

    		Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            Unsafe unsafe1 = (Unsafe) f.get(null);
    
            TestAllocateInst testAllocateInst = (TestAllocateInst) unsafe1.allocateInstance(TestAllocateInst.class);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    package unsafeTest;
    
    public class TestAllocateInst {
    
        public TestAllocateInst() {
            System.out.println("Constructor");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    运行并未触发构造器

    在这里插入图片描述

    defineClass定义类

    绕过安全检查直接向jvm注册类

    在这里插入图片描述
    传入六个参数:类名、字节码、字节码起始、字节码长度、加载器、保护域

    package unsafeTest;
    
    import sun.misc.Unsafe;
    import java.io.File;
    import java.io.FileInputStream;
    import java.lang.reflect.Field;
    import java.security.CodeSource;
    import java.security.ProtectionDomain;
    import java.security.cert.Certificate;
    
    public class TestDefine {
        public static void main(String[] args) throws Exception{
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            Unsafe unsafe = (Unsafe) f.get(null);
            
            FileInputStream fis = new FileInputStream(new File("src//main//java//unsafeTest//TestAllocateInst.class"));
            byte[] bytes = new byte[fis.available()];
            fis.read(bytes);
    
            ClassLoader clazzLoader = ClassLoader.getSystemClassLoader();
            ProtectionDomain domain = new ProtectionDomain(
                    new CodeSource(null, (Certificate[]) null), null, clazzLoader, null
            );
            
            Class clazz = unsafe.defineClass("TestAllocateInst", bytes, 0, bytes.length, clazzLoader, domain);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    在这里插入图片描述

    抛出任意错误

    在这里插入图片描述
    在这里插入图片描述

    获取内存信息

    在这里插入图片描述

    参考

    https://javasec.org/javase/Unsafe

    欢迎关注我的CSDN博客 :@Ho1aAs
    版权属于:Ho1aAs
    本文链接:https://ho1aas.blog.csdn.net/article/details/126928128
    版权声明:本文为原创,转载时须注明出处及本声明

  • 相关阅读:
    Spring中@Validated和@Valid区别是什么
    Xml转json
    【追求卓越01】数据结构--数组
    mock-随机生成数据工具
    Vue双向绑定的原理
    传统考勤太复杂怎么办?这个小技巧,我必须吹爆!
    聚焦千兆光模块和万兆光模块的测试技术及设备
    iOS 新建本地数据库FMDB
    Leetcode 93. Restore IP Addresses
    海格里斯HEGERLS仓储货架厂家标准解析|智能自动化立体仓库AS/RS存储系统
  • 原文地址:https://blog.csdn.net/Xxy605/article/details/126928128