ics-boomlab

BombLab
题目下载
一、实验简介

CSAPP 第三章配套实验。

本学期,我们对 csapp 的经典 bomblab 进行了全面升级(除了难度)。你将假扮一位精通 x86汇编语言 / Linux / gdb / 数据结构 的逆向工程大师,在这款全新的代码世界冒险游戏中冒险,发现隐藏在机器码背后的真相……
本次Lab由两个部分组成:

一个互动式 gdb 教程:gdb-tutor
一个包含若干个关卡的二进制炸弹:Bomb+
你的目标是拆除炸弹,无伤通过Bomb+的所有关卡。

二、实验内容

下载链接:bomblab-handout

互动式 gdb 教程 gdb-tutor

本部分不占分,也不要求必须完成。

在挑战 BombLab 时,gdb是一个非常有用的工具,但以往的 BombLab 只会列出一些常用的 gdb 指令,并不会教大家如何使用。

为了降低本 Lab 的上手难度,帮助大家掌握 gdb,认识这一强大的工具,我们编写了这个互动式的 gdb 教程。

使用方法:直接执行 ./gdb-tutor,教程源码见 gdb-tutor.c。

二进制炸弹 Bomb+

这是一个包含若干关卡的可执行文件。只有你输入满足条件的关卡口令时,才能通过该关卡,到达下一个关卡。如果口令错误,炸弹就会爆炸!(程序会打印爆炸信息并立刻退出)

你的目标是找到所有关卡的正确口令,让炸弹成功解除。炸弹制造者不小心给出了 main.cpp ,其中包含了Bomb+的主要流程,你可以参考这个源文件了解炸弹的大致逻辑。

如果炸弹爆炸,它将会输出 BOOM!!!,否则通过每一关后炸弹都会恭喜你;在通关后,它将会输出 Cool! your skill on Reverse Engineering is great.;而通关真结局后,它将会输出 You are really a Master of Reverse Engineering!。(详见 main.cpp )

炸弹会读取 fail.txt 并在爆炸时打印其内容,如果你想要很酷炫的爆炸,可以自行修改 fail.txt 或直接将其删去。

实验各个关卡涉及的知识大致如下:

函数调用
循环
分支
递归
面向对象
循环队列
Secret. ████

请注意,Secret的解锁条件在第三关中进行了提示,或许你能在 main.cpp 的某个函数中发现一些违和之处……

三、实验步骤

完整阅读本实验文档、下载题目附件
跟随 gdb-tutor 学习 gdb 的基础使用方法
使用静态分析与动态分析方法分析 Bomb+,尽力找出正确的口令
编写实验报告,在 elearning 上提交压缩包
四、提交事项

提交格式

新建文件夹,以你的学号命名(例如 22307130001)。
将实验报告 report.pdf 以及正确口令 password.txt 放入这个文件夹。注意,password.txt 需要满足可以用重定向秒杀 Bomb+ 的要求(我们会在后面介绍什么是重定向),我们会用这个来判断你通过了几关。
在上级文件夹使用 tar -cf .tar 将文件夹压缩成 tar 包,你会得到一个名为 .tar 的文件。(请把 替换为你的学号)
你的实验报告应包含以下内容:

姓名和学号
每个关卡的推演过程(重点),如你推测的函数的功能
拆弹成功的截图(随便弄下)
如果有,请列出引用的内容以及参考的资料
意见+建议(可选)
助教の温馨提示

实验报告是用来判断你是否 独立思考 来解决本次Lab的。

我们不希望看到冗长或表意混乱的报告,请一定不要把报告写成论文QaQ

评分

项目 分值
提交格式正确 5%
通过正常关卡 6*13% 78%
通过隐藏关卡 7%
实验报告 10%
另:抄袭倒扣分!!勿谓言之不预。

反卷斗士の承诺

实验过程非抄袭、提交格式正确且通过所有关卡的同学,实验报告部分赋满分。

五、实验指导

