CSAPP 3e: Bomb lab (phase_1)

少年乘勇气,百战过乌孙。这篇文章主要讲述CSAPP 3e: Bomb lab (phase_1)相关的知识,希望能为你提供帮助。
这一个lab拖了好久才开始慢慢完成,花的时间比较多,我也是没想到会需要这么多时间来折腾。考虑到如果把所有关卡的内容都一次发出来,太长了。所以分开操作吧。
然后,有一点是,在开始解题前的确该好好认识一下GDB,因为要使用这个工具。虽然我也感觉有些东西是可以等需要的时候再查的,但是后来找到了一篇介绍gdb命令的,写的比较详细,就下载了打印出来,占用了几节课的时间好好看了一下,就感觉特别有用,比之前更加熟悉了GDB。大概是在网页上看的时候比较急躁,所以吸收不好吧23333。还有,在解题过程中参考了不少网上前辈的资料,向每位分享知识的前辈致敬。
我的操作方法是把程序反汇编到一个文本中,反汇编了两个版本,一个是objdump -d   bomb > bomb_disas.s (反汇编bomb中需要执行指令的那些section),另一个是 objdump -D bomb > bomb_disas2.s (反汇编bomb中所有的section). 这个放在Windows系统中,便于查看,分析,主要是感觉notepad++看着舒服啦。然后,调试是在虚拟机中进行的。
关于GDB命令的东西,如果你还没有接触过,那还是先了解一下的好,或者可以在阅读途中碰上了再百度。
 
在Linux中,gdb bomb用GDB打开bomb,输入list可以查看代码。不过bomb lab 文件夹中也有源码。通过这个可以看到代码中每个关卡的通用格式,比如:

input = read_line(); /* Get input*/ phase_1(input); /* Run the phase*/ phase_defused(); /* Drat!They figured it out! * Let me know how they did it. */

 
每一关的函数是phase_x,这里x是关卡数。看第一关的汇编函数phase_1,发现其中调用了两个函数。
0000000000400ee0 < phase_1> : 400ee0:48 83 ec 08sub$0x8,%rsp 400ee4:be 00 24 40 00mov$0x402400,%esi 400ee9:e8 4a 04 00 00callq401338 < strings_not_equal> 400eee:85 c0test%eax,%eax
400ef0:74 05je400ef7 < phase_1+0x17>
400ef2:e8 43 05 00 00callq40143a < explode_bomb>
400ef7:48 83 c4 08add$0x8,%rsp 400efb:c3retq

一个是 strings_not_eaqual ,一个是 explode_bomb .这里先说这个explode_bomb是解密失败后引发爆炸(bomb)的函数。具体可以自行去调用查看,在bomb_disas.s中查找该函数即可查看其执行过程,不予细说了。然后,这里另一个函数是 strings_not_eaqual .从字面上也可以理解,这个函数是检查两个字符串是否一样。应用就是你输入的字符串如果跟他指向的另一串字符串不一样,就bomb了,请看查看这个函数的代码。
0000000000401338 < strings_not_equal> : 401338:41 54push%r12 40133a:55push%rbp 40133b:53push%rbx 40133c:48 89 fbmov%rdi,%rbx; %rdi是储存输入的字符串首地址 40133f:48 89 f5mov%rsi,%rbp; 由phase(1)知道;; %rsi是储存拆弹密码字符串的首地址. 401342:e8 d4 ff ff ffcallq40131b < string_length> ; 计算字符串长度, 401347:41 89 c4mov%eax,%r12d 40134a:48 89 efmov%rbp,%rdi 40134d:e8 c9 ff ff ffcallq40131b < string_length> 401352:ba 01 00 00 00mov$0x1,%edx 401357:41 39 c4cmp%eax,%r12d; 字符串长度不一样的话,就bomb. 40135a:75 3fjne40139b < strings_not_equal+0x63> 40135c:0f b6 03movzbl (%rbx),%eax; 零扩展传递第一个字符到%eax. 40135f:84 c0test%al,%al; 第一个为0就ret,以0作为返回值。 401361:74 25je401388 < strings_not_equal+0x50> ; 但是要考虑字符串长度,所以0不是正确答案 401363:3a 45 00cmp0x0(%rbp),%al; 对比第一个字符串,相同则进入循环,否则bomb 401366:74 0aje401372 < strings_not_equal+0x3a> ; 0x401372进入循环。 401368:eb 25jmp40138f < strings_not_equal+0x57> 40136a:3a 45 00cmp0x0(%rbp),%al; 循环的起始地址 40136d:0f 1f 00nopl(%rax) 401370:75 24jne401396 < strings_not_equal+0x5e> ; 第N个字符不相同则bomb. 401372:48 83 c3 01add$0x1,%rbx; 所输入字符串向后移一位,为了向后检查 401376:48 83 c5 01add$0x1,%rbp; 密码字符串后移,为了向后检查 40137a:0f b6 03movzbl (%rbx),%eax; 零扩展传递第N个字符到%eax 40137d:84 c0test%al,%al 40137f:75 e9jne40136a < strings_not_equal+0x32> ; 第N个字符不是%0,即字符串未结束,则继续循环 401381:ba 00 00 00 00mov$0x0,%edx 401386:eb 13jmp40139b < strings_not_equal+0x63> 401388:ba 00 00 00 00mov$0x0,%edx 40138d:eb 0cjmp40139b < strings_not_equal+0x63> 40138f:ba 01 00 00 00mov$0x1,%edx 401394:eb 05jmp40139b < strings_not_equal+0x63> 401396:ba 01 00 00 00mov$0x1,%edx 40139b:89 d0mov%edx,%eax 40139d:5bpop%rbx 40139e:5dpop%rbp 40139f:41 5cpop%r12 4013a1:c3retq

这里重点就是%rdi存储输入所输入的字符串的首地址,%rsi存储拆弹密码字符串的首地址。
再回过来查看phase_1, 第二行将0x402400赋值给了寄存器%esi。
0000000000400ee0 < phase_1> : 400ee0:48 83 ec 08sub$0x8,%rsp 400ee4:be 00 24 40 00mov$0x402400,%esi 400ee9:e8 4a 04 00 00callq401338 < strings_not_equal> 400eee:85 c0test%eax,%eax; %eax返回值为1就bomb 400ef0:74 05je400ef7 < phase_1+0x17> ; 通过查看strings_not_equal函数知道 400ef2:e8 43 05 00 00callq40143a < explode_bomb> ; 0x402400位置的字符串即为第一关答案. 400ef7:48 83 c4 08add$0x8,%rsp; 在gdb中用 x/s 0x402400查看内存即可看到答案。 400efb:c3retq

在gdb中用 x/s 0x402400查看内存中的字符串就得到了答案。
CSAPP 3e: Bomb lab (phase_1)

文章图片

输入该字符串即可通过第一关。
CSAPP 3e: Bomb lab (phase_1)

文章图片

至此,第一关结束。加油挑战!
 
【CSAPP 3e: Bomb lab (phase_1)】对我来说,感觉这bomb lab拖了好久才完成的原因,主要还是在于对GDB工具的不了解,所以弄得是无从下手。所以如果有后来者看到这篇文章,希望你先好好熟悉一下GDB,这样才可以事半功倍。





    推荐阅读