这个lab主要考察gdb的使用和对汇编代码的理解。后者在平时的作业中涉及得较多,这里不再赘述,主要介绍一下gdb
其实偶对这个也不是很熟,有错误请指正 @@
简单的说,gdb是一款强大的调试工具,尽管它只有文本界面(需要图形界面可以使用ddd,不过区别不大),但是功能却比eclipse等调试环境强很多。
接下来看看怎样让它为lab2拆炸弹服务,在命令行下运行gdb bomb就能开始调试这个炸弹程序,提高警惕,恩
首先最重要的,就是如何阻止炸弹的引爆,gdb自然提供了一般调试工具都包括的断点功能——break命令
在gdb中输入help break能够看到相关的信息
(gdb) help break
Set breakpoint at specified line or function.
Argument may be line number, function name, or "*" and an address.
If line number is specified, break at start of code for that line.
If function is specified, break at start of code for that function.
If an address is specified, break at that exact address.
With no arg, uses current execution address of selected stack frame.
This is useful for breaking on return to a stack frame.
Multiple breakpoints at one place are permitted, and useful if conditional.
Do "help breakpoints" for info on other commands dealing with breakpoints.
可以看到break允许我们使用行号、函数名或地址设置断点
按ctrl+z暂时挂起当前的gdb进程,运行objdump –d bomb | more 查看反编译后的炸弹文件,可以看到里面有这么一行(开始的那个地址每个人都不同):
08049719 <explode_bomb>:
这个就是万恶的引爆炸弹的函数了,运行fg返回gdb环境,在这个函数设置断点:
break explode_bomb (可以使用tab键自动补齐)
显示
Breakpoint 1 at 0x8049707
接下来你可以喘口气,一般情况下炸弹是不会引爆的了
下面我们来拆第一个炸弹,首先同样是设置断点,bomb.c中给出了各个关卡的函数名,第一关就是phase_1,使用break phase_1在第一关设置断点
接下来就开始运行吧,输入run
Welcome to my fiendish little bomb. You hava 6 phases with
which to blow yourself up. Hava a nice day!
我们已经设置了炸弹断点,这些恐吓可以直接无视。
输入ABC继续(输入这个是为了方便在后面的测试中找到自己的输入串地址)
提示Breakpoint 2, 0x08048c2e in phase_1 (),说明现在程序已经停在第一个关了
接下来就是分析汇编代码,使用disassemble phase_1显示这个函数的汇编代码
注意其中关键的几行:
8048c2e:68 b4 99 04 08 push $0x80499b4
8048c33:ff 75 08 pushl 0x8(%ebp)
8048c36:e8 b1 03 00 00 call 8048fec <strings_not_equal>
这个lab很厚道的一点就是函数名很明确地说明了函数的功能 ^_^
估计这三行代码的意思就是比较两个字符串相等,不相等的话应该就会让炸弹爆炸了
因为字符串很大,所以传递给这个比较函数的肯定是他们的地址,分别为0x80499b4和0x8(%ebp)
我们先来看后者,使用p/x *(int*)($ebp + 8)查看字符串所在的地址
$1 = 0x804a720,继续使用p/x *0x804a720查看内存中这个地址的内容
$2 = 0x434241,连续的三个数,是不是想起什么了?把这三个数分别转换为十进制,就是67 66 65,分别为CBA的ASCII码,看来这里保存了我们输入的串。
接下来0x80499b4里肯定保存着过关的密码
p/x *0x80499b4,显示$3 = 0x62726556,c中的字符串是以0结尾的,看来这个字符串还不止这个长度,继续使用
p/x *0x80499b4@10查看这个地址及其后面36个字节的内容,终于在第二行中出现了终结符”0x0”(不一定是四个字节)
$4 = {0x62726556, 0x7469736f, 0x656c2079, 0x20736461, 0x75206f74, 0x656c636e, 0x202c7261, 0x72616e69,
0x75636974, 0x6574616c, 0x69687420, 0x2e73676e, 0x0, 0x21776f57, 0x756f5920, 0x20657627, 0x75666564,
0x20646573, 0x20656874, 0x72636573}
把开头到0x0的所有信息字节下来,通过手算或者自己写程序得出最后的密码串(注意little endian中字符的排列方式!)
输入run重新运行,输入刚才得出的密码串,如果前面的计算正确的话,就会提示
Phase 1 defused. How about the next one?
关于这个lab的一些其他心得:
1. VMware中开发很不舒服,屏幕小、字体丑@@、需要Ctrl+Alt切换回windows,不怎么方便,推荐在windows下使用pietty登录虚拟机中的linux系统(RedHat 9默认安装了sshd),个人觉得这样比较方便。
2. ASCII查询可以在linux终端中运行man ascii。
3. 退出gdb后,再次进入时一定要注意使用break给explode_bomb上断点,不可大意 ~.~
4. 后面的几关涉及递归等内容,也有和前面几次作业很相似的东东。
5. gdb中还有一个很好用的jump指令,可以在运行时任意跳转。
6. 看汇编代码时,使用objdump -d bomb > bomb.asm把汇编代码保存到bomb.asm中,然后使用sftp工具把这个文件下载到windows或者直接在vim中查看,这样比在gdb中看方便一些。
7. 个人认为lab2和期中考试不冲突,这个lab2可以帮你理清很多汇编语言的概念
其他补充:
sfox:
可以通过GDB中的
x /s addr输出以\0结尾的字符串
ICSLab:
为了防止每次拆的时候都不停的输入之前的stage的key,可以把key存入文本文件,一行一个key,不要有多余字符
然后GDB run 的时候用
gdb bomb 回车
(gdb)
b .... ....
(gdb)
r password.txt
这样bomb就会自动从password.txt中读入之前的密码
直到到达最后一个空行处,如Lab2的说明文档中所述。