11# Lab3: FlowLab
22
3- > Deadline:2025-11-11 23:59:59
3+ > Deadline:2025-11-18 23:59:59
44
55## 〇、实验简介
66
77### 实验简介
88
99栈帧与程序控制流相关实验。
1010
11- 本学期,我们仍然将金老师 ICS 第三个 Lab 回炉重造,减轻代码工作量并添加更多讲解和提示,以加深各位同学对栈帧和程序控制流的理解,并探索协程的应用,最后从宏观角度思考程序控制流的发展,丰富同学们的知识面 。
11+ 本学期,我们依然将金老师 ICS 第三个 Lab 回炉重造,减轻代码工作量并添加更多讲解和提示,以加深各位同学对栈帧和程序控制流的理解。
1212
1313本次Lab由五个部分组成,含四个主题:
1414
1515- 尝试在含有漏洞的程序中实现** 任意代码执行**
1616- 学习 Canary 机制,了解栈溢出的** 防御**
1717- 在栈帧基础上探索更多有意思的功能,如** 协程**
18- - 从高处思考程序** 控制流** 的运行
18+ - 从高处思考程序** 控制流** 的运行机制,探索其发展方向
1919
2020> [ !tip]
2121>
2828> - ` b *[address] ` :直接在指定地址处设定断点(例如 ` b *0x401000 ` )
2929> - ![ 设定断点] ( flowlab/b_gdb.png )
3030
31+ ### 实验要求
32+
33+ 1 . Problem 需要在实验报告中作答,如有要求需附上截图;
34+ 2 . Task 需要在实验报告中附上代码,结果截图和** 简要** 的实验过程;
35+ 3 . ** 不应** 修改不含 TODO 标记的代码,或添加额外的函数;
36+ 4 . 欢迎在实验报告中吐槽/建议/记日记(划掉
37+ 5 . 发挥创造力吧;)
38+
3139## 一、危险的计算器
3240
3341### RCE 攻击
@@ -100,7 +108,7 @@ void foo() {
100108
101109> [ !NOTE] Task 1.1 (10 pts)
102110>
103- > 你的任务是:利用栈溢出漏洞,控制程序执行 ` ./malware ` 。这个“恶意程序”会检测自己的父进程调用,如果发现自己由 ` dark-calc ` 调用,就会输出 ` You have successfully detonated the bomb! Congratulations! ` ,表示你已经成功完成了任务。
111+ > 你的任务是:利用栈溢出漏洞,控制程序执行 ` ./malware ` 。这个“恶意程序”会检测自己的父进程调用,如果发现自己由 ` dark-calc ` 调用,就会输出 ` You have successfully detonated the bomb! Congratulations! ` ,表示你已经成功完成了任务。在实验报告中描述你的攻击流程。
104112
105113#### 实验步骤
106114
@@ -143,7 +151,7 @@ void foo() {
143151
144152> [! tip]
145153>
146- > cmd 字符串对应地址处的值在输入完后不变。
154+ > 注意: cmd 字符串对应地址处的值在输入完后不变。
147155>
148156> 我们的目标类似于执行 `system(" ./malware" )` ,如果你已经构造成功了 payload 使程序执行 `system(" ./malware" )` ,但程序在 `system` 函数的内部崩溃了,这在我们的预期内。** 也就是说,只需要见到 `You have successfully detonated the bomb! Congratulations!` 这一行就算通过实验。**
149157>
@@ -159,7 +167,7 @@ void foo() {
159167
160168> [! NOTE ]Problem 1.1 (5 pts)
161169>
162- > 除了在报告描述你的攻击流程之外,你还需要在报告中回答以下问题: 实验任务中导致溢出的函数早就成为了一个臭名昭著的函数,现如今几乎没有人会再使用它。但即使在 2025 年的今天,我们依然会看到许许多多的栈溢出、堆溢出漏洞。请你思考一下,还有什么其他的场景、函数会导致溢出?你自己是否在编程中遇到过栈溢出的情况?
170+ > 实验任务中导致溢出的函数早就成为了一个臭名昭著的函数,现如今几乎没有人会再使用它。但即使在 2025 年的今天,我们依然会看到许许多多的栈溢出、堆溢出漏洞。请你思考一下,还有什么其他的场景、函数会导致溢出?你自己是否在编程中遇到过栈溢出的情况?
163171
164172# # 二、更危险的计算器
165173
@@ -179,7 +187,7 @@ void foo() {
179187
180188但是存在漏洞,使得我们可以编译出栈空间可执行的程序(参照[这篇文章](https:// mp.weixin.qq.com/ s/ D43kHb5_b0U9EPt_dA4p7g))。
181189
182- 很不幸的是,上述危险的计算器的编译过程存在这样的漏洞 ,使这个计算器变得更加危险了。这意味着我们可以利用漏洞,在栈空间执行自己编写的简易汇编程序 ,例如修改一些寄存器的值之后跳转到其他地方。
190+ 很不幸的是,我们编译危险的计算器时没有注意到这一点 ,使这个计算器变得更加危险了。这意味着我们可以在栈空间执行自己编写的简易汇编程序 ,例如修改一些寄存器的值之后跳转到其他地方。
183191
184192# ## 实验任务
185193
@@ -189,23 +197,29 @@ void foo() {
189197
190198> [! tip]
191199>
192- > 可以用与 Task 1.1 相似的方法保存 payload 并进行调试。
200+ > 可以用与 Task 1.1 相似的方法保存 payload 并在 GDB 调试。
201+ >
202+ > GDB 内,默认情况下程序的栈空间位置在** 较长时间内** 固定;而直接执行程序时,栈空间位置一般是随机的,且与 GDB 内不同。
193203>
194- > 在 GDB 中,默认程序的栈空间位置在** 一次重启期间** 固定。
195204> 我们需要在栈空间内执行代码,期望效果是** 赋值输入参数** 并** 调用函数** 。
196205>
197- > 大家学过 CSAPP ,打过 BombLab,想必对常用 x86- 64 汇编指令的机器码有一些了解,此处给出 mov 和 jmp 指令的机器码参考 :
206+ > 大家已经学过 CSAPP 中有关汇编与机器码对应的知识点,此处给出 x86- 64 汇编指令 mov 和 jmp 指令的机器码形式参考 :
198207>
199- > - `mov $ imm, % rxx` (64 位立即数移动,占 7 字节):`48 c7 [Mod+ Reg+ R/ M](1 byte) [imm](4 byte)`
208+ > - `mov $ imm, % rxx` (64 位立即数移动,共 7 字节):`48 ` `c7` ` [Mod+ Reg+ R/ M]` (1 字节) ` [imm]` (4 字节)
200209> - `Mod` 指定寄存器模式(2 位,`11 ` 为寄存器寻址)
201210> - `Reg` 源操作数(3 位,这里是立即数,所以置为 0 )
202211> - `R/ M` 指定目标寄存器(3 位);
203- > - `jmp *% rxx` (跳转到 `rxx` 寄存器指向的地址,占 2 字节):`ff [Mod+ Reg+ R/ M](1 byte)`
212+ > - `jmp *% rxx` (跳转到 `rxx` 寄存器指向的地址,共 2 字节):`ff` ` [Mod+ Reg+ R/ M]` (1 字节)
204213> - `Mod` 指定寄存器模式(2 位,`11 ` 为寄存器寻址)
205214> - `Reg` 设为 `100 ` 指定此指令为 `jmp` 指令(3 位,此处代表指令模式选择值)
206215> - `R/ M` 指定目标寄存器(3 位);
207216>
208217> < s> 善用人工智能工具编写汇编/ 机器代码(逃< / s>
218+ >
219+ > 样例截图:
220+ >
221+ > 
222+ >
209223
210224# # 三、栈溢出的防御
211225
@@ -232,13 +246,13 @@ gcc -fno-pie -no-pie -o dark-calc-my dark-calc.c
232246
233247> [ !NOTE] Problem 3.2 (5 pts)
234248>
235- > 尝试根据资料复原出之前实验中 ` dark-calc ` 的编译指令。
249+ > 尝试根据线索复原出之前实验中(漏洞百出的) ` dark-calc ` 的编译指令。
236250
237251> [ !tip]
238252>
239253> 通过** 特定命令行参数** ,可以不开启防御机制;
240254>
241- > 为触发可写栈空间漏洞,编译时包含了额外文件,不仅包含 ` dark-calc.c ` 。
255+ > 为触发可写栈空间漏洞,编译时包含了 ** 额外文件 ** (在哪呢
242256
243257## 四、栈帧的更多应用——协程
244258
@@ -357,7 +371,7 @@ funcB:
357371
358372> [ !NOTE] Problem 4.4 (2 pts)
359373>
360- > 在实验报告中填写你的答案 :假如变量 x 被存放在栈帧上,在 restore 操作后,x 的值为 _______________ _ ;假如变量 x 被存放在寄存器上,在 restore 操作后,x 的值为 _______________ _ 。
374+ > 在实验报告中填写答案 :假如变量 x 被存放在栈帧上,在 restore 操作后,x 的值为 _______________ _ ;假如变量 x 被存放在寄存器上,在 restore 操作后,x 的值为 _______________ _ 。
361375
362376由于变量放在寄存器还是内存是由编译器决定的,根据编译器策略的不同,可能会导致同一份代码产生不同的运行结果。为了简化问题,我们可以做出如下限定:在 save 语句后修改过的局部变量,在 restore 操作后都是未知的,让开发者不要在 restore 之后直接使用这些变量的值。
363377
@@ -396,7 +410,7 @@ naive_func(void **p):
396410>
397411> 也许你在课上学过函数开头两条指令的固定格式 ` push rbp; mov rbp, rsp ` 。但是前面所写的 naive_func 显然不遵循这样的格式,为什么这是可以的呢?
398412
399- 接下来,我们开始着手实现 save 和 restore 函数,为了实现更多后续功能,这两个函数的定义与上文所述有略微不同,请参见 API 手册 。
413+ 接下来,我们开始着手实现 save 和 restore 函数,为了实现更多后续功能,这两个函数的定义与上文所述有略微不同,请参见 API 文档(coroutine-api.md) 。
400414
401415> [ !NOTE] Task 4.1 (8 pts)
402416>
@@ -561,11 +575,15 @@ funcB:
561575
562576> [ !NOTE] Problem 4.7 (5 pts)
563577>
564- > 请阅读 ` context.c ` 中的函数 ` send ` 、 ` yield ` 、 ` back_to_reality ` ,` context.h ` 中对 ` try ` 、 ` catch ` 和 ` throw ` 的宏定义,并在报告中解释这些函数和宏定义的功能。
578+ > 请阅读 ` context.c ` 中的函数 ` send ` 、 ` yield ` 、 ` back_to_reality ` ,以及 ` context.h ` 中对 ` try ` 、 ` catch ` 和 ` throw ` 的宏定义,并在报告中解释这些函数和宏定义的功能。
565579
566580> [ !NOTE] Problem 4.8 (5 pts)
567581>
568- > 任选 test6、test7、test8 中的一个,使用 GDB 动态调试,运用 ` x/10gx $rsp ` 指令查看至少两种不同位置处开始的栈帧或是伪栈帧并截图,体会协程中开辟虚拟栈空间的设计。
582+ > 任选 test7、test8 中的一个,使用 GDB 动态调试,运用 ` x/10gx $rsp ` 指令查看默认栈帧,和协程产生的伪栈帧,体会协程中开辟虚拟栈空间的设计。
583+ >
584+ > 在报告中提交截图。
585+ >
586+ > - 参考 test6 的实验现象:![ 栈帧和伪栈帧] ( flowlab/problem4-8.png )
569587
570588### 协程的一些实际应用
571589
@@ -731,6 +749,8 @@ def game():
731749> 长崎·raise: 要怎么做才能回来?只要是我能做的,我什么都愿意做!
732750>
733751> 丰try·祥子: 你这个人,满脑子都只想着自己呢。
752+ >
753+ > ![ 你这个人,满脑子都只想着自己呢] ( flowlab/try_raise.png )
734754
735755和其它 lab 的评分标准相同,除去 Honor Part 的内容满分为 100 分,Honor Part 只能用来抵前面报告的扣分和迟交得分。Lab 的分数上限仍为 100 分。
736756
0 commit comments