首页 > 编程语言 >【java编程】Unsafe 类

【java编程】Unsafe 类

时间:2024-11-28 21:44:13浏览次数:7  
标签:java theUnsafe 编程 Unsafe public class static Class

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@74a14482

        byte[] 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 CMD
        evilClazz.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@74a14482

        byte[] 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/356573597
        evilClazz.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@74a14482
        Cat cat = (Cat) o.allocateInstance(Cat.class);
        System.out.println(cat); // com.heihu577.Cat@1540e19d
    }
}

最终可以实例化Cat类。

标签:java,theUnsafe,编程,Unsafe,public,class,static,Class
From: https://www.cnblogs.com/o-O-oO/p/18575306

相关文章

  • 基于Java+SpringBoot+Mysql实现的点卡各种卡寄售平台功能设计与实现一
    一、前言介绍:1.1项目摘要随着电子商务和在线支付技术的快速发展,数字商品和虚拟货币的交易需求日益增长。点卡及各种卡类商品(如游戏点卡、话费充值卡、礼品卡等)作为数字商品的一种,因其便捷性和即时性,在市场中占据了重要地位。然而,传统的点卡销售方式往往存在渠道单一、交易效率......
  • 基于Java+SpringBoot+Mysql实现的点卡各种卡寄售平台功能设计与实现二
    一、前言介绍:1.1项目摘要随着电子商务和在线支付技术的快速发展,数字商品和虚拟货币的交易需求日益增长。点卡及各种卡类商品(如游戏点卡、话费充值卡、礼品卡等)作为数字商品的一种,因其便捷性和即时性,在市场中占据了重要地位。然而,传统的点卡销售方式往往存在渠道单一、交易效率......
  • 【java编程】Xalan ClassLoader
    Xalan是Java中用于操作XML的一个库,它是ApacheXML项目的一部分,主要用于将XSLT(ExtensibleStylesheetLanguageTransformations)转换为可执行代码,从而实现XML文档的转换。XSLT的理解当然了,我们先理解该模块如何使用之后,我们再研究它的妙用,XSLT说白了就是将XML+......
  • Java中的“多态“详解
    多态(Polymorphism)是面向对象编程(OOP)中的一个核心概念,它允许同一个接口或方法在不同对象上具有不同的实现方式。多态性使得程序在运行时可以根据对象的实际类型来决定调用哪个方法,从而提高代码的灵活性和可扩展性。在Java中,多态主要通过以下几种方式实现:1.方法重载(编译时多态......
  • 【java编程】BCEL ClassLoader
    BCEL介绍BCEL的全名应该是ApacheCommonsBCEL,属于ApacheCommons项目下的一个子项目。ApacheCommons大家应该不陌生,反序列化最著名的利用链就是出自于其另一个子项目——ApacheCommonsCollections。BCEL库提供了一系列用于分析、创建、修改JavaClass文件的API。就这个库......
  • 【java编程】URLClassLoader
    从上面我们研究【java编程】双亲委派模式时进行Debug了源代码,可以发现的是,URLClassLoader是ExtClassLoader&&AppClassLoader的父类(不是父亲),publicclassLauncher{staticclassExtClassLoaderextendsURLClassLoader{}staticclassAppClassLoaderextend......
  • 【java编程】双亲委派模式
    双亲委派模式图文解释一个类加载器查找class和resource时,是通过委托模式进行的,它首先判断这个class是不是已经加载成功,如果没有的话它并不是自己进行查找,而是先通过父加载器,然后递归下去,直到BootstrapClassLoader,如果Bootstrapclassloader找到了,直接返回,如果没有找到,则一级一......
  • 14Java Lambda、方法引用、算法、正则表达式
    一、Arrays类接下来我们学习的类叫做Arrays,其实Arrays并不是重点,但是我们通过Arrays这个类的学习有助于我们理解下一个知识点Lambda的学习。所以我们这里先学习Arrays,再通过Arrays来学习Lamdba这样学习会更丝滑一些^_^.1.1Arrays基本使用我们先认识一下Arrays是干什么用的,A......
  • 15Java集合进阶(异常、集合)
    一、异常1.1认识异常接下来,我们学习一下异常,学习异常有利于我们处理程序中可能出现的问题。我先带着同学们认识一下,什么是异常?我们阅读下面的代码,通过这段代码来认识异常。我们调用一个方法时,经常一部小心就出异常了,然后在控制台打印一些异常信息。其实打印的这些异常信息......
  • 16Java集合进阶(Set、Map集合、可变参数、斗地主案例)
    请先看我上篇文章15Java集合进阶(异常、集合)-CSDN博客一、Set系列集合1.1认识Set集合的特点Set集合是属于Collection体系下的另一个分支,它的特点如下图所示下面我们用代码简单演示一下,每一种Set集合的特点。//Set<Integer>set=newHashSet<>(); //无序、无索引、不重......