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+ 0 . (复读)前排温馨提醒:本实验任务量可能较大,请尽早开始;
34+ 1 . Problem 需要在实验报告中作答,如有要求需附上截图;
35+ 2 . Task 需要在实验报告中附上代码,结果截图和** 简要** 的实验过程;
36+ 3 . ** 不应** 修改不含 TODO 标记的代码,或添加额外的函数;
37+ 4 . 欢迎在实验报告中吐槽/建议/记日记(划掉
38+ 5 . 发挥创造力吧;)
39+
3140## 一、危险的计算器
3241
3342### RCE 攻击
@@ -100,7 +109,7 @@ void foo() {
100109
101110> [ !NOTE] Task 1.1 (10 pts)
102111>
103- > 你的任务是:利用栈溢出漏洞,控制程序执行 ` ./malware ` 。这个“恶意程序”会检测自己的父进程调用,如果发现自己由 ` dark-calc ` 调用,就会输出 ` You have successfully detonated the bomb! Congratulations! ` ,表示你已经成功完成了任务。
112+ > 你的任务是:利用栈溢出漏洞,控制程序执行 ` ./malware ` 。这个“恶意程序”会检测自己的父进程调用,如果发现自己由 ` dark-calc ` 调用,就会输出 ` You have successfully detonated the bomb! Congratulations! ` ,表示你已经成功完成了任务。在实验报告中描述你的攻击流程。
104113
105114#### 实验步骤
106115
@@ -143,7 +152,7 @@ void foo() {
143152
144153> [! tip]
145154>
146- > cmd 字符串对应地址处的值在输入完后不变。
155+ > 注意: cmd 字符串对应地址处的值在输入完后不变。
147156>
148157> 我们的目标类似于执行 `system(" ./malware" )` ,如果你已经构造成功了 payload 使程序执行 `system(" ./malware" )` ,但程序在 `system` 函数的内部崩溃了,这在我们的预期内。** 也就是说,只需要见到 `You have successfully detonated the bomb! Congratulations!` 这一行就算通过实验。**
149158>
@@ -159,7 +168,7 @@ void foo() {
159168
160169> [! NOTE ]Problem 1.1 (5 pts)
161170>
162- > 除了在报告描述你的攻击流程之外,你还需要在报告中回答以下问题: 实验任务中导致溢出的函数早就成为了一个臭名昭著的函数,现如今几乎没有人会再使用它。但即使在 2025 年的今天,我们依然会看到许许多多的栈溢出、堆溢出漏洞。请你思考一下,还有什么其他的场景、函数会导致溢出?你自己是否在编程中遇到过栈溢出的情况?
171+ > 实验任务中导致溢出的函数早就成为了一个臭名昭著的函数,现如今几乎没有人会再使用它。但即使在 2025 年的今天,我们依然会看到许许多多的栈溢出、堆溢出漏洞。请你思考一下,还有什么其他的场景、函数会导致溢出?你自己是否在编程中遇到过栈溢出的情况?
163172
164173# # 二、更危险的计算器
165174
@@ -179,7 +188,7 @@ void foo() {
179188
180189但是存在漏洞,使得我们可以编译出栈空间可执行的程序(参照[这篇文章](https:// mp.weixin.qq.com/ s/ D43kHb5_b0U9EPt_dA4p7g))。
181190
182- 很不幸的是,上述危险的计算器的编译过程存在这样的漏洞 ,使这个计算器变得更加危险了。这意味着我们可以利用漏洞,在栈空间执行自己编写的简易汇编程序 ,例如修改一些寄存器的值之后跳转到其他地方。
191+ 很不幸的是,我们编译危险的计算器时没有注意到这一点 ,使这个计算器变得更加危险了。这意味着我们可以在栈空间执行自己编写的简易汇编程序 ,例如修改一些寄存器的值之后跳转到其他地方。
183192
184193# ## 实验任务
185194
@@ -189,23 +198,29 @@ void foo() {
189198
190199> [! tip]
191200>
192- > 可以用与 Task 1.1 相似的方法保存 payload 并进行调试。
201+ > 可以用与 Task 1.1 相似的方法保存 payload 并在 GDB 调试。
202+ >
203+ > GDB 内,默认情况下程序的栈空间位置在** 较长时间内** 固定;而直接执行程序时,栈空间位置一般是随机的,且与 GDB 内不同。
193204>
194- > 在 GDB 中,默认程序的栈空间位置在** 一次重启期间** 固定。
195205> 我们需要在栈空间内执行代码,期望效果是** 赋值输入参数** 并** 调用函数** 。
196206>
197- > 大家学过 CSAPP ,打过 BombLab,想必对常用 x86- 64 汇编指令的机器码有一些了解,此处给出 mov 和 jmp 指令的机器码参考 :
207+ > 大家已经学过 CSAPP 中有关汇编与机器码对应的知识点,此处给出 x86- 64 汇编指令 mov 和 jmp 指令的机器码形式参考 :
198208>
199- > - `mov $ imm, % rxx` (64 位立即数移动,占 7 字节):`48 c7 [Mod+ Reg+ R/ M](1 byte) [imm](4 byte)`
209+ > - `mov $ imm, % rxx` (64 位立即数移动,共 7 字节):`48 ` `c7` ` [Mod+ Reg+ R/ M]` (1 字节) ` [imm]` (4 字节)
200210> - `Mod` 指定寄存器模式(2 位,`11 ` 为寄存器寻址)
201211> - `Reg` 源操作数(3 位,这里是立即数,所以置为 0 )
202212> - `R/ M` 指定目标寄存器(3 位);
203- > - `jmp *% rxx` (跳转到 `rxx` 寄存器指向的地址,占 2 字节):`ff [Mod+ Reg+ R/ M](1 byte)`
213+ > - `jmp *% rxx` (跳转到 `rxx` 寄存器指向的地址,共 2 字节):`ff` ` [Mod+ Reg+ R/ M]` (1 字节)
204214> - `Mod` 指定寄存器模式(2 位,`11 ` 为寄存器寻址)
205215> - `Reg` 设为 `100 ` 指定此指令为 `jmp` 指令(3 位,此处代表指令模式选择值)
206216> - `R/ M` 指定目标寄存器(3 位);
207217>
208218> < s> 善用人工智能工具编写汇编/ 机器代码(逃< / s>
219+ >
220+ > 样例截图:
221+ >
222+ > 
223+ >
209224
210225# # 三、栈溢出的防御
211226
@@ -232,17 +247,23 @@ gcc -fno-pie -no-pie -o dark-calc-my dark-calc.c
232247
233248> [ !NOTE] Problem 3.2 (5 pts)
234249>
235- > 尝试根据资料复原出之前实验中 ` dark-calc ` 的编译指令。
250+ > 尝试根据线索复原出之前实验中(漏洞百出的) ` dark-calc ` 的编译指令。
236251
237252> [ !tip]
238253>
239254> 通过** 特定命令行参数** ,可以不开启防御机制;
240255>
241- > 为触发可写栈空间漏洞,编译时包含了额外文件,不仅包含 ` dark-calc.c ` 。
256+ > 为触发可写栈空间漏洞,编译时包含了 ** 额外文件 ** (在哪呢
242257
243258## 四、栈帧的更多应用——协程
244259
260+ > [ !tip]
261+ >
245262> 改编自 2024 StackLab 的第三部分(源于 2022 年 Kieray Lab),减少协程部分的代码工作量,替换为阅读思考题。
263+ >
264+ > 往届 TA 在 ` coroutine ` 文件夹中留下了 ` QA.md ` 作为常见问题 QA。
265+ >
266+ > (此次不用亲自实现如此多的功能,不过对理解有帮助)
246267
247268在前两项任务中,我们已经加深了对程序运行时的栈帧的认识,接下来,我们使用栈帧和一定的汇编语言,来给 C 语言实现一些更加现代的功能吧。
248269
@@ -357,7 +378,7 @@ funcB:
357378
358379> [ !NOTE] Problem 4.4 (2 pts)
359380>
360- > 在实验报告中填写你的答案 :假如变量 x 被存放在栈帧上,在 restore 操作后,x 的值为 _______________ _ ;假如变量 x 被存放在寄存器上,在 restore 操作后,x 的值为 _______________ _ 。
381+ > 在实验报告中填写答案 :假如变量 x 被存放在栈帧上,在 restore 操作后,x 的值为 _______________ _ ;假如变量 x 被存放在寄存器上,在 restore 操作后,x 的值为 _______________ _ 。
361382
362383由于变量放在寄存器还是内存是由编译器决定的,根据编译器策略的不同,可能会导致同一份代码产生不同的运行结果。为了简化问题,我们可以做出如下限定:在 save 语句后修改过的局部变量,在 restore 操作后都是未知的,让开发者不要在 restore 之后直接使用这些变量的值。
363384
@@ -396,7 +417,7 @@ naive_func(void **p):
396417>
397418> 也许你在课上学过函数开头两条指令的固定格式 ` push rbp; mov rbp, rsp ` 。但是前面所写的 naive_func 显然不遵循这样的格式,为什么这是可以的呢?
398419
399- 接下来,我们开始着手实现 save 和 restore 函数,为了实现更多后续功能,这两个函数的定义与上文所述有略微不同,请参见 API 手册 。
420+ 接下来,我们开始着手实现 save 和 restore 函数,为了实现更多后续功能,这两个函数的定义与上文所述有略微不同,请参见 API 文档(coroutine-api.md) 。
400421
401422> [ !NOTE] Task 4.1 (8 pts)
402423>
@@ -561,11 +582,15 @@ funcB:
561582
562583> [ !NOTE] Problem 4.7 (5 pts)
563584>
564- > 请阅读 ` context.c ` 中的函数 ` send ` 、 ` yield ` 、 ` back_to_reality ` ,` context.h ` 中对 ` try ` 、 ` catch ` 和 ` throw ` 的宏定义,并在报告中解释这些函数和宏定义的功能。
585+ > 请阅读 ` context.c ` 中的函数 ` send ` 、 ` yield ` 、 ` back_to_reality ` ,以及 ` context.h ` 中对 ` try ` 、 ` catch ` 和 ` throw ` 的宏定义,并在报告中解释这些函数和宏定义的功能。
565586
566587> [ !NOTE] Problem 4.8 (5 pts)
567588>
568- > 任选 test6、test7、test8 中的一个,使用 GDB 动态调试,运用 ` x/10gx $rsp ` 指令查看至少两种不同位置处开始的栈帧或是伪栈帧并截图,体会协程中开辟虚拟栈空间的设计。
589+ > 任选 test7、test8 中的一个,使用 GDB 动态调试,运用 ` x/10gx $rsp ` 指令查看默认栈帧,和协程产生的伪栈帧,体会协程中开辟虚拟栈空间的设计。
590+ >
591+ > 在报告中提交截图。
592+ >
593+ > - 参考 test6 的实验现象:![ 栈帧和伪栈帧] ( flowlab/problem4-8.png )
569594
570595### 协程的一些实际应用
571596
@@ -600,7 +625,7 @@ def game():
600625>
601626> 基于上面的讨论,请你完善 ` main.c ` 中的 ` progress_bar ` 函数,实现一个自定义的进度条动画。发挥你的想象力即可。
602627
603- ![ 进度条] ( flowlab/task3_result .gif )
628+ ![ 进度条] ( flowlab/coroutine_result .gif )
604629
605630## 五、控制流和栈帧的进一步思考
606631
@@ -731,6 +756,8 @@ def game():
731756> 长崎·raise: 要怎么做才能回来?只要是我能做的,我什么都愿意做!
732757>
733758> 丰try·祥子: 你这个人,满脑子都只想着自己呢。
759+ >
760+ > ![ 你这个人,满脑子都只想着自己呢] ( flowlab/try_raise.png )
734761
735762和其它 lab 的评分标准相同,除去 Honor Part 的内容满分为 100 分,Honor Part 只能用来抵前面报告的扣分和迟交得分。Lab 的分数上限仍为 100 分。
736763
@@ -785,7 +812,7 @@ int main() {
785812## 参考资料与鸣谢
786813
787814- CMU 原版 [Attack Lab](http://csapp.cs.cmu.edu/3e/labs.html)
788- - 2022年 Kieray Lab,作者 @[虎鲸](https://github.com/zzzly3)
789- - 本实验参考 2024 年的 StackLab 实验开发,鸣谢24 Fall TA:@[y<sup>2</sup>](https://github.com/Cameudis)、@[Yosame](https://github.com/Yosame08)
815+ - 2022 Kieray Lab,作者 @[虎鲸](https://github.com/zzzly3)
816+ - 本实验参考 2024 年的 StackLab 实验开发,鸣谢 2024 Fall TA:@[y<sup>2</sup>](https://github.com/Cameudis)、@[Yosame](https://github.com/Yosame08)
790817
791818> 负责助教:周弈成 @[JurFal](https://github.com/JurFal) 朱程炀 @[Zecyel](https://github.com/Zecyel)
0 commit comments