计算机系统lab2——bomb lab
(1)phase_1
先得到汇编代码:
看到函数是<strings_not_equal>,猜测是一个比较字符串是否相等的函数,在0x400ee9处调用了函数strings_not_equal(%rdi,%rsi),在这之前向%esi输入了一个地址0x402400,我们使用命令x/s 0x402400得到待比较的字符串。
所以我们需要输入的字符串和其相等即可。
字符串为 Border relations with Canada have never been better.
(2)phase_2
先得到汇编代码
看到函数是<read_six_numbers>则判断输入是6个数字,在400f0a处(%rsp)中内容和1作比较,如果第一个数!=1就炸弹爆炸;(%rbx)始终保存为过程中的值;(%rbp)储存栈末后一位的指针,作为循环跳出的条件;进入循环400f17,每次比较前一个数的两倍和第二个数,根据400f1a处看到,如果前一个数的两倍!=第二个数,则炸弹爆炸,否则栈指针+1,继续比较。则根据6个数的循环,判断出数字为1 2 4 8 16 32。
(3)phase_3
观察到sscanf函数作为读入函数,则查看其传入参数是什么值;
发现是输入是两个整数;观察关于栈的操作:
400f43: 48 83 ec 18 sub $0x18,%rsp
400f47: 48 8d 4c 24 0c lea 0xc(%rsp),%rcx
400f4c: 48 8d 54 24 08 lea 0x8(%rsp),%rdx
0x8(%rsp)中储存第一个值的地址,0xc(%rsp)储存第二个数的地址;
400f5b: e8 90 fc ff ff callq 400bf0 <[email protected]>
400f60: 83 f8 01 cmp $0x1,%eax
调用读入函数返回的值为读入正确数据的个数,若小于1则炸弹爆炸,否则继续;
400f6a: 83 7c 24 08 07 cmpl $0x7,0x8(%rsp)
指令将第一个数和7做比较,若大于7则炸弹爆炸,由此看出第一个数一定要<=7;
400f71: 8b 44 24 08 mov 0x8(%rsp),%eax
400f75: ff 24 c5 70 24 40 00 jmpq *0x402470(,%rax,8)
由此看出第二句为switch跳转表,则*0x402470为间接寻址,则使用指令得出其所存储的地址;
则根据输入值直接构成跳转表
400f75: ff 24 c5 70 24 40 00 jmpq *0x402470(,%rax,8)
400f7c: b8 cf 00 00 00 mov $0xcf,%eax
400f81: eb 3b jmp 400fbe <phase_3+0x7b>
400f83: b8 c3 02 00 00 mov $0x2c3,%eax
400f88: eb 34 jmp 400fbe <phase_3+0x7b>
400f8a: b8 00 01 00 00 mov $0x100,%eax
400f8f: eb 2d jmp 400fbe <phase_3+0x7b>
400f91: b8 85 01 00 00 mov $0x185,%eax
400f96: eb 26 jmp 400fbe <phase_3+0x7b>
400f98: b8 ce 00 00 00 mov $0xce,%eax
400f9d: eb 1f jmp 400fbe <phase_3+0x7b>
400f9f: b8 aa 02 00 00 mov $0x2aa,%eax
400fa4: eb 18 jmp 400fbe <phase_3+0x7b>
400fa6: b8 47 01 00 00 mov $0x147,%eax
400fab: eb 11 jmp 400fbe <phase_3+0x7b>
所以输入的字符串是0 207或1 311或2 707或3 256或4 389或5 206或6 682或7 327
(4)phase_4
先得到汇编代码
观察输入函数和phase_3相同,得到输入是两个整数;
0x0000000000401024 <+24>: callq 0x400bf0 <[email protected]>
0x0000000000401029 <+29>: cmp $0x2,%eax
0x000000000040102c <+32>: jne 0x401035 <phase_4+41>
这一段表明sscanf输入函数返回值不等于2的时候就爆炸
0x000000000040102e <+34>: cmpl $0xe,0x8(%rsp)
0x0000000000401033 <+39>: jbe 0x40103a <phase_4+46>
0x0000000000401035 <+41>: callq 0x40143a <explode_bomb>
由此看出如果第一个数大于14的话就会爆炸;否则调用函数func4
0x000000000040103a <+46>: mov $0xe,%edx
0x000000000040103f <+51>: mov $0x0,%esi
0x0000000000401044 <+56>: mov 0x8(%rsp),%edi
0x0000000000401048 <+60>: callq 0x400fce <func4>
看出函数的参数为三个数,%edi为第一个参数是我们输入的第一个数,%esi是函数的第二个参数是0,%edx是函数的第三个参数是14
由此我们输入命令观察func4函数的汇编代码
其是一个递归函数,翻译成c语言大致是
0x000000000040104d <+65>: test %eax,%eax
0x000000000040104f <+67>: jne 0x401058 <phase_4+76>
0x0000000000401051 <+69>: cmpl $0x0,0xc(%rsp)
0x0000000000401056 <+74>: je 0x40105d <phase_4+81>
0x0000000000401058 <+76>: callq 0x40143a <explode_bomb>
再观察这一段表现出func4的返回值必须为0和我们输入的第二个数必须为0
最后通过计算得出
0 0或1 0或3 0或7 0都为正确答案
(5)phase_5
0x0000000000401062 <+0>: push %rbx
0x0000000000401063 <+1>: sub $0x20,%rsp
0x0000000000401067 <+5>: mov %rdi,%rbx
0x000000000040106a <+8>: mov %fs:0x28,%rax
0x0000000000401073 <+17>: mov %rax,0x18(%rsp)
将输入的地址%rdi给了%rbx;
观察函数<string_length>为返回字符串长度的值
0x000000000040107a <+24>: callq 0x40131b <string_length>
0x000000000040107f <+29>: cmp $0x6,%eax
0x0000000000401082 <+32>: je 0x4010d2 <phase_5+112>
0x0000000000401084 <+34>: callq 0x40143a <explode_bomb>
可以看到我们需要输入6个字符,否则爆炸
下面是一个字符串处理的六次循环函数
0x000000000040108b <+41>: movzbl (%rbx,%rax,1),%ecx
0x000000000040108f <+45>: mov %cl,(%rsp)
0x0000000000401092 <+48>: mov (%rsp),%rdx
0x0000000000401096 <+52>: and $0xf,%edx
0x0000000000401099 <+55>: movzbl 0x4024b0(%rdx),%edx
0x00000000004010a0 <+62>: mov %dl,0x10(%rsp,%rax,1)
由上面看到movzbl命令将从%rbx(输入)开始的%rax位置的一个字节赋给%ecx的低16位。接下来先把%cl中的值复制到%rsp处,再将%rsp中的值复制到%rdx中,并且&0xf取%edx的低4位。所以就是取读入的字符串中%rax位置处的字符,并且再取它的低4位放在%edx中。然后再将0x4024b0(%rdx)的一个字节放入%edx再将其末尾2字节放在了0x10(%rsp,%rax,1);
可以看到0x4024b0中的字符串如上;
0x00000000004010b3 <+81>: mov $0x40245e,%esi
0x00000000004010b8 <+86>: lea 0x10(%rsp),%rdi
0x00000000004010bd <+91>: callq 0x401338 <strings_not_equal>
0x00000000004010c2 <+96>: test %eax,%eax
0x00000000004010c4 <+98>: je 0x4010d9 <phase_5+119>
0x00000000004010c6 <+100>: callq 0x40143a <explode_bomb>
对比我们输入的字符串和处理后的字符串,调用<strings_not_equal>函数,如果不相同则爆炸;
0x40245e的字符串是如上;
总的来说即以我们输入的六个字符的每一个字符的低8位作为0x4024b0这个字符串的偏移量,取出的和0x40245e中的相同。
再根据ascii码表查表
flyers对应的下标是
9 1001
15 1111
14 1110
5 0101
6 0110
7 0111
yonuvw
得到相应字符;
(6)phase_6
先得到相应的汇编代码(太长了)不截屏了
观察上面这段代码,得出是读取6个值放入栈中;
从中可以看到我们读取的值需要前后相邻的不相等并且<=6,否则就爆炸;
每一个输入的值都用7减去 并且替换原来的值;
可以看出构造了一段地址连续的储存值的空间,
可以使用gdb命令看看地址中的内容
0x0000000000401183 <+143>: mov $0x6032d0,%edx
0x0000000000401188 <+148>: mov %rdx,0x20(%rsp,%rsi,2)
发现是node给了提示,这样的数据结构可能是链表;
并且根据我们输入的值存放的%ecx中的顺序构造;结点的首地址是rsp+0x20
%rbx(0x20(%rsp))储存的是链表的首节点地址,0x28(%rsp)储存在%rax中是链表的第二个结点的地址,0x50(%rsp)是链表的最后一个结点的地址;
取出首地址的值并且根据%rbx和%rax的移动来遍历链表,
0x00000000004011e5 <+241>: cmp %eax,(%rbx)
0x00000000004011e7 <+243>: jge 0x4011ee <phase_6+250>
0x00000000004011e9 <+245>: callq 0x40143a <explode_bomb>
并且要求链表的前一个结点中存放的数据的最后4字节要
大于后一个结点。
所以使用命令观察地址中的值,观察其顺序;
则得出从大到小的顺序是3 4 5 6 1 2
所以7-x=4 3 2 1 6 5
成功拆弹。
总体跑分截图