前段时间刚刚做完bomb lab实验,记录一下我做CSAPP 二进制炸弹实验的详细过程。有什么问题可以在评论中指出,一起进步。
首先需要下载相关的资料。
代码:http://csapp.cs.cmu.edu/3e/bomb.tar
GDB命令文档:http://csapp.cs.cmu.edu/3e/docs/gdbnotes-x86-64.pdf
说明:http://csapp.cs.cmu.edu/3e/bomblab.pdf
README:http://csapp.cs.cmu.edu/3e/REA
实验环境是基于linux x86-64,目的是培养看懂反汇编代码的能力,以及利用gdb进行调试的能力。代码文件解压后有一个bomb和bomb.c,bomb是实验的可执行程序,bomb.c是实验的main函数(里面隐藏了若干函数,需要我们通过bomb的可执行文件进行反汇编,去搜索六个关卡的答案)
第一步:objdump -d bomb > bomb.s
将反汇编代码放在bomb.s文本中方便查看
第二步:Ctrl+F快捷键搜索phase_1,这是第一关的反汇编代码,我们要基于此进行拆炸弹。
第三步:仔细分析找到的反汇编代码,在终端中执行 gdb bomb
,输入r就开启了该实验,需要输入正确的字符串才能过关。
实验过程需要通过gdb获得一些信息找到答案,列举一下我用到的gdb调试命令:
b:设置断点。 如b phase_1
,表示在phase1函数中设断点
r:执行,直到第一个断点处停止。
ni:单步执行。
x/8x 0x400124:以十六进制打印0x400124的8字节内容
x/8d 0x400124:以十进制打印0x400124的8字节内容
x/2s 0x400124:打印地址0x400124开头的字符串
info reg:打印寄存器的值。
好的,现在我们开始第一关的分析。
1.phase_1主函数:
0000000000400ee0 <phase_1>:
400ee0: 48 83 ec 08 sub $0x8,%rsp
400ee4: be 00 24 40 00 mov $0x402400,%esi
400ee9: e8 4a 04 00 00 callq 401338 <strings_not_equal>
// call一个比较字符串的函数,两字符串不相等则返回1,相等则返回0
400eee: 85 c0 test %eax,%eax
400ef0: 74 05 je 400ef7 <phase_1+0x17>
// 若等于0,则正常返回,不然爆炸
400ef2: e8 43 05 00 00 callq 40143a <explode_bomb>
400ef7: 48 83 c4 08 add $0x8,%rsp
400efb: c3 retq
phase_1
逻辑很清楚,调用strings_not_equal函数
,若返回0则成功,返回1则bomb()
,所以先分析后面的函数部分。`
2.strings_not_equal 函数:
0000000000401338 <strings_not_equal>:
401338: 41 54 push %r12
40133a: 55 push %rbp
40133b: 53 push %rbx
40133c: 48 89 fb mov %rdi,%rbx #rbx=x
40133f: 48 89 f5 mov %rsi,%rbp #rbp=y
401342: e8 d4 ff ff ff callq 40131b <string_length>
401347: 41 89 c4 mov %eax,%r12d # r12d=length(x)
40134a: 48 89 ef mov %rbp,%rdi # rdi=y
40134d: e8 c9 ff ff ff callq 40131b <string_length>
401352: ba 01 00 00 00 mov $0x1,%edx # edx=1
401357: 41 39 c4 cmp %eax,%r12d
40135a: 75 3f jne 40139b <strings_not_equal+0x63>
// if(length(y)!=length(x))-->return 1
40135c: 0f b6 03 movzbl (%rbx),%eax #rax=*x
40135f: 84 c0 test %al,%al
401361: 74 25 je 401388 <strings_not_equal+0x50>
// if(*x==0) --> {401388}
401363: 3a 45 00 cmp 0x0(%rbp),%al
401366: 74 0a je 401372 <strings_not_equal+0x3a>
// if(*x==*y) --> {401372}
401368: eb 25 jmp 40138f <strings_not_equal+0x57>
// else --> return 1
40136a: 3a 45 00 cmp 0x0(%rbp),%al #{
40136a}
40136d: 0f 1f 00 nopl (%rax)
401370: 75 24 jne 401396 <strings_not_equal+0x5e>
// if (*x!=*y) -> return 1
401372: 48 83 c3 01 add $0x1,%rbx #rbx+=1 (x++)
401376: 48 83 c5 01 add $0x1,%rbp #rbp+=1 (y++)
40137a: 0f b6 03 movzbl (%rbx),%eax #rax=*x
40137d: 84 c0 test %al,%al
40137f: 75 e9 jne 40136a <strings_not_equal+0x32>
//if(*x!=0) ->{40136a}
401381: ba 00 00 00 00 mov $0x0,%edx
401386: eb 13 jmp 40139b <strings_not_equal+0x63>
// return 0
401388: ba 00 00 00 00 mov $0x0,%edx #{
401388}:
40138d: eb 0c jmp 40139b <strings_not_equal+0x63>
// return 0;
40138f: ba 01 00 00 00 mov $0x1,%edx
401394: eb 05 jmp 40139b <strings_not_equal+0x63>
// return 1;
401396: ba 01 00 00 00 mov $0x1,%edx
40139b: 89 d0 mov %edx,%eax
40139d: 5b pop %rbx
40139e: 5d pop %rbp
40139f: 41 5c pop %r12
4013a1: c3 retq
将上述汇编代码忠实地实现为C代码为:
bool strings_not_equal(char *x,char *y)
{
if (length(x)!=length(y))
return 1;
if (*x==0)
return 0;
if (*x!=*y)
return 1;
else
{
do
{
if (*x!=*y)
return 1;
else
{
x++;
y++;
}
}(while (*x!=0))
}
return 0;
}
简化代码后变为:
bool string_not_equal(char *x,char *y)
{
if (length(x)!=length(y))
return 1;
while (*x!=0)
{
if (*x!=*y)
return 1;
x++;y++;
}
return 0;
}``
3.string_length 函数:
0000000000401338 <strings_not_equal>:
401338: 41 54 push %r12
40133a: 55 push %rbp
40133b: 53 push %rbx
40133c: 48 89 fb mov %rdi,%rbx #rbx=x
40133f: 48 89 f5 mov %rsi,%rbp #rbp=y
401342: e8 d4 ff ff ff callq 40131b <string_length>
401347: 41 89 c4 mov %eax,%r12d # r12d=length(x)
40134a: 48 89 ef mov %rbp,%rdi # rdi=y
40134d: e8 c9 ff ff ff callq 40131b <string_length>
401352: ba 01 00 00 00 mov $0x1,%edx # edx=1
401357: 41 39 c4 cmp %eax,%r12d
40135a: 75 3f jne 40139b <strings_not_equal+0x63>
// if(length(y)!=length(x))-->return 1
40135c: 0f b6 03 movzbl (%rbx),%eax #rax=*x
40135f: 84 c0 test %al,%al
401361: 74 25 je 401388 <strings_not_equal+0x50>
401363: 3a 45 00 cmp 0x0(%rbp),%al
401366: 74 0a je 401372 <strings_not_equal+0x3a>
401368: eb 25 jmp 40138f <strings_not_equal+0x57>
40136a: 3a 45 00 cmp 0x0(%rbp),%al
40136d: 0f 1f 00 nopl (%rax)
401370: 75 24 jne 401396 <strings_not_equal+0x5e>
401372: 48 83 c3 01 add $0x1,%rbx #rbx+=1 (x++)
401376: 48 83 c5 01 add $0x1,%rbp #rbp+=1 (y++)
40137a: 0f b6 03 movzbl (%rbx),%eax #rax=*x
40137d: 84 c0 test %al,%al
40137f: 75 e9 jne 40136a <strings_not_equal+0x32>
401381: ba 00 00 00 00 mov $0x0,%edx
401386: eb 13 jmp 40139b <strings_not_equal+0x63>
401388: ba 00 00 00 00 mov $0x0,%edx
40138d: eb 0c jmp 40139b <strings_not_equal+0x63>
40138f: ba 01 00 00 00 mov $0x1,%edx
401394: eb 05 jmp 40139b <strings_not_equal+0x63>
401396: ba 01 00 00 00 mov $0x1,%edx
40139b: 89 d0 mov %edx,%eax
40139d: 5b pop %rbx
40139e: 5d pop %rbp
40139f: 41 5c pop %r12
4013a1: c3 retq
将上述汇编代码忠实地实现为C代码为:
int string_length(char *x) //求字符串长度
{
if (*x==0)
return 0;
x_begin=x;
else
{
do
{
x++;
}while(*x !=0)
}
return (x-xbegin);
}
简化代码后变为:
int string_length(char *x)
{
x_begin=x;
while (*x!=0)
x++;
return x-x_begin
}
4.最后的求解结果:
实现了两个函数后很清晰:
string_length(char *):
用来求字符串长度
string_not_equal(char *,char *):
如其名字一样,当两字符串相等时return 0.
至此,可以完成phase_2函数–>
void phase_2(char *x)
{