本题本质上是一道逆向工程题,需要你在没有源代码的情况下复原程序编写者的意图与程序的逻辑。你可能会好奇,我们为什么要学习逆向工程、学习汇编:作为科班CS学生,你需要知道自己写出来的程序到底会变成什么样子,到底如何运行,这样你才能知道如何写出更好的程序——正是这些底层的细节将科班程序员和培训班程序员区分开来。这个Lab将会帮助你搞清楚机器码 / 汇编语言具体而言如何运作。

除此以外,这个Lab还会带你入门逆向工程。逆向工程作为信息安全的一个研究领域,有着许多有趣的应用领域——注册机、软件破解、游戏安全(如修改器、外挂)……除了这些看起来很恶意的应用场景以外,逆向工程一个非常重要的作用就是帮助白帽黑客们找到程序的漏洞,发掘程序的安全问题。不过,最纯粹的逆向工程热爱者,往往是出于自己的好奇心来逆向闭源的软件——这玩意到底怎么实现的?

如果你对逆向工程感兴趣,可以试着从CTF(Capture The Flag)竞赛开始。逆向工程是CTF竞赛的一个主要领域,比赛中出题人会用各种语言、工具编写赛题,试图隐藏程序的逻辑。参赛者需要使用各种工具、结合各种资料来还原程序逻辑。在比赛与练习中,你会接触到各种软件开发技术(如python、rust、golang、android……)、各种编码和密码学算法(如Base64、TEA、RC4……),了解其底层的实现原理。我们学校也有相应的社团/CTF战队——信息网络安全协会/六星战队,大家可以了解一下哦~

在逆向工程中,分析方法可以大致归类为两类:动态分析与静态分析。简单来说,动态分析就是运行程序、观察其行为;静态分析就是借助可执行文件中的信息与数据(如机器码)还原程序逻辑。在本节中,我们会分别介绍动态分析、静态分析的方法与工具,然后再介绍一些别的小工具。

动态分析

最简单的动态分析就是直接运行程序。你可以试试引爆炸弹先。

正经的动态分析就是使用 gdb(全称为 GNU Debugger)等调试工具进行动态调试。动态调试的坏处是可能会一不小心让程序“跑飞了”,错过你想要观察的代码;而好处就是你可以直观地看到程序运行时,各种数据的实际值。

至于如何使用,请参考 gdb-tutor。

你可以去网上找一个 gdb cheetsheet(小抄),方便你查找想用的指令。我们也给出一个挺好的英文教程:Tudor‘s gdb crash course

静态分析

反汇编

我们回顾一下C程序的编译过程:源代码 -> 汇编代码 -> 机器码,中间两步分别称为编译与汇编。

在源代码到汇编代码的过程中,编译器作了许多的优化、也删去了很多源代码中的信息,比如局部变量名等等……而汇编代码和机器码则是几乎等价的,汇编语言是机器码的助记符。

因此,有工具能帮我们将可执行文件中的机器码转化为汇编代码也就不足为奇了,这种工具被称为反汇编器。至于汇编代码到源代码,这种工具也存在,但由于本次实验旨在帮助大家熟悉汇编代码,因此在本次实验中我们不会介绍它们。我们这里介绍一个非常经典且常用的反汇编器——objdump。

我们在命令行中输入 objdump -d ./bomb > bomb.S 就可以获得反汇编文件 bomb.S。

objdump --help 会打印出 objdump 的所有用法,并且会给出精简的解释。

助教の温馨提示

你可以尝试在objdump后加上 -D 和/或 -x 和/或 -C,就像上面出现的-d一样。你可以通过搜索或读文档的方式了解这会导致什么后果;TA相信这几个参数会对你的实验有很大帮助!

X86 / AMD64 汇编语言的格式

在CSAPP课本上,有一个拓展框介绍了两种汇编语言的格式——AT&T 以及 Intel。

他们最显著的区别有两个(当然还有别的区别,见课本):

两者的源操作数和目的操作数顺序相反
AT&T 中寄存器需要加上 % 前缀,而 Intel 语法则不用。
本课程上课教学时使用的语法是 AT&T,这也是 objdump 默认使用的语法。但我们同样推荐你试试 Intel 语法,因为这是安全研究人员更常用的一种语法。想让 objdump 输出语法变为 Intel,只需要给 objdump 添加参数 -M intel。

