ASM之FieldVisitor创建变量

FieldVisitor使用abstract 修饰,用于创建变量,在使用时调用 ClassWriter.visitField即可创建FieldVisitor

方法介绍

visitField(Opcodes.ACC_PUBLIC, “str”, “Ljava/lang/String;”, null, “Hello World”)

第一个参数是修饰类型,第二个参数是变量名,第三个是变量类型,第四个签名,第五个是变量的值(设置值好像没什么用,所以我在下面代码的初始化中重新初始化了str的值)

示例代码如下
package com.example.asmapplicationimport org.junit.Test
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.Opcodes
import java.io.File
import java.io.FileOutputStream
import java.net.URLClassLoaderclass DemoASMGenerateField {@Testfun generate() {val filePath ="E:\\Develop\\ASMApplication2\\app\\src\\test\\java\\com\\example\\asmapplication\\generate\\GenerateField.class"val file = File(filePath)if (!file.parentFile.exists()) {file.parentFile.mkdir()}//创建ClassWriterval cw = ClassWriter(ClassWriter.COMPUTE_FRAMES)//设定包名和类名cw.visit(Opcodes.V1_8,Opcodes.ACC_PUBLIC,"com/example/asmapplication/generate/GenerateField",null,"java/lang/Object",null)//创建全局变量val vfStr =cw.visitField(Opcodes.ACC_PUBLIC, "str", "Ljava/lang/String;", null, "Hello World")vfStr.visitEnd()//每个classFile都有一个<init>的初始化方法val mvInit = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null)mvInit.visitCode()mvInit.visitVarInsn(Opcodes.ALOAD, 0)mvInit.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false)mvInit.visitVarInsn(Opcodes.ALOAD, 0)//初始化定义的变量的值mvInit.visitLdcInsn("Hello World")mvInit.visitFieldInsn(Opcodes.PUTFIELD, "com/example/asmapplication/generate/GenerateField", "str", "Ljava/lang/String;")mvInit.visitInsn(Opcodes.RETURN)mvInit.visitMaxs(0, 0)mvInit.visitEnd()//创建一个test()方法val mvTest = cw.visitMethod(Opcodes.ACC_PUBLIC, "test", "()V", null, null)mvTest.visitCode()//打印Hello WordmvTest.visitVarInsn(Opcodes.ALOAD, 0);mvTest.visitFieldInsn(Opcodes.GETFIELD,"com/example/asmapplication/generate/GenerateField","str","Ljava/lang/String;");mvTest.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;")mvTest.visitInsn(Opcodes.SWAP)mvTest.visitMethodInsn(Opcodes.INVOKEVIRTUAL,"java/io/PrintStream","println","(Ljava/lang/Object;)V",false)mvTest.visitInsn(Opcodes.RETURN)mvTest.visitMaxs(0, 0)mvTest.visitEnd()//类的访问结束cw.visitEnd()//输出为class文件val outputStream = FileOutputStream(file)outputStream.write(cw.toByteArray())outputStream.flush()outputStream.close()val classLoader = URLClassLoader(arrayOf(File("E:\\Develop\\ASMApplication2\\app\\src\\test\\java").toURI().toURL()))val clazz = classLoader.loadClass("com.example.asmapplication.generate.GenerateField")val obj = clazz.newInstance()clazz.getMethod("test").invoke(obj)}
}
最终生成代码:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package com.example.asmapplication.generate;public class GenerateField {public String str = "Hello World";public GenerateField() {}public void test() {System.out.println(this.str);}
}

技巧分享

假如我们想在MainActivity中动态生成两个变量

public int age = 100;
public String str = "Hello World";

可以这样做:

1、先在一个Test类中创建两个变量,代码 如下:

public class Test {public int age = 100;public String str = "Hello World";private int sum(int i, int j) {return i+j;}
}

编译后,通过ASM Bytecode Outline Rebooted等工具查看Test.class的字节码信息:

public class com/baidu/main/test/Test {// access flags 0x1public I age// access flags 0x1public Ljava/lang/String; str// access flags 0x1public <init>()VALOAD 0INVOKESPECIAL java/lang/Object.<init> ()VALOAD 0BIPUSH 100PUTFIELD com/baidu/main/test/Test.age : IALOAD 0LDC "Hello World"PUTFIELD com/baidu/main/test/Test.str : Ljava/lang/String;RETURNMAXSTACK = 2MAXLOCALS = 1// access flags 0x2private sum(II)IILOAD 1ILOAD 2IADDIRETURNMAXSTACK = 2MAXLOCALS = 3
}

对应的ASM信息如下:

public class TestDump implements Opcodes {public static byte[] dump() throws Exception {ClassWriter classWriter = new ClassWriter(0);FieldVisitor fieldVisitor;MethodVisitor methodVisitor;AnnotationVisitor annotationVisitor0;classWriter.visit(V1_8, ACC_PUBLIC | ACC_SUPER, "com/baidu/main/test/Test", null, "java/lang/Object", null);{fieldVisitor = classWriter.visitField(ACC_PUBLIC, "age", "I", null, null);fieldVisitor.visitEnd();}{fieldVisitor = classWriter.visitField(ACC_PUBLIC, "str", "Ljava/lang/String;", null, null);fieldVisitor.visitEnd();}{methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);methodVisitor.visitCode();methodVisitor.visitVarInsn(ALOAD, 0);methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);methodVisitor.visitVarInsn(ALOAD, 0);methodVisitor.visitIntInsn(BIPUSH, 100);methodVisitor.visitFieldInsn(PUTFIELD, "com/baidu/main/test/Test", "age", "I");methodVisitor.visitVarInsn(ALOAD, 0);methodVisitor.visitLdcInsn("Hello World");methodVisitor.visitFieldInsn(PUTFIELD, "com/baidu/main/test/Test", "str", "Ljava/lang/String;");methodVisitor.visitInsn(RETURN);methodVisitor.visitMaxs(2, 1);methodVisitor.visitEnd();}{methodVisitor = classWriter.visitMethod(ACC_PRIVATE, "sum", "(II)I", null, null);methodVisitor.visitCode();methodVisitor.visitVarInsn(ILOAD, 1);methodVisitor.visitVarInsn(ILOAD, 2);methodVisitor.visitInsn(IADD);methodVisitor.visitInsn(IRETURN);methodVisitor.visitMaxs(2, 3);methodVisitor.visitEnd();}classWriter.visitEnd();return classWriter.toByteArray();}
}