阅读汇编

在拿到汇编代码文件后,我们就需要通过分析它来理解程序的逻辑。如果是一个简短的函数,或许汇编也就几十行;但你很有可能会遇到百来行的函数。如何应对这种复杂的代码?

我们介绍一种理解汇编代码的方法,叫做 CFG(Control Flow Graph,控制流图)。显然,汇编代码中没有 if-else/for loop/while loop 这样的结构,而只有各种jump、conditional jump。很容易想到,我们可以把各种jump指令把它们的目标用一个箭头连起来,来让代码变得稍微好看懂一点。不过,我们还可以做得更加好一些:

这是一个伪代码的例子,我们同样可以将这个方法运用到汇编语言中。构造CFG的基础方法很简单:我们只需要把不含跳转代码当作一个Block,然后把Block们连接起来即可。你可以在草稿纸上使用这个方法,将函数的跳转逻辑理清楚。不要小看了CFG的作用,亲自试试吧,或许你会从此觉得读汇编语言也不过如此。

另外一种推荐的技巧是……将汇编代码打印出来。没错,虽然我知道手写代码一定是痛苦的体验,但在纸上阅读汇编语言代码确实是一种推荐的方法。这是因为,汇编语言的阅读可能需要大量的标注,在纸上标记会方便很多。不过也请注意,Bomb+的汇编代码很长,包含了许多不会执行或与实验无关的函数。你可以只在遇到应付不了的关卡时才选择把看不懂的那些函数打印出来。

其他实验帮助

重定向与管道

上过C语言和C++的大家应该知道,命令行程序有三个默认打开的“流”,分别是stdin,stdout以及stderr。在我们运行命令行程序时,标准输入就是我们敲进去的东西,而程序打印东西到stdout或者stderr,其实就是打印到命令行上。

在学习C或C++的文件操作的时候,会发现一个很巧的事情——文件读写用到的API,和标准输入输出用的那些API其实都差不多,这是因为文件和标准输入输出本来就是一样的。在Linux系统中,一切皆文件。不仅传统意义上的文本文件、多媒体文件等普通文件是文件,套接字(网络接口)、键盘鼠标设备等等都是文件,可以用统一的一套文件API进行处理。

这种设计不仅带来了极大的统一性,也带来了极大的便捷性。本节介绍的iostream重定向和pipes管道就与这种设计有关。

既然stdin和stdout也是文件流,那么我们当然可以把他们重定向到一个普通文件!我们让一个文件被定向到一个程序的标准输入,或者让一个程序的标准输出定向到一个文件当中。前者我们使用 < file,后者我们使用 > file,如下所示:

$ echo hello > hello.txt
$ cat hello.txt
hello

$ cat < hello.txt
hello

$ cat < hello.txt > hello2.txt
$ cat hello2.txt
hello
如果你找到了所有的正确口令,那么把它们写到一个文本文件 password.txt 中,那么使用 ./bomb < password.txt 就可以直接通过所有的关卡。

除此以外,还有更加便利的 管道 操作,可以帮助我们将两个程序的输入和输出相连接,也就是构造一条虚拟的管道。这种神奇的操作是通过 | 来完成的:

$ cat 1.txt
GODEL
ESCHER
BACH
$ cat 1.txt | tail -n1
BACH
$ cat 1.txt | grep CH
ESCHER
BACH
利用这两种操作,我们可以方便地处理BombLab的输入。我们知道 cat 是打开文件,也知道标准输入同样也是一个文件,因此我们可以用 cat 打开标准输入文件,这时候 cat 就相当于一个 echo,可以复读我们说的话:

$ cat -
Hello, world!
Hello, world!
除此以外,cat还可以打开多个文件,如下所示:

$ cat 1.txt
hello
$ cat 2.txt
world
$ cat 1.txt 2.txt
hello
world
如果你在做BombLab时,已经找到了前面某些阶段的口令,不想在后续步骤中再一遍遍重新输入它们的话,就可以将已知的口令写入一个文本文件中,然后用 cat 打开那个文本文件以及标准输入,然后利用管道机制将这两个文件的内容导向bomb+的输入:

$ cat password.txt - | ./bomb
助教の温馨提示

使用这种操作时注意,由于Bomb+每一阶段都会重新读取一行,所以文件结尾多出的换行符会导致Bomb+下一阶段读到一个寂寞,从而导致炸弹爆炸。因此,在存放口令的文本文件中,注意不要多加一个空白的结尾行。

文件拓展名

熟悉Windows的各位同学一定对诸如 .exe .docx .xls .png .jpeg 等拓展名见惯不惯了,Windows系统会通过文件名中的这些后缀来判断如何打开这个程序。

不过在使用 Linux 时,通常不需要你为文件加上拓展名,这是因为 Linux 系统往往通过文件头中的魔数来区分文件类型。(这个概念我们在DataLab讲义中简单介绍过,如果你不知道的话可以自己去百度/谷歌看看)因此,我们在这里为文本文件标上 .txt 后缀类似于注释一样,是为了让大家看得更清楚一些。

“超纲”的汇编指令

大家在实验过程中,或许会遇到一些课上没有讲过的汇编指令,我们在这里介绍一下其中一个。

endbr64:一种用于防御ROP(Return Oriented Programming)攻击的机制 —— CET(Control-flow Enforcement)的一部分,但大多的CPU现在还没有实装,因此它们执行到这条指令时会直接略过。本次实验并不涉及相关的内容,你也可以直接略过。如果对二进制漏洞攻防感兴趣,大家也可以关注信息网络安全协会的相关活动。

如果遇到其他没见过的汇编指令,我们建议自己查询互联网。如果你有钻研的精神,欢迎你试着查询Intel的官方手册 英特尔® 64 位和 IA-32 架构开发人员手册,真正理解这个指令的细节。在查询这种奇厚无比的手册时,请一定记得利用好目录以及搜索功能。

五、参考资料 & 推荐资料
http://csapp.cs.cmu.edu/3e/labs.html 原版Lab
本实验参考22年的实验开发,感谢lrx学长支持

从汇编角度学习C/C++ - 看雪

bomb-lab 实验报告
范意阳 22307110117
bomb-lab 实验报告

第一题:
key:Computer science is not a boring subject

思路:跳转到 phase_1 后,总览一遍代码
首先循环调用 read_line 读取输入值,存储在 0x7fffffffe510
0x55555555558c<phase_1+52> call string_not_equal:
此指令调用 string_not_equal 函数,从函数名称推断它会比较 rdi 和 rsi 寄存器中的 字符串(目标储存在 0x4061ae),查看它们是否不相等,这个函数的结果存储在 eax 寄存 器中。只需要查看 0x4061ae 地址储存字符串即可。

功能:phase_1 函数将输入字符串与目标字符串进行比较

第二题:
key:1 -3 13 -51 205 -819(首项不为 0,后一个数为前一个数的负四倍加一) 思路:依然首先总览一遍代码
0x5555555555be<phase_2+30> call read_six_numbers <read_six_numbers>
看来第二题的 key 是六个整数,并存储在 rsi 寄存器中指向的地址中。

在<read_six_numbers> 中:
0x0000555555556225 <+109>: test eax,eax
0x0000555555556227 <+111>: jne 0x55555555622e<read_six_numbers+118>

bomb-lab 实验报告

发现没有对第一个数进行比较,说明第一个数没有限制,下面以输入 1 为例
0x5555555555f7 <phase_2+87> imul edx, eax
乘 4
0x5555555555e4 <phase_2+68> cdqe
将 EAX (储存输入值)的值符号扩展到 RAX。
0x555555555600 <phase_2+96> ad eax, edx
info registerseax eax 0x1 1
加一
最后,每一位与上一位进行比较
功能:读取六个整数,检验第一个数是否为 0 ,然后检验后一个是否为前一个的-4 倍+1。
第三题:
key:610 987 w(之一)

思路:
lea rsi, [rip + 0x1bf0]:将 RIP 寄存器的当前值加上 0x1bf0 ,然后加载到寄存器 rsi 中。这可 能是为了初始化 rsi 以指向某个数据或字符串。
通过在<__isoc99_vsscanf>打断点,读取寄存器 rsi 的值,得到输入为%d %d %c
0x555555555676 <phase_3+72> cmp eax, 0x262
0x55555555568c<phase_3+94> cmp eax, 0xe9

0x0000555555555676 <+72>:cmp eax,0x262
0x000055555555567b<+77>: je 0x55555555577c<phase_3+334>
eax 储存输入的第一个整数,如果为 610 ,则跳转到 0x55555555577c
0x000055555555577c<+334>:mov BYTE PTR [rbp-0x1],
0x77 0x0000555555555780 <+338>:moveax,DWORD PTR [rbp-0x10]
0x0000555555555783 <+341>:cmp eax,0x3db
0x0000555555555788 <+346>: je 0x5555555557ad<phase_3+383>
0x000055555555578a<+348>: call 0x55555555605a<explode_bomb>
DWORD PTR [rbp-0x10] 储存的是第二个输入的整数值;如果为 0x3db 即 987 ,跳转到
0x00005555555557ad<+383>:nop
0x00005555555557ae<+384>:movzxeax,BYTE PTR [rbp-0x11]
0x00005555555557b2 <+388>: cmp BYTE PTR [rbp-0x1],al
0x00005555555557b5 <+391>: je 0x5555555557bc<phase_3+398>
判断第三个输入是否与寄存器中 al 相等,相等则判断为成功
其余还有 233 377 o
89 144 l
1 1 o
2 3 v
5 8 e
13 21 r
34 55 f

第四题:
Key:51539607553-51539607564 中一个数

bomb-lab 实验报告
范意阳 22307110117
思路:

读取了一个 64 位的数放在 0x7fffffffde70
0x40182f<phase_4+59> mov rax, qword ptr [rbp - 0x10]
► 0x401833 <phase_4+63> sar rax, 0x20
将读取的数据右移了 32 位,储存在 rbp - 4,

输入数据的全部,储存在 rbp - 8
0x40183e<phase_4+74> mov dword ptr [rbp - 8], eax

0x401841 <phase_4+77> cmp
0x401848 <phase_4+84> cmp
高位需要比 0 大比 15 小

dword ptr [rbp - 4], 0
dword ptr [rbp - 4], 0xe

0x401854 <phase_4+96> 0x401860 <phase_4+108>
低位需要比 0 大比 15 小

cmp dword ptr [rbp - 8], 0
cmp dword ptr [rbp - 8], 0xe

0x40187a<phase_4+134> call hope(int) <hope(int)>
Hope 函数递归把 rdi 存储的高位的数值传输了进去

0x4017b8 <hope(int)+12> 0x4017b<hope(int)+15> 0x4017bf<hope(int)+19>
如果不是 0 大跳转到 28

mov dword ptr [rbp - 0x14], edi
cmp dword ptr [rbp - 0x14], 0
jne hope(int)+28 <hope(int)+28>

0x4017c8 <hope(int)+28> 0x4017cb<hope(int)+31> 0x4017cd<hope(int)+33> 0x4017cf<hope(int)+35>

mov eax, dword ptr [rbp - 0x14]
sar eax, 1
mov edi, eax
call hope(int)

<hope(int)>

右移一位然后重新进入循环,一直到变成 0 ,给 eax 赋值为 1

0x4017e1 <hope(int)+53> mov eax, dword ptr [rbp - 4]
0x4017e4 <hope(int)+56> imul eax, eax
0x4017e7 <hope(int)+59> shl eax, 2
0x4017ea<hope(int)+62> jmp hope(int)+70 <hope(int)+70>
开始把 eax 自己与自己相乘,不断左移两位,然后返回<hope(int)+35>的下一位

0x40187f<phase_4+139> cmp eax, 0x1000000
0x401884 <phase_4+144> setne al
如果结果为 0x1000000 即可通过