从ASM生成的代码中可以看到,age和str两个变量后并没有立刻赋值(赋值了不一定生效),而是在init方法里面进行了赋值。

2.对MainActivity进行插装

package com.baidu.plugin.printimport org.objectweb.asm.AnnotationVisitor
import org.objectweb.asm.Attribute
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.FieldVisitor
import org.objectweb.asm.Label
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes
import org.objectweb.asm.commons.AdviceAdapterclass PrintClassVisitor(nextVisitor: ClassVisitor, private val className: String): ClassVisitor(Opcodes.ASM5, nextVisitor) {override fun visit(version: Int,access: Int,name: String?,signature: String?,superName: String?,interfaces: Array<out String>?) {println("visit access $access className $className name $name  signature $signature")val numFiledVisitor = cv.visitField(Opcodes.ACC_PRIVATE, "age", "I", null, 25)numFiledVisitor.visitEnd()val strFiledVisitor = cv.visitField(Opcodes.ACC_PUBLIC, "str", "Ljava/lang/String;", null, "Hello World")strFiledVisitor.visitEnd()super.visit(version, access, name, signature, superName, interfaces)}override fun visitEnd() {super.visitEnd()}override fun visitField(access: Int,name: String?,descriptor: String?,signature: String?,value: Any?): FieldVisitor {println("visitField access $access className $className name $name  descriptor $descriptor")val filedVisitor = super.visitField(access, name, descriptor, signature, value)return MyPrintFieldVisitor(Opcodes.ASM5,filedVisitor)}override fun visitMethod(access: Int,name: String?,descriptor: String?,signature: String?,exceptions: Array<out String>?): MethodVisitor {val methodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions)return MyPrintMethodVisitor(Opcodes.ASM5,methodVisitor,access,className,name,descriptor)}}class MyPrintFieldVisitor(api: Int, filedVisitor: FieldVisitor) : FieldVisitor(api, filedVisitor) {override fun visitAnnotation(descriptor: String?, visible: Boolean): AnnotationVisitor {println("visitAnnotation descriptor $descriptor visible $visible")return super.visitAnnotation(descriptor, visible)}}class MyPrintMethodVisitor(api: Int,methodVisitor: MethodVisitor?,private val access: Int,private val className: String,private val name: String?,private val descriptor: String?
) : AdviceAdapter(api, methodVisitor, access, name, descriptor) {override fun onMethodEnter() {println("onMethodEnter access $access className $className name $name  descriptor $descriptor")if (name.equals("<init>") && descriptor.equals("()V")) {//每个classFile都有一个<init>的初始化方法(固定写法)mv.visitVarInsn(Opcodes.ALOAD, 0)mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false)mv.visitVarInsn(Opcodes.ALOAD, 0)//初始化定义的变量的值mv.visitIntInsn(BIPUSH, 100)mv.visitFieldInsn(PUTFIELD, "com/baidu/main/MainActivity", "age", "I" )//String的初始化会在构造方法中mv.visitVarInsn(Opcodes.ALOAD, 0)mv.visitLdcInsn("Hello World")mv.visitFieldInsn(PUTFIELD, "com/baidu/main/MainActivity", "str", "Ljava/lang/String" )mv.visitInsn(RETURN)}if (name.equals("sum999")) {//System.out.println("999999");mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");mv.visitLdcInsn("999999-begin")mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);}super.onMethodEnter()}override fun onMethodExit(opcode: Int) {println("onMethodExit access $access className $className name $name  descriptor $descriptor")if (name.equals("sum999")) {//System.out.println("999999");mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");mv.visitLdcInsn("999999-end")mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);}super.onMethodExit(opcode)}override fun visitFieldInsn(opcode: Int, owner: String?, name: String?, descriptor: String?) {println("visitFieldInsn opcode $opcode owner $owner name $name  descriptor $descriptor")super.visitFieldInsn(opcode, owner, name, descriptor)}override fun visitLocalVariable(name: String?,descriptor: String?,signature: String?,start: Label?,end: Label?,index: Int) {println("visitLocalVariable name $name  descriptor $descriptor start $start end $end index $index")super.visitLocalVariable(name, descriptor, signature, start, end, index)}override fun visitAttribute(attribute: Attribute?) {println("visitAttribute attribute $attribute")super.visitAttribute(attribute)}override fun visitLineNumber(line: Int, start: Label?) {println("visitLineNumber line $line start $start")super.visitLineNumber(line, start)}override fun visitFrame(type: Int,numLocal: Int,local: Array<out Any>?,numStack: Int,stack: Array<out Any>?) {println("visitFrame type $type  numLocal $numLocal local $local numStack $numStack stack $stack")super.visitFrame(type, numLocal, local, numStack, stack)}override fun visitLabel(label: Label?) {println("visitLabel label $label")super.visitLabel(label)}override fun visitCode() {println("visitCode")super.visitCode()}override fun visitMaxs(maxStack: Int, maxLocals: Int) {println("visitMaxs maxStack $maxStack maxLocals $maxLocals")super.visitMaxs(maxStack, maxLocals)}override fun visitEnd() {println("visitEnd")super.visitEnd()}
}

关键代码如下:

创建变量:

override fun visit(version: Int,access: Int,name: String?,signature: String?,superName: String?,interfaces: Array<out String>?) {println("visit access $access className $className name $name  signature $signature")val numFiledVisitor = cv.visitField(Opcodes.ACC_PRIVATE, "age", "I", null, 25)numFiledVisitor.visitEnd()val strFiledVisitor = cv.visitField(Opcodes.ACC_PUBLIC, "str", "Ljava/lang/String;", null, "Hello World")strFiledVisitor.visitEnd()super.visit(version, access, name, signature, superName, interfaces)}

注意:

cv.visitField(Opcodes.ACC_PUBLIC, "str", "Ljava/lang/String;", null, "Hello World")也给变量赋值了,但是没有生效。

在init方法中给变量赋值:

 override fun onMethodEnter() {println("onMethodEnter access $access className $className name $name  descriptor $descriptor")if (name.equals("<init>") && descriptor.equals("()V")) {//每个classFile都有一个<init>的初始化方法(固定写法)mv.visitVarInsn(Opcodes.ALOAD, 0)mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false)mv.visitVarInsn(Opcodes.ALOAD, 0)//初始化定义的变量的值mv.visitIntInsn(BIPUSH, 100)mv.visitFieldInsn(PUTFIELD, "com/baidu/main/MainActivity", "age", "I" )//String的初始化会在构造方法中mv.visitVarInsn(Opcodes.ALOAD, 0)mv.visitLdcInsn("Hello World")mv.visitFieldInsn(PUTFIELD, "com/baidu/main/MainActivity", "str", "Ljava/lang/String" )mv.visitInsn(RETURN)}super.onMethodEnter()}

如果不会写,可以参考Test.class的ASM生成代码,直接照抄就行。

插桩后的代码如下:

package com.baidu.main;import android.os.Bundle;
import androidx.activity.ComponentActivity;
import kotlin.Metadata;/* compiled from: MainActivity.kt */
@Metadata(d1 = {"\u0000&\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0010\b\n\u0002\b\u0005\n\u0002\u0010\t\n\u0000\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002J\u0012\u0010\u0003\u001a\u00020\u00042\b\u0010\u0005\u001a\u0004\u0018\u00010\u0006H\u0014J\u0018\u0010\u0007\u001a\u00020\b2\u0006\u0010\t\u001a\u00020\b2\u0006\u0010\n\u001a\u00020\bH\u0002J\u0018\u0010\u000b\u001a\u00020\b2\u0006\u0010\t\u001a\u00020\b2\u0006\u0010\n\u001a\u00020\bH\u0002J\u0010\u0010\f\u001a\u00020\u00042\u0006\u0010\r\u001a\u00020\u000eH\u0002¨\u0006\u000f"}, d2 = {"Lcom/baidu/main/MainActivity;", "Landroidx/activity/ComponentActivity;", "()V", "onCreate", "", "savedInstanceState", "Landroid/os/Bundle;", "sum", "", "i", "j", "sum999", "test", "time", "", "app_debug"}, k = 1, mv = {1, 8, 0}, xi = 48)
/* loaded from: classes4.dex */
public final class MainActivity extends ComponentActivity {private int age = 100;public String str;public MainActivity() {this.str = "Hello World";}/* access modifiers changed from: protected */@Override // androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activitypublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);test(100);sum(1, 2);}private final void test(long time) {Thread.sleep(time);}private final int sum(int i, int j) {return i + j;}private final int sum999(int i, int j) {System.out.println("999999-begin");int i2 = i + j;System.out.println("999999-end");return i2;}
}

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

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

相关文章

数据库 |试卷1试卷2

1.数据库语言四大语句 4.四大类&#xff08;DDL、DML、DQL、DCL&#xff09;_中度ddl-CSDN博客 数据定义&#xff08;data defination language&#xff09; 查询、创建、删除、使用 #查询所有数据库 show databases;#查询当前数据库 select database();#创建数据库 create …

C++ 65 之 模版的局限性

#include <iostream> #include <cstring> using namespace std;class Students05{ public:string m_name;int m_age;Students05(string name, int age){this->m_name name;this->m_name age;} };// 两个值进行对比的函数 template<typename T> bool …

[思考记录]未来已近 - AI带来的变化,以及简单思考

最近在我们的内部知识库系统中引入了个比较有意思的功能——借助AI大模型&#xff0c;对思考总结类日志做要点提炼。这个想法来自涛哥&#xff0c;目前做了初步的验证性实现。尽管还没有对输出结果做调优&#xff0c;但已展现出的效果仍让我略感惊艳。不由地感叹&#xff0c;&a…

如何掌握 Java 中的安全机制,如权限控制和加密解密

Java是一门具有强大安全功能的编程语言&#xff0c;它内置了多种安全机制&#xff0c;包括权限控制、加密解密、认证授权等。 一、权限控制 权限控制是Java安全模型的重要组成部分&#xff0c;它主要通过Java安全管理器&#xff08;Security Manager&#xff09;和权限&#…

Python 数据可视化 多色散点图

Python 数据可视化 多色散点图 fig, ax plt.subplots() max_line max([max(merged_df[unif_ref_value]), max(merged_df[unif_rust_value])]) min_line min([max(merged_df[unif_ref_value]), max(merged_df[unif_rust_value])]) ax.plot([min_line, max_line], [min_line, …

【系统架构设计师】三、数据库系统(事务并发|封锁协议|数据库安全|商业智能|SQL语句)

目录 一、事务并发 1.1 事务概述 1.2 并发控制 1.3 封锁 1.3.1 X 封锁和 S 封锁 1.3.2 三级封锁协议 二、数据库安全 2.1 备份(转储)与恢复 2.2 备份分类 2.3 数据库故障 三、商业智能 3.1 数据仓库 3.2 数据仓库的结构-OLAP 3.3 数据挖掘 3.4 分布式数据库 四…

DDei在线设计器-API-DDei

DDei DDei是DDeiEditor的一个内置对象&#xff0c;实现了部分与图形显示有关但与设计器无关的功能、配置以及公共方法。 在图形内部一般不直接访问DDeiEditor&#xff0c;而是使用DDei&#xff0c;DDeiEditor的绝大多数初始化属性、回调函数等在DDei也能获取。。 本篇最后提供的…

研导AI写作:辅助创作的未来伙伴

人工智能&#xff08;AI&#xff09;写作技术正逐渐成为创作者们的强大助手。它不仅提高了写作效率&#xff0c;还拓展了创作的边界。本文将探讨AI写作的辅助作用&#xff0c;分析其如何在不同层面上促进人类创作的发展。 提升写作效率 AI写作的第一个辅助作用是提升写作效率…

GD32错误调试篇:串口通讯乱码/stm32移植到GD32后串口通讯乱码等问题

本文章基于兆易创新GD32 MCU所提供的2.2.4版本库函数开发 向上代码兼容GD32F450ZGT6中使用 后续项目主要在下面该专栏中发布&#xff1a; https://blog.csdn.net/qq_62316532/category_12608431.html?spm1001.2014.3001.5482 感兴趣的点个关注收藏一下吧! 电机驱动开发可以跳转…

小程序分页新写法

// pages/query/query.js import {request } from ../../utils/request; Page({/*** 页面的初始数据*/data: {tabClickIndex: ,page: 1,limit: 10,listData: []},/*** 生命周期函数--监听页面加载*/onLoad(options) {this.getList()},/*** 生命周期函数--监听页面初次渲染完成*…

【JS】上传文件显示文件的为空,显示的文件参数内容只有uid

上传的文件参数file里面只包含uid&#xff0c;没有其他信息 例子解决办法 例子 例如使用elment ui的el-upload组件上传文件&#xff0c;会导致上传的文件参数file里面只包含uid&#xff0c;没有其他信息&#xff0c;如图&#xff1a; 正确应为如下图&#xff1a; 解决办法 …

云上战场:ToDesk云电脑、青椒云、顺网云全面对决

前言 记得端午放假期间&#xff0c;我已经在旅游的路上了&#xff0c;老板突然发短信&#xff0c;让我给他画个图&#xff0c;我手上的战斗机已经是十年前的老古董了(平常一直用的公司电脑&#xff0c;也没想过要换)&#xff0c;压根满足不了老板的任务要求&#xff0c;不得已&…

WPF 程序 分布式 自动更新 登录 打包

服务器server端 core api 客户端WPF // 检查应用更新 //1、获取最新文件列表 // var files fileService.GetUpgradeFiles(); // 2、文件判断&#xff0c;新增的直接下载&#xff1b;更新的直接下载&#xff1b;删除的直接删除 // 客户端本地需要一个记录…

SpringMVC系列三: Postman(接口测试工具)

接口测试工具 &#x1f49e;Postman(接口测试工具)Postman介绍Postman是什么Postman相关资源Postman安装Postman快速入门Postman完成Controller层测试其它说明 &#x1f49e;课后作业 上一讲, 我们学习的是SpringMVC系列二: 请求方式介绍 现在打开springmvc项目 &#x1f49e…

2024年十大数据集成工具和软件应用场景解析

详细阐述了十大数据集成工具及其优缺点&#xff1a; 数据集成的挑战 在当今的商业环境中&#xff0c;企业常常面临着数据分散、系统孤立的难题。传统的数据集成方式&#xff0c;就像一张复杂的蜘蛛网&#xff0c;难以理顺&#xff0c;令人头痛不已。 数据孤岛: 各个业务系统独立…

window.history()方法总结

window.history()方法总结 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; window.history是JavaScript中的一个内置对象&#xff0c;代表浏览器的历史记录。该…

【博士每天一篇文献-算法】Memory aware synapses_ Learning what (not) to forget

阅读时间&#xff1a;2023-12-13 1 介绍 年份&#xff1a;2018 作者&#xff1a;Rahaf Aljundi,丰田汽车欧洲公司研究员;阿卜杜拉国王科技大学(KAUST)助理教授;Marcus Rohrbach德国达姆施塔特工业大学多模式可靠人工智能教授 会议&#xff1a; Proceedings of the European c…

系统学习PLC

1.OB组织块 程序循环 PC ob1执行一次 ob123也执行一次 是 statup是程序启动的是第一个周期先执行starup&#xff08;0b100&#xff09;然后在执行ob1和0b123.这二个循环&#xff0c;周期执行这二个循环。1000是1s 2.DB块 建立指定数据块可以直接建立自己喜欢的类型 3.FB与…

轻量级 ioc/aop 框架 loveqq 1.0 发布,完全替换掉若依底层 spring 及其 starter

loveqq-framework 轻量级 ioc/aop 框架&#xff0c;比 spring 更强大的条件注解推断&#xff0c;打包后支持 jar index 启动。 本次更新&#xff1a; 正式更名为&#xff1a;loveqq-famework 新增&#xff1a;loveqq-boot-starter-mybatis 新增&#xff1a;loveqq-boot-start…

网络安全--安全设备(一)Dos

安全设备--Dos 一、Dos 是什么二、DDos是什么三、Dos&DDos的区别四、产品防御Dos&DDos方式五、常见的DDoS攻击类型包括但不限于以下几种&#xff1a; 一、Dos 是什么 Dos(拒绝服务攻击,Denial-of-Service)&#xff0c;是一种试图通过压倒网络或服务器来阻止合法用户访…