bomb-lab 实验报告
范意阳 22307110117
因此我需要将这个函数调用四次,即我的输入(高位)需要为二进制 1110 或者 1111 ,来保 证调用了 hope 四次,因此高位只能为 0xc

第五题:
读取了一个字符串以及一个整数,存储到了 0x9de6006425207325
RSI 0x4032e5 ◂ — 0x9de6006425207325 n/* ‘%s %d’ */

0x40193b<phase_5+168> lea rsi, [rip + 0x19c3]
0x401942 <phase_5+175> mov rdi, rax
0x401945 <phase_5+178> call strcmp@plt
调用 strcmp 函数。它用于比较两个字符串。
Strcmp 函数调用了两个地址
0x7fffffffe4d0 用于储存输入的字符串
0x4032eb ◂ — 0x9de6809de6809de6 储存用于比较的字符串
Strump 在函数中调用了三次
在 gdb 中查看这个地址,另外两次地址为
0x4032f8 ◂ — 0x80e98080e98080e9
0x403305 ◂ — 0x86e5b286e5b286e5
在 gdb 中调取他们的信息,得到三个字符串为

0x4018fa<phase_5+103> call worldline1::worldline1() worldline1::worldline1()
当看到这个函数我脑子“噔噔蹬 ”了一下,有类存在,怕不是要找类里面的
冲冲冲~情况:

0x401f5fworldline2::worldline2()+23 call worldline::worldline()
调用了 worldline ::worldline() 函数,是初始化 worldline2 对象,将 worldline 对象 与当前 worldline2 对象关联。

0x401e94worldline::worldline()+12 lea rdx, [rip + 0x3efd] <vtable for worldline+16>
提醒这里是一个存储类的虚函数
0x401963 <phase_5+208> mov qword ptr [rbp - 0x18], rbx
把这个函数的指针放进了 rbp - 0x18

0x40197c<phase_5+233> mov edx, dword ptr [rbp - 0x34]

bomb-lab 实验报告
范意阳 22307110117
把输入值存放到了 RDX

0x402039 worldline3::dmail(int)+15
cmp dword ptr [rbp - 0xc], 0x7e7
我们处理后需要是 0x7e7 才能通过

0x401f6 worldline3::worldline3()+46 mov qword ptr [rax+ 8], 0x1124fd

0x401eb6 worldline::is_phase5_passable()+16 mov rax, qword ptr [rax+ 8]
0x401ebaworldline::is_phase5_passable()+20 cmp rax, 0xf423f
这里需要 rax 值大于 0xf423f,而我们的值为 0x1124fd 成功

而在我尝试其他两种情况的时候,发现事情出现了不一样的情况
0x401ef6 worldline1::worldline1()+46 mov qword ptr [rax+ 8], 0x8b690
rax + 8 被赋值成了其他值,经过尝试只有冲冲冲~才能成功
但是我弄了好久也没有弄明白,都是worldline1::worldline1()+46,但是传输的数据不一样 不太懂,但是还是过了。

第六题:
Key:6 1 6 1 6 1
思路:
读取了六个整数,存放在了 0x7fffffffe510

然后进入了一个循环,
0x401cb1 <phase_6+59>

mov eax, dword ptr [rbp - 4]

► 0x401cb4 <phase_6+62> cdqe
0x401cb6 <phase_6+64> lea rdx, [rax*4]
0x401cbe<phase_6+72> mov rax, qword ptr [rbp - 0x10]
0x401c2 <phase_6+76> ad rax, rdx
0x401c5 <phase_6+79> mov eax, dword ptr [rax]
0x401c7 <phase_6+81> cmp eax, 6

从 rax = 1 一直到 rax = 5 把输入传递给 phase 6 nums 入二) 以这种形式

之后进入 build_target

0x401ab<build_target+21>
把输入写入 rbp - 0x98

以及之后+16 +20 等等一系列地址 0x(输入一)0000000(输

mov qword ptr [rbp - 0x98], rdi <phase 6 nums>

进入 build_queue
0x401a22 <build_queue+8> lea rax, [rip + 0x49d7]
initialNodes 里存储着六个数字,按顺序为 0x14 0x3c

<initialNodes+64>
0x28 0x32 0xa 0x1e

bomb-lab 实验报告
范意阳 22307110117

get_val 里
0x401a03 <get_val+24> mov rax, qword ptr [rbp - 0x18]

0x401a07 <get_val+28> mov rax, qword ptr [rax]
0x401a0a<get_val+31> mov rdx, qword ptr [rax+ 8]
0x401a0e<get_val+35> mov rax, qword ptr [rbp - 0x18]
0x401a12 <get_val+39> mov qword ptr [rax], rdx
把下一个数字读取进 0x7fffffffe450 — ▸ 0x4063c0 (initialNodes) ◂ — 0x3c 上一个数字放入 0x7fffffffe400 ◂ — 0x14

第二次调用
0x7fe400 ◂ — 0x3c00000014
0x7fe450 —▸ 0x406410 (initialNodes+80) ◂ — 0x28
第三次调用
0x7fe400 ◂ — 0x3c00000014
0x7fe450 —▸ 0x4063e0 (initialNodes+32) ◂ — 0x32

一直到五个数字全部读取
0x7fe400 ◂ — 0x3c00000014
0x7fe408 ◂ — 0x3200000028
0x7fe410 ◂ — 0x7f0000000a

put_val :
0x4019f3 <get_val+8> 0x4019f7 <get_val+12> 0x4019fb<get_val+16> 0x4019fe<get_val+19> 0x401a00 <get_val+21> 0x401a03 <get_val+24> 0x401a07 <get_val+28> 0x401a0a<get_val+31>

mov qword ptr [rbp - 0x18], rdi
mov rax, qword ptr [rbp - 0x18]
mov rax, qword ptr [rax]
mov eax, dword ptr [rax]
mov dword ptr [rbp - 4], eax
mov rax, qword ptr [rbp - 0x18]
mov rax, qword ptr [rax]
mov rdx, qword ptr [rax+ 8]、

寄存器状态:
0x7fe48 —▸ 0x406400 (initialNodes+64) ◂ — 0x14
0x406400 (initialNodes+64) ◂ — 0x14
0x406400 (initialNodes+64) ◂ — 0xa
0x7fe48 —▸ 0x406400 (initialNodes+64) ◂ — 0xa
RDX 0x4063c0 (initialNodes) ◂ — 0x3c

0x7fe48 —▸ 0x4063c0 (initialNodes) ◂ — 0x3c
0x4063c0 (initialNodes) ◂ — 0x3c
0x4063c0 (initialNodes) ◂ — 0x32
0x7fe48 —▸ 0x4063c0 (initialNodes) ◂ — 0x32

bomb-lab 实验报告
范意阳 22307110117
0x406410 (initialNodes+80) ◂ — 0x28

put_val 输入两个数据,第一个是一个指针指向现在这个数据的指针,第二个是一个数;把 第二个数放进现在这个位置,然后原来的指针指向这个位置。

即把调用的两个值位置进行交换,接下来要找什么决定了我的 put_val 的输入
► 0x401c31 <build_target+411> lea rax, [rbp - 0x78]

0x401c35 <build_target+415> 0x401c37 <build_target+417> 0x401c3a<build_target+420>
存储在 rbp - 0x78
0x401c24 <build_target+398> 0x401c28 <build_target+402> 0x401c2b<build_target+405> ► 0x401c2e<build_target+408> 0x401c31 <build_target+411> 0x401c35 <build_target+415> 0x401c37 <build_target+417> 0x401c3a<build_target+420>

mov esi, edx
mov rdi, rax
call put_val <put_val>第一个输入

mov rax, qword ptr [rbp - 0x60]
mov edx, dword ptr [rbp - 0x34]
movsxdrdx, edx
mov edx, dword ptr [rax+ rdx*4]
lea rax, [rbp - 0x78]
mov esi, edx
mov rdi, rax
call put_val

第二个存储在 rax + rdx*4,其中 rdx 为计数器
RAX 0x7fffffffe400 ◂ — 0x2800000032

我猜这是一个循环队列,get_val 和 put_val 前者把输入写进队列后者替换队列元素
0x7fffffffe400
0x7fffffffe408
0x7fffffffe410 储存这六个元素

0x401a66 <check_answer+59> shl rax, 2
0x401a6a<check_answer+63> lea rcx, [rax - 4]
► 0x401a6e<check_answer+67> mov rax, qword ptr [rbp - 0x18]
0x401a72 <check_answer+71> ad rax, rcx
0x401a75 <check_answer+74> mov eax, dword ptr [rax]
0x401a77 <check_answer+76> cmp edx, eax
通过查看寄存器的值很容易发现需要我们的队列是从小到大排列的才能通过

(看了将近十个小时 实在是找不到我的输入是怎么控制循环的,破防了;放弃正常写了)

bomb-lab 实验报告
范意阳 22307110117
运用 subprocess 库来控制终端的输入,在终端进入 wsl 后 python run.py 得到答案。

Secret_phase:
一开始助教提醒在第三题,我还以为是在第三题后面的某一行代码,或者里面的代码;一直 si 看了很多没用的外部函数,后来问了一下助教,助教让我注意第三题答案,结果拼出来了 overflow ,“挠 ”的一下我就懂了。在输入后面加上
11111111111111111111111111111111111111111111111111111111111111111111111111over flow 后即可进入。

输入值存放在 0x7fffffffe510
存储到 rbp - 0x18
0x401dc1 <secret_phase+12> mov qword ptr [rbp - 0x18], rdi

把一个奇奇怪怪的值放进去了,感觉一定很有用
0x401d4 <secret_phase+31> mov dword ptr [rbp - 4], 0xdeadc0de
0x401db<secret_phase+38> lea rdx, [rbp - 8]
*RDX 0x7fe4f8 ◂ — 0xdeadc0de0af5e100

0x401e06 <secret_phase+81>
► 0x401e09 <secret_phase+84>
0x401e0c<secret_phase+87>
0x401e0f<secret_phase+90>
0x401e12 <secret_phase+93>
0x401e17 <secret_phase+98>

mov eax, dword ptr [rbp - 8](输入的十六进制)
xor eax, dword ptr [rbp - 4]
mov dword ptr [rbp - 8], eax
mov eax, dword ptr [rbp - 8]
cmp eax, 0xbadf00d
je secret_phase+105

重点就在这个 xor 上,这个数异或上 0xdeadc0de 等于 0xbaadf00d

得到答案(隐藏意外的简单)

感受:
属于一个看山不是山-看山是山-看山又不是山了 这么一个过程,从最开始第一题,进度超 级缓慢;然后二三四好像掌握了一些技巧,虽然过程曲折,但是结果是好的。到第五题,虽 然有些地方不理解,但是整体是能懂在干什么;然后到了第六题,写的时间比我前四个题目 加一起都多,到最后还是 get_val 和 put_val 能懂,但是就是不懂循环是怎么操纵的;做第六 题的时候,晚上做梦都在地址倒来倒去。最后 secret_phase ,在第三题看了好多好多遍,没
想到在这么一个位置,有挺有意思。
总之感谢助教,学到了很多东西。

  • 30
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
对于题目"web-ics-05",根据提供的引用内容,我们可以得到以下信息: - 这道题可能是在入侵后利用管理平台来完成一些信息的收集,读取文件并利用是非常重要的。\[1\] - 在源代码中有一段注释,提到要给HTTP头部添加X-forwarded-For=127.0.0.1。\[2\] - preg_replace函数可以执行正则表达式的搜索和替换。\[3\] 根据这些信息,我们可以推测"web-ics-05"可能是一道关于入侵和利用管理平台的题目,要求读取文件并进行一些操作,同时还需要使用preg_replace函数进行正则表达式的搜索和替换。具体的题目要求和操作细节可能需要进一步的信息才能确定。 #### 引用[.reference_title] - *1* *3* [xctf-web-ics05](https://blog.csdn.net/zhejichensha_l7l/article/details/113530046)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [攻防世界-ics-05-(详细操作)做题笔记](https://blog.csdn.net/qq_43715020/article/details/125291336)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值