【CSAPP】拆炸弹实验:BombLab

555 阅读27分钟

Bomblab 实验

CSAPP课程中拆炸弹实验

注意:这个实验整体难度很大,需要静下心来慢慢研究,加油!

gdb 相关命令

gdb -q bomb      //调试bomb程序
disas phase_1       //反汇编phase_1函数
x/s 0x804a264       //取出内存中0x804a264字符串的值
x/(8)g 0x402470       //取出0x402470开始,八个八字节单元(常用于switch表)
                     //如果是x/w读取字,x/b读取字节,x/h读取双字节,x/x按16进制显示变量

常用指令

test S1, S2        //S1&S2比较,设置对应标志位
cmp S1, S2         //S2-S1比较
lea    //加载有效地址
jmp    //直接跳转

拆弹实验具体题目

第一题

   0x0000000000400ee0 <+0>:	sub    $0x8,%rsp             //开辟一个空间保存返回地址
   0x0000000000400ee4 <+4>:	mov    $0x402400,%esi        //0x402400放入esi寄存器
   0x0000000000400ee9 <+9>:	callq  0x401338 <strings_not_equal>       //调用函数判断是否不相等,不相等返回1否则返回0
   0x0000000000400eee <+14>:	test   %eax,%eax      //测试返回值是否为0
   0x0000000000400ef0 <+16>:	je     0x400ef7 <phase_1+23>      //如果返回值为0,跳过爆炸函数
   0x0000000000400ef2 <+18>:	callq  0x40143a <explode_bomb>
   0x0000000000400ef7 <+23>:	add    $0x8,%rsp     //加回来
   0x0000000000400efb <+27>:	retq  

key:<strings_not_equal> 传入edi和esi寄存器的值,判断相等与否,返回值在rax中 answer:0x402400的值即为所求字符串

第一题实战

0x0000000000001204 <+0>:	sub    $0x8,%rsp
0x0000000000001208 <+4>:	lea    0x1781(%rip),%rsi        # 0x2990
0x000000000000120f <+11>:	callq  0x16c6 <strings_not_equal>   // 调用函数判断是否不相等,不相等返回1,相等返回0
0x0000000000001214 <+16>:	test   %eax,%eax
0x0000000000001216 <+18>:	jne    0x121d <phase_1+25>          // eax不为0则爆炸
0x0000000000001218 <+20>:	add    $0x8,%rsp
0x000000000000121c <+24>:	retq
0x000000000000121d <+25>:	callq  0x1956 <explode_bomb>
0x0000000000001222 <+30>:	jmp    0x1218 <phase_1+20>

在phase_1打上断点,stepi至+11,直接获取%rsi的值:"I am not part of the problem. I am a Republican."

第二题

   0x0000000000400efc <+0>:	push   %rbp          //rbp入栈
   0x0000000000400efd <+1>:	push   %rbx          //rbx入栈
   0x0000000000400efe <+2>:	sub    $0x28,%rsp       //开辟五个空间
   0x0000000000400f02 <+6>:	mov    %rsp,%rsi        //栈指针地址存入rsi中
   0x0000000000400f05 <+9>:	callq  0x40145c <read_six_numbers>     //调用read_six_numbers函数
   0x0000000000400f0a <+14>:	cmpl   $0x1,(%rsp)     //rsp的地址的值与1比较
   0x0000000000400f0e <+18>:	je     0x400f30 <phase_2+52>     //如果rsp的值等于1,跳转到0x400f30,否则直接触发爆炸
——————————————————————————————————————————————————————————————————————————————
   0x0000000000400f10 <+20>:	callq  0x40143a <explode_bomb>
   0x0000000000400f15 <+25>:	jmp    0x400f30 <phase_2+52>
   0x0000000000400f17 <+27>:	mov    -0x4(%rbx),%eax     //rbx的地址减4的值放入eax
   0x0000000000400f1a <+30>:	add    %eax,%eax       //eax乘2
   0x0000000000400f1c <+32>:	cmp    %eax,(%rbx)     //rbx的内存值减eax
   0x0000000000400f1e <+34>:	je     0x400f25 <phase_2+41>      //如果rbx地址的值与eax相等,跳转至0x400f25(跳过爆炸)
   0x0000000000400f20 <+36>:	callq  0x40143a <explode_bomb>     //爆炸
   0x0000000000400f25 <+41>:	add    $0x4,%rbx     //rbx的值+0x4
   0x0000000000400f29 <+45>:	cmp    %rbp,%rbx     //rbx的值-rbp的值
   0x0000000000400f2c <+48>:	jne    0x400f17 <phase_2+27>     //如果不相等跳转到0x400f17
   0x0000000000400f2e <+50>:	jmp    0x400f3c <phase_2+64>     //否则跳转到0x400f3c
——————————————————————————————————————————————————————————————————————————————
   0x0000000000400f30 <+52>:	lea    0x4(%rsp),%rbx       //rsp+4地址的值放入rbx
   0x0000000000400f35 <+57>:	lea    0x18(%rsp),%rbp      //rsp+0x18(十进制24)值放入rbp
   0x0000000000400f3a <+62>:	jmp    0x400f17 <phase_2+27>     //直接跳转到0x400f17
   0x0000000000400f3c <+64>:	add    $0x28,%rsp     //加回栈值,程序结束
   0x0000000000400f40 <+68>:	pop    %rbx
   0x0000000000400f41 <+69>:	pop    %rbp
   0x0000000000400f42 <+70>:	retq

key:

   0x0000000000400f17 <+27>:	mov    -0x4(%rbx),%eax     //rbx的地址减4的值放入eax
   0x0000000000400f1a <+30>:	add    %eax,%eax       //eax乘2
   0x0000000000400f1c <+32>:	cmp    %eax,(%rbx)     //rbx的内存值减eax
   0x0000000000400f1e <+34>:	je     0x400f25 <phase_2+41>      //如果rbx地址的值与eax相等,跳转至0x400f25(跳过爆炸)
   由此可以得知,rbx比eax index大1,需要rbx的值恰好为eax的两倍

answer:读入六个int组成数组,此数组中index大1,则数值翻一倍。同时首值必须为1: 1 2 4 8 16 32

第二题实战

   0x0000000000001224 <+0>:	push   %rbp
   0x0000000000001225 <+1>:	push   %rbx
   0x0000000000001226 <+2>:	sub    $0x28,%rsp
   0x000000000000122a <+6>:	mov    %fs:0x28,%rax
   0x0000000000001233 <+15>:	mov    %rax,0x18(%rsp)
   0x0000000000001238 <+20>:	xor    %eax,%eax                 // eax异或自身,eax=0
   0x000000000000123a <+22>:	mov    %rsp,%rsi
   0x000000000000123d <+25>:	callq  0x1992 <read_six_numbers>
   0x0000000000001242 <+30>:	cmpl   $0x0,(%rsp)
   0x0000000000001246 <+34>:	jne    0x124f <phase_2+43>       // rsp的值 !=0 跳转到+43爆炸
   0x0000000000001248 <+36>:	cmpl   $0x1,0x4(%rsp)
   0x000000000000124d <+41>:	je     0x1254 <phase_2+48>       // rsp+4的值==1 则跳转至+48避免爆炸
   0x000000000000124f <+43>:	callq  0x1956 <explode_bomb>
   0x0000000000001254 <+48>:	mov    %rsp,%rbx                 // rbx = rsp
   0x0000000000001257 <+51>:	lea    0x10(%rbx),%rbp           // rbp = rbx+16的值
   0x000000000000125b <+55>:	jmp    0x1266 <phase_2+66>       // 跳转至+66
   0x000000000000125d <+57>:	add    $0x4,%rbx                 // rbx +=4
   0x0000000000001261 <+61>:	cmp    %rbp,%rbx
   0x0000000000001264 <+64>:	je     0x1277 <phase_2+83>       // rbx==rbp则跳转至+83
   0x0000000000001266 <+66>:	mov    0x4(%rbx),%eax            // eax = rbx+4的值
   0x0000000000001269 <+69>:	add    (%rbx),%eax               // eax += rbx的值
   0x000000000000126b <+71>:	cmp    %eax,0x8(%rbx)
   0x000000000000126e <+74>:	je     0x125d <phase_2+57>       // rbx+8的值==eax则跳转至+57避免爆炸
   0x0000000000001270 <+76>:	callq  0x1956 <explode_bomb>
   0x0000000000001275 <+81>:	jmp    0x125d <phase_2+57>
   0x0000000000001277 <+83>:	mov    0x18(%rsp),%rax
   0x000000000000127c <+88>:	xor    %fs:0x28,%rax
   0x0000000000001285 <+97>:	jne    0x128e <phase_2+106>      // 金丝雀用法,发现原来%fs:0x28的值被覆盖后则栈溢出错误
   0x0000000000001287 <+99>:	add    $0x28,%rsp
   0x000000000000128b <+103>:	pop    %rbx
   0x000000000000128c <+104>:	pop    %rbp
   0x000000000000128d <+105>:	retq
   0x000000000000128e <+106>:	callq  0xe50 <__stack_chk_fail@plt>

answer: rsp开始依次存放数,要求第一个数为0,第二个数为1。 之后从下面这段代码知主体为斐波那契数列,输入0 1 1 2 3 5通关

   0x0000000000001266 <+66>:	mov    0x4(%rbx),%eax            // eax = rbx+4的值
   0x0000000000001269 <+69>:	add    (%rbx),%eax               // eax += rbx的值
   0x000000000000126b <+71>:	cmp    %eax,0x8(%rbx)
   0x000000000000126e <+74>:	je     0x125d <phase_2+57>       // rbx+8的值==eax则跳转至+57避免爆炸

其他细节:rbp为尾指针,rbx和rax中间变量完成比较操作

第三题

   0x0000000000400f43 <+0>:	sub    $0x18,%rsp      //开辟24位栈空间
   0x0000000000400f47 <+4>:	lea    0xc(%rsp),%rcx       //rsp值加12,存入rcx(第四个参数)中
   0x0000000000400f4c <+9>:	lea    0x8(%rsp),%rdx       //rsp值加8,存入rdx(第三个参数)中
   0x0000000000400f51 <+14>:	mov    $0x4025cf,%esi      //0x4025cf移入esi(第二个参数)中,访问0x4025cf得到"%d %d"说明scanf输入两个整数
   0x0000000000400f56 <+19>:	mov    $0x0,%eax       //0移入eax中
   0x0000000000400f5b <+24>:	callq  0x400bf0 <__isoc99_sscanf@plt>     //调用__isoc99_sscanf@plt函数,得到eax返回值。注意scanf函数返回值是根据输入数决定的,如正确输入两个数返回值=2
   0x0000000000400f60 <+29>:	cmp    $0x1,%eax  
   0x0000000000400f63 <+32>:	jg     0x400f6a <phase_3+39>     //如果eax>1则跳转到0x400f6a
   0x0000000000400f65 <+34>:	callq  0x40143a <explode_bomb>     //eax<=1 则触发爆炸
   0x0000000000400f6a <+39>:	cmpl   $0x7,0x8(%rsp)
   0x0000000000400f6f <+44>:	ja     0x400fad <phase_3+106>     //如果rsp+8地址处值>7则跳转到爆炸
   0x0000000000400f71 <+46>:	mov    0x8(%rsp),%eax      //rsp+8地址处值<=7则让rsp+8的值移入eax
   ———————————————————————————————————————————————————————————————— 一个switch表格
   0x0000000000400f75 <+50>:	jmpq   *0x402470(,%rax,8)     //*号为间接跳转,跳转至0x402470+ 8*rax的地址
   0x0000000000400f7c <+57>:	mov    $0xcf,%eax     //eax = 0xcf即207
   0x0000000000400f81 <+62>:	jmp    0x400fbe <phase_3+123>     //跳转至0x400fbe,下同
   0x0000000000400f83 <+64>:	mov    $0x2c3,%eax     //eax = 0x2c3即707
   0x0000000000400f88 <+69>:	jmp    0x400fbe <phase_3+123>
   0x0000000000400f8a <+71>:	mov    $0x100,%eax     //eax = 0x100即256
   0x0000000000400f8f <+76>:	jmp    0x400fbe <phase_3+123>
   0x0000000000400f91 <+78>:	mov    $0x185,%eax     //eax = 0x185即389
   0x0000000000400f96 <+83>:	jmp    0x400fbe <phase_3+123>
   0x0000000000400f98 <+85>:	mov    $0xce,%eax      //eax = 0xce即206
   0x0000000000400f9d <+90>:	jmp    0x400fbe <phase_3+123>
   0x0000000000400f9f <+92>:	mov    $0x2aa,%eax     //eax = 0x2aa即682
   0x0000000000400fa4 <+97>:	jmp    0x400fbe <phase_3+123>
   0x0000000000400fa6 <+99>:	mov    $0x147,%eax      //eax = 0x147即327
   0x0000000000400fab <+104>:	jmp    0x400fbe <phase_3+123>
   0x0000000000400fad <+106>:	callq  0x40143a <explode_bomb>
   0x0000000000400fb2 <+111>:	mov    $0x0,%eax      //eax = 0x0
   0x0000000000400fb7 <+116>:	jmp    0x400fbe <phase_3+123>
   0x0000000000400fb9 <+118>:	mov    $0x137,%eax      //eax = 0x137即311
   ————————————————————————————————————————————————————————————————————
   0x0000000000400fbe <+123>:	cmp    0xc(%rsp),%eax
   0x0000000000400fc2 <+127>:	je     0x400fc9 <phase_3+134>     //如果eax==rsp+12的值则避免爆炸
   0x0000000000400fc4 <+129>:	callq  0x40143a <explode_bomb>
   0x0000000000400fc9 <+134>:	add    $0x18,%rsp
   0x0000000000400fcd <+138>:	retq

key:x/s 0x4025cf得到"%d %d"知晓scanf输入两个数字 key2:栈首先减0x18(开辟空间),再输入值可以理解为由顶部开始往下放。为什么会有这个结果呢?可能是输入时借助了一个临时栈,使得第一个输入存在临时栈的栈底,然后返回时便成为了栈帧的栈顶。 key3:x/8g 0x402470得到switch跳转表

0x402470:	0x0000000000400f7c	0x0000000000400fb9
0x402480:	0x0000000000400f83	0x0000000000400f8a
0x402490:	0x0000000000400f91	0x0000000000400f98
0x4024a0:	0x0000000000400f9f	0x0000000000400fa6

answer:输入两个数字,第一个指定跳转到switch表第几位,第二个用于判断对应switch表的数字是否相等 0 207;1 311;2 707;3 256; 4 389;5 206; 6 682; 7 327(选一个输入)

第三题实战

   0x0000555555555293 <+0>:	sub    $0x18,%rsp
   0x0000555555555297 <+4>:	mov    %fs:0x28,%rax
   0x00005555555552a0 <+13>:	mov    %rax,0x8(%rsp)
   0x00005555555552a5 <+18>:	xor    %eax,%eax              // eax = 0
   0x00005555555552a7 <+20>:	lea    0x4(%rsp),%rcx         // rcx = rsp+4的值
   0x00005555555552ac <+25>:	mov    %rsp,%rdx              // rdx = rsp
   0x00005555555552af <+28>:	lea    0x1987(%rip),%rsi      // 访问此处%rsi得到"%d %d"得到输入为两个整数
   0x00005555555552b6 <+35>:	callq  0x555555554ef0 <__isoc99_sscanf@plt>
   0x00005555555552bb <+40>:	cmp    $0x1,%eax
   0x00005555555552be <+43>:	jle    0x5555555552dd <phase_3+74>     // eax<=1 跳转至+74爆炸(检测输入是否两个整数)
   0x00005555555552c0 <+45>:	cmpl   $0x7,(%rsp)
   0x00005555555552c4 <+49>:	ja     0x555555555363 <phase_3+208>    // rsp的值>7跳转至+208爆炸(输入小于7)
   0x00005555555552ca <+55>:	mov    (%rsp),%eax                     // eax = rsp的值
   0x00005555555552cd <+58>:	lea    0x172c(%rip),%rdx               // rdx = rip+0x172c的值
   0x00005555555552d4 <+65>:	movslq (%rdx,%rax,4),%rax              // rax = rdx+4*rax
   0x00005555555552d8 <+69>:	add    %rdx,%rax                       // rax += rdx = 2*rdx + 4*rax
   0x00005555555552db <+72>:	jmpq   *%rax                           // 间接跳转,跳转至rax的地址值
   0x00005555555552dd <+74>:	callq  0x555555555956 <explode_bomb>
   0x00005555555552e2 <+79>:	jmp    0x5555555552c0 <phase_3+45>     // 跳转至+45
   0x00005555555552e4 <+81>:	mov    $0x18c,%eax                     // eax = 0x18c
   0x00005555555552e9 <+86>:	jmp    0x5555555552f0 <phase_3+93>     // 跳转至+93
   0x00005555555552eb <+88>:	mov    $0x0,%eax
   0x00005555555552f0 <+93>:	sub    $0x95,%eax
   0x00005555555552f5 <+98>:	add    $0x3a8,%eax
   0x00005555555552fa <+103>:	sub    $0x390,%eax
   0x00005555555552ff <+108>:	add    $0x390,%eax
   0x0000555555555304 <+113>:	sub    $0x390,%eax
   0x0000555555555309 <+118>:	add    $0x390,%eax
   0x000055555555530e <+123>:	sub    $0x390,%eax
   0x0000555555555313 <+128>:	cmpl   $0x5,(%rsp)
   0x0000555555555317 <+132>:	jg     0x55555555531f <phase_3+140>    // rsp的值>5则爆炸(输入小于等于5)
   0x0000555555555319 <+134>:	cmp    %eax,0x4(%rsp)
   0x000055555555531d <+138>:	je     0x555555555324 <phase_3+145>    // rsp+4的值==eax则跳转至+145避免爆炸
   0x000055555555531f <+140>:	callq  0x555555555956 <explode_bomb>
   0x0000555555555324 <+145>:	mov    0x8(%rsp),%rax
   0x0000555555555329 <+150>:	xor    %fs:0x28,%rax
   0x0000555555555332 <+159>:	jne    0x55555555536f <phase_3+220>    // 异或不为0跳转至栈溢出报错
   0x0000555555555334 <+161>:	add    $0x18,%rsp                      // 加回栈值返回
   0x0000555555555338 <+165>:	retq
   ————————————————————————————————————————————————————————————————————一个switch0x0000555555555339 <+166>:	mov    $0x0,%eax
   0x000055555555533e <+171>:	jmp    0x5555555552f5 <phase_3+98>
   0x0000555555555340 <+173>:	mov    $0x0,%eax
   0x0000555555555345 <+178>:	jmp    0x5555555552fa <phase_3+103>
   0x0000555555555347 <+180>:	mov    $0x0,%eax
   0x000055555555534c <+185>:	jmp    0x5555555552ff <phase_3+108>
   0x000055555555534e <+187>:	mov    $0x0,%eax
   0x0000555555555353 <+192>:	jmp    0x555555555304 <phase_3+113>
   0x0000555555555355 <+194>:	mov    $0x0,%eax
   0x000055555555535a <+199>:	jmp    0x555555555309 <phase_3+118>
   0x000055555555535c <+201>:	mov    $0x0,%eax
   0x0000555555555361 <+206>:	jmp    0x55555555530e <phase_3+123>
   0x0000555555555363 <+208>:	callq  0x555555555956 <explode_bomb>
   0x0000555555555368 <+213>:	mov    $0x0,%eax
   0x000055555555536d <+218>:	jmp    0x555555555313 <phase_3+128>
   0x000055555555536f <+220>:	callq  0x555555554e50 <__stack_chk_fail@plt>

answer:我们知道第一个输入(rsp)小于等于5,且是unsigned所以值>=0。第二个输入需要等于处理后的eax值,同第三题处理方案。 这里我们偷懒直接试探出0 271

第四题

   0x000000000040100c <+0>:	sub    $0x18,%rsp
   0x0000000000401010 <+4>:	lea    0xc(%rsp),%rcx      //rsp+12读到rcx(第四个参数)
   0x0000000000401015 <+9>:	lea    0x8(%rsp),%rdx      //rsp+8读到rdx(第三个参数)
   0x000000000040101a <+14>:	mov    $0x4025cf,%esi      //0x4025cf的值移动到esi中,读到"%d %d",说明scanf仍然输入两个整数
   0x000000000040101f <+19>:	mov    $0x0,%eax      //0移入eax
   0x0000000000401024 <+24>:	callq  0x400bf0 <__isoc99_sscanf@plt>     //调用scanf函数
   0x0000000000401029 <+29>:	cmp    $0x2,%eax  
   0x000000000040102c <+32>:	jne    0x401035 <phase_4+41>      //eax不等于2则跳转至爆炸
   0x000000000040102e <+34>:	cmpl   $0xe,0x8(%rsp)  
   0x0000000000401033 <+39>:	jbe    0x40103a <phase_4+46>    //rsp+8地址的值<=14则不爆炸
   0x0000000000401035 <+41>:	callq  0x40143a <explode_bomb>
   0x000000000040103a <+46>:	mov    $0xe,%edx     //0xe(14)移动到edx(第三个参数)
   0x000000000040103f <+51>:	mov    $0x0,%esi     //0移动到esi(第二个参数)
   0x0000000000401044 <+56>:	mov    0x8(%rsp),%edi     //rsp+8的值移动到edi(第一个参数)
   0x0000000000401048 <+60>:	callq  0x400fce <func4>     //调用func4
   0x000000000040104d <+65>:	test   %eax,%eax  
   0x000000000040104f <+67>:	jne    0x401058 <phase_4+76>     //eax不等于0则爆炸
   0x0000000000401051 <+69>:	cmpl   $0x0,0xc(%rsp)
   0x0000000000401056 <+74>:	je     0x40105d <phase_4+81>      //rsp+12的值不等于0则爆炸
   0x0000000000401058 <+76>:	callq  0x40143a <explode_bomb>
   0x000000000040105d <+81>:	add    $0x18,%rsp
   0x0000000000401061 <+85>:	retq

key:由此可以知道,输入两个整数,记为x、y,第一个输入<=14,由jbe知其会大于等于0(unsigned),存储在rdx中,第二个输入必须为0。(func4不会改变rsp+12的值),存储在rcx中。

调用disas func4可以获得以下代码

   0x0000000000400fce <+0>:	sub    $0x8,%rsp
   0x0000000000400fd2 <+4>:	mov    %edx,%eax      //edx存到eax中
   0x0000000000400fd4 <+6>:	sub    %esi,%eax      //eax = edx - esi
   0x0000000000400fd6 <+8>:	mov    %eax,%ecx      //eax的值移动到ecx
   0x0000000000400fd8 <+10>:	shr    $0x1f,%ecx     //ecx右移31位
   0x0000000000400fdb <+13>:	add    %ecx,%eax      //eax = eax + ecx
   0x0000000000400fdd <+15>:	sar    %eax           //eax 算术右移1位
   0x0000000000400fdf <+17>:	lea    (%rax,%rsi,1),%ecx      //ecx = rax+rsi的值
   0x0000000000400fe2 <+20>:	cmp    %edi,%ecx
   0x0000000000400fe4 <+22>:	jle    0x400ff2 <func4+36>       //如果ecx<= edi则跳转至0x400ff2
   0x0000000000400fe6 <+24>:	lea    -0x1(%rcx),%edx           //如果ecx>edi则将rcx-1的值读取到edx
   0x0000000000400fe9 <+27>:	callq  0x400fce <func4>          //调用func4
   0x0000000000400fee <+32>:	add    %eax,%eax                 //调用完后把eax*2
   0x0000000000400ff0 <+34>:	jmp    0x401007 <func4+57>       //跳转至函数结束
   0x0000000000400ff2 <+36>:	mov    $0x0,%eax                  //eax = 0
   0x0000000000400ff7 <+41>:	cmp    %edi,%ecx
   0x0000000000400ff9 <+43>:	jge    0x401007 <func4+57>         //如果ecx>=edi 则跳转到0x401007,结束递归
   0x0000000000400ffb <+45>:	lea    0x1(%rcx),%esi              //rcx+1读取到esi(第二个参数)
   0x0000000000400ffe <+48>:	callq  0x400fce <func4>            //调用递归
   0x0000000000401003 <+53>:	lea    0x1(%rax,%rax,1),%eax       //调用完后把2*rax+1读取到eax中
   0x0000000000401007 <+57>:	add    $0x8,%rsp
   0x000000000040100b <+61>:	retq

key:关于递归如果用汇编执行过程会很复杂, 我们使用高级语言翻译再执行过程 这里我们用python进行翻译: 前置条件:x = 第一个输入,需要返回值为0

def func4(esi = 0, edx = 14, ecx = 0):
   result = edx-esi
   ecx = result>>31
   result = (result + ecx)>>1
   ecx = result+ esi
   if ecx<=x:
      result = 0
      if ecx >= x:
         return result
      else:                   # 一旦进入这个分支,最后返回一定不是0,所以x<=7
         result = func4(esi = esi+1, edx = edx, ecx = ecx)
         return 2*result + 1
   else:
      result = func4(esi = esi, edx = ecx-1, ecx = ecx)
      return 2*result

得到此后,我们可以不断尝试0~7的x值,发现x=0、1、3可以通过迭代并返回0, 最终得到结果: 0 0;1 0;3 0; 7 0;(任取其一)

第四题实战

代码:

   0x00005555555553b3 <+0>:	sub    $0x18,%rsp
   0x00005555555553b7 <+4>:	mov    %fs:0x28,%rax
   0x00005555555553c0 <+13>:	mov    %rax,0x8(%rsp)
   0x00005555555553c5 <+18>:	xor    %eax,%eax
   0x00005555555553c7 <+20>:	lea    0x4(%rsp),%rcx
   0x00005555555553cc <+25>:	mov    %rsp,%rdx
   0x00005555555553cf <+28>:	lea    0x1867(%rip),%rsi        // 同样为"%d %d"输入两个整数
   0x00005555555553d6 <+35>:	callq  0x555555554ef0 <__isoc99_sscanf@plt>
   0x00005555555553db <+40>:	cmp    $0x2,%eax
   0x00005555555553de <+43>:	jne    0x5555555553e6 <phase_4+51>     // eax!=2 爆炸
   0x00005555555553e0 <+45>:	cmpl   $0xe,(%rsp)
   0x00005555555553e4 <+49>:	jbe    0x5555555553eb <phase_4+56>     // rsp的值<=14跳转至+56,否则爆炸
   0x00005555555553e6 <+51>:	callq  0x555555555956 <explode_bomb>
   0x00005555555553eb <+56>:	mov    $0xe,%edx                       // edx = 14
   0x00005555555553f0 <+61>:	mov    $0x0,%esi                       // esi = 0
   0x00005555555553f5 <+66>:	mov    (%rsp),%edi                     // edi = rsp的值
   0x00005555555553f8 <+69>:	callq  0x555555555374 <func4>
   0x00005555555553fd <+74>:	cmp    $0x6,%eax
   0x0000555555555400 <+77>:	jne    0x555555555409 <phase_4+86>     // 最终eax!=6跳转至+86爆炸
   0x0000555555555402 <+79>:	cmpl   $0x6,0x4(%rsp)
   0x0000555555555407 <+84>:	je     0x55555555540e <phase_4+91>     // rsp+4的值==6 跳转至+91避免爆炸
   0x0000555555555409 <+86>:	callq  0x555555555956 <explode_bomb>
   0x000055555555540e <+91>:	mov    0x8(%rsp),%rax
   0x0000555555555413 <+96>:	xor    %fs:0x28,%rax                   // 日常金丝雀保护栈
   0x000055555555541c <+105>:	jne    0x555555555423 <phase_4+112>
   0x000055555555541e <+107>:	add    $0x18,%rsp
   0x0000555555555422 <+111>:	retq
   0x0000555555555423 <+112>:	callq  0x555555554e50 <__stack_chk_fail@plt>

由上述代码可以知道:

  • 第一个输入<=14,第二个输入=6.
  • func4的参数:edx = 14, esi = 0, edi = 第一个输入记为x, ecx = 第二个输入 = 6
  • func4返回需要为6

func4:

   0x0000555555555374 <+0>:	sub    $0x8,%rsp
   0x0000555555555378 <+4>:	mov    %edx,%eax
   0x000055555555537a <+6>:	sub    %esi,%eax
   0x000055555555537c <+8>:	mov    %eax,%ecx
   0x000055555555537e <+10>:	shr    $0x1f,%ecx
   0x0000555555555381 <+13>:	add    %eax,%ecx
   0x0000555555555383 <+15>:	sar    %ecx
   0x0000555555555385 <+17>:	add    %esi,%ecx
   0x0000555555555387 <+19>:	cmp    %edi,%ecx
   0x0000555555555389 <+21>:	jg     0x555555555399 <func4+37>    // ecx>edi跳转至+37
   0x000055555555538b <+23>:	mov    $0x0,%eax
   0x0000555555555390 <+28>:	cmp    %edi,%ecx
   0x0000555555555392 <+30>:	jl     0x5555555553a5 <func4+49>    // ecx<edi跳转至+49
   0x0000555555555394 <+32>:	add    $0x8,%rsp
   0x0000555555555398 <+36>:	retq
   0x0000555555555399 <+37>:	lea    -0x1(%rcx),%edx
   0x000055555555539c <+40>:	callq  0x555555555374 <func4>
   0x00005555555553a1 <+45>:	add    %eax,%eax
   0x00005555555553a3 <+47>:	jmp    0x555555555394 <func4+32>
   0x00005555555553a5 <+49>:	lea    0x1(%rcx),%esi
   0x00005555555553a8 <+52>:	callq  0x555555555374 <func4>
   0x00005555555553ad <+57>:	lea    0x1(%rax,%rax,1),%eax
   0x00005555555553b1 <+61>:	jmp    0x555555555394 <func4+32>

同样翻译为python

def func4(esi = 0, edx = 14,ecx = 6):
   result = edx - esi
   ecx = result>>31              # 逻辑右移
   ecx = (ecx + result) >>1 +esi     # 算术右移
   if ecx > edi:
      result = func4(esi = esi, edx = ecx-1,ecx = ecx)
      return result*2
   else:
      result = 0
      if ecx< edi:            # 一旦一开始进入这个分支,那么最终结果一定不是6,所以x必须<=ecx = 7
         result = func4(esi = ecx+1, edx = edx,ecx = ecx)
         return result*2 + 1
      else:
         return result

这里穷举,得到x=6时通过。所以最终结果取6 6

第五题

注:这里开始不用对所有细节完全参悟,消耗时间过多。 代码:

   0x0000000000401062 <+0>:	push   %rbx
   0x0000000000401063 <+1>:	sub    $0x20,%rsp
   0x0000000000401067 <+5>:	mov    %rdi,%rbx              //rbx = rdi
   0x000000000040106a <+8>:	mov    %fs:0x28,%rax          //fs寄存器偏移0x28的值移动到rax
   0x0000000000401073 <+17>:	mov    %rax,0x18(%rsp)        //rax移动到rsp+0x18,即rsp+0x18保存着%fs:0x28的值(金丝雀)
   0x0000000000401078 <+22>:	xor    %eax,%eax              //eax自身按位异或,eax = 0
   0x000000000040107a <+24>:	callq  0x40131b <string_length>       //调用函数string_length,返回值于eax中
   0x000000000040107f <+29>:	cmp    $0x6,%eax
   0x0000000000401082 <+32>:	je     0x4010d2 <phase_5+112>          //eax不为6即字串长度不为6则爆炸
   0x0000000000401084 <+34>:	callq  0x40143a <explode_bomb>
   0x0000000000401089 <+39>:	jmp    0x4010d2 <phase_5+112>
   ————————————————————————————————————————————————————————————————————————————————————
   0x000000000040108b <+41>:	movzbl (%rbx,%rax,1),%ecx              //rbx+rax的值移动到ecx,猜测rbx为我们输入字符串的开头
                                                                     //最后结果验证了我们的猜想,rdi就是一个输入字串首指针
                                                                     //movzbl——做了0扩展的字传送到双字
   0x000000000040108f <+45>:	mov    %cl,(%rsp)                      //rsp = cl(ecx)
   0x0000000000401092 <+48>:	mov    (%rsp),%rdx                     //rdx = rsp = cl
   0x0000000000401096 <+52>:	and    $0xf,%edx                       //edx = edx & 0xf 即取最小的四位
   0x0000000000401099 <+55>:	movzbl 0x4024b0(%rdx),%edx             //访问0x4024b0+rdx的地址,值传输到edx(字符数组)
   0x00000000004010a0 <+62>:	mov    %dl,0x10(%rsp,%rax,1)           //dl(edx) 移动到rsp+rax+0x10的地址
   0x00000000004010a4 <+66>:	add    $0x1,%rax                       //rax = rax+1(注意这里+1是指一个字节)
   0x00000000004010a8 <+70>:	cmp    $0x6,%rax
   0x00000000004010ac <+74>:	jne    0x40108b <phase_5+41>           //rax不等于6移动到0x40108b
   ————————————————————————————————————————————————————————————————————————————————————————
   0x00000000004010ae <+76>:	movb   $0x0,0x16(%rsp)                 //rax等于6则 0移动到rsp+0x16
   0x00000000004010b3 <+81>:	mov    $0x40245e,%esi                  //esi = 0x40245e的值:"flyers",作为第二个参数
   0x00000000004010b8 <+86>:	lea    0x10(%rsp),%rdi                 //rdi = rsp+0x10地址的值,作为第一个参数
   0x00000000004010bd <+91>:	callq  0x401338 <strings_not_equal>    //调用0x401338 <strings_not_equal>函数
   0x00000000004010c2 <+96>:	test   %eax,%eax
   0x00000000004010c4 <+98>:	je     0x4010d9 <phase_5+119>          //eax如果等于0跳转到0x4010d9,否则爆炸
   0x00000000004010c6 <+100>:	callq  0x40143a <explode_bomb>
   0x00000000004010cb <+105>:	nopl   0x0(%rax,%rax,1)                //气泡
   0x00000000004010d0 <+110>:	jmp    0x4010d9 <phase_5+119>          //跳转到0x4010d9
   0x00000000004010d2 <+112>:	mov    $0x0,%eax                       //eax = 0
   0x00000000004010d7 <+117>:	jmp    0x40108b <phase_5+41>           //跳转至0x40108b
   0x00000000004010d9 <+119>:	mov    0x18(%rsp),%rax                 //rsp+18的值移动到rax
   0x00000000004010de <+124>:	xor    %fs:0x28,%rax                   //rax = fs:0x28 ^ rax, 并设置控制码
   0x00000000004010e7 <+133>:	je     0x4010ee <phase_5+140>          //如果异或结果为0跳转至0x4010ee,结束函数
   0x00000000004010e9 <+135>:	callq  0x400b30 <__stack_chk_fail@plt>       //否则调用0x400b30函数(栈溢出)
   0x00000000004010ee <+140>:	add    $0x20,%rsp
   0x00000000004010f2 <+144>:	pop    %rbx
   0x00000000004010f3 <+145>:	retq

key:x/b访问0x4024b0数组,得到以下值,此值可视为字符数组,用edx的最后四位取对应值(如最后四位为0011取到u)

0x4024b0 <array.3449>:	"maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?"

key2:%fs:0x28金丝雀用法,保存后与之前异或,看是否有栈溢出,这里我们设限为rsp+0x18(实际上我们只能输入6个字符,只到0x16所以完全安全)

answer:flyers在语句中索引为—— 9(1001),15(1111),14(1110),5(0101),6(0110),7(0111) 随意从asc2表中寻找字符,找到一个组合:ionuvw

第五题实战

代码

   0x0000000000001428 <+0>:	push   %rbx
   0x0000000000001429 <+1>:	mov    %rdi,%rbx              // rbx = rdi
   0x000000000000142c <+4>:	callq  0x16a9 <string_length>
   0x0000000000001431 <+9>:	cmp    $0x6,%eax
   0x0000000000001434 <+12>:	jne    0x1467 <phase_5+63>    // 不相等跳转至+63爆炸,说明输入字串长度为6
   0x0000000000001436 <+14>:	mov    %rbx,%rax
   0x0000000000001439 <+17>:	lea    0x6(%rbx),%rdi         // rdi = rbx+6的值
   0x000000000000143d <+21>:	mov    $0x0,%ecx              // ecx = 0
   0x0000000000001442 <+26>:	lea    0x15d7(%rip),%rsi      // 0x2a20 <array.3417>
   0x0000000000001449 <+33>:	movzbl (%rax),%edx            // edx = rax的值,通过gdb调试知晓此即为我们输入的字符串akshdj
   0x000000000000144c <+36>:	and    $0xf,%edx              // edx = edx最后四位
   0x000000000000144f <+39>:	add    (%rsi,%rdx,4),%ecx     // ecx = ecx + rsi+ 4*edx(地址*4)
   0x0000000000001452 <+42>:	add    $0x1,%rax              // rax+=1
   0x0000000000001456 <+46>:	cmp    %rdi,%rax
   0x0000000000001459 <+49>:	jne    0x1449 <phase_5+33>    // rax!=rdi跳转至+33,gdb调试知晓rdi是尾指针,此处要循环6次
   0x000000000000145b <+51>:	cmp    $0x25,%ecx
   0x000000000000145e <+54>:	je     0x1465 <phase_5+61>    // ecx==37跳转至+61避免爆炸
   0x0000000000001460 <+56>:	callq  0x1956 <explode_bomb>
   0x0000000000001465 <+61>:	pop    %rbx
   0x0000000000001466 <+62>:	retq
   0x0000000000001467 <+63>:	callq  0x1956 <explode_bomb>
   0x000000000000146c <+68>:	jmp    0x1436 <phase_5+14>

answer:首先获取rsi处数组信息

0x555555556a20 <array.3417>:	0x0000000a 00000002	0x00000001 00000006
0x555555556a30 <array.3417+16>:	0x00000010  0000000c	0x00000003  00000009
0x555555556a40 <array.3417+32>:	0x00000007  00000004	0x00000005  0000000e
0x555555556a50 <array.3417+48>:	0x00000008  0000000b	0x0000000d  0000000f

对应array:[2,a,6,1,c,16,9,3,4,7,e,5,b,8,f,d]。 注:1个int型32位,64位机中中2个int放一行,其中小端编址所以后面的int实际为前面的值。 计算ecx的值时,取我们输入字符的最后四位(asc2码)索引数组的值,如a(0001)取到10,b(0010)取到6

知道此我们便可很容易地得到一组答案:5*6+7(bbbbbi)

第六题

代码:

   0x00000000004010f4 <+0>:	push   %r14
   0x00000000004010f6 <+2>:	push   %r13
   0x00000000004010f8 <+4>:	push   %r12
   0x00000000004010fa <+6>:	push   %rbp
   0x00000000004010fb <+7>:	push   %rbx
   0x00000000004010fc <+8>:	sub    $0x50,%rsp
   0x0000000000401100 <+12>:	mov    %rsp,%r13           //r13 = rsp
   0x0000000000401103 <+15>:	mov    %rsp,%rsi           //rsi = rsp
   0x0000000000401106 <+18>:	callq  0x40145c <read_six_numbers>     //调用读入6个数的函数
   0x000000000040110b <+23>:	mov    %rsp,%r14           //r14 = rsp
   0x000000000040110e <+26>:	mov    $0x0,%r12d          //r12d = 0
   ——————————————————————————————————————————————————————————————————————————————————————————
   0x0000000000401114 <+32>:	mov    %r13,%rbp           //rbp = r13 推断r13是一个链表的当前指针
   0x0000000000401117 <+35>:	mov    0x0(%r13),%eax      //eax = r13的值
   0x000000000040111b <+39>:	sub    $0x1,%eax           //eax -=1
   0x000000000040111e <+42>:	cmp    $0x5,%eax
   0x0000000000401121 <+45>:	jbe    0x401128 <phase_6+52>           //联系上下文,每个数都应该<=6
   0x0000000000401123 <+47>:	callq  0x40143a <explode_bomb>
   0x0000000000401128 <+52>:	add    $0x1,%r12d          //r12d +=1
   0x000000000040112c <+56>:	cmp    $0x6,%r12d
   0x0000000000401130 <+60>:	je     0x401153 <phase_6+95>        //r12d == 6跳转至 +95
   ————————————————————————————————————————————————————————————————————————————————————————
   0x0000000000401132 <+62>:	mov    %r12d,%ebx                   //否则ebx = r12d
   ————————————————————————————————————————————————————————————————————————————————————————
   0x0000000000401135 <+65>:	movslq %ebx,%rax                    //rax = ebx (符号扩展)
   0x0000000000401138 <+68>:	mov    (%rsp,%rax,4),%eax           //eax = rsp + rax*4,截断只有32位赋入
   0x000000000040113b <+71>:	cmp    %eax,0x0(%rbp)
   0x000000000040113e <+74>:	jne    0x401145 <phase_6+81>        //rbp == eax 则爆炸,联系上下文,知晓每个数都不应该相等
   0x0000000000401140 <+76>:	callq  0x40143a <explode_bomb>
   0x0000000000401145 <+81>:	add    $0x1,%ebx              //ebx +=1
   0x0000000000401148 <+84>:	cmp    $0x5,%ebx
   0x000000000040114b <+87>:	jle    0x401135 <phase_6+65>        //ebx<=5 则跳转至 +65(第二层循环头)
   ————————————————————————————————————————————————————————————————————————————————————————————
   0x000000000040114d <+89>:	add    $0x4,%r13                    //r13+=4
   0x0000000000401151 <+93>:	jmp    0x401114 <phase_6+32>        //跳转至0x+32(第一层循环头)
   0x0000000000401153 <+95>:	lea    0x18(%rsp),%rsi              //rsi = rsp+0x18,即数组末尾指针
   0x0000000000401158 <+100>:	mov    %r14,%rax                    //rax = r14,在此处rax的作用等效于数组指针
   0x000000000040115b <+103>:	mov    $0x7,%ecx                    //ecx = 7
   ————————————————————————————————————————————————————————————————————————————————————————————
   0x0000000000401160 <+108>:	mov    %ecx,%edx                    //edx = ecx = 7
   0x0000000000401162 <+110>:	sub    (%rax),%edx                  //edx -= rax的值
   0x0000000000401164 <+112>:	mov    %edx,(%rax)                  //rax的值 = edx,即当前位置值x = 7-x
   0x0000000000401166 <+114>:	add    $0x4,%rax                    //rax+=4
   0x000000000040116a <+118>:	cmp    %rsi,%rax
   0x000000000040116d <+121>:	jne    0x401160 <phase_6+108>       //rax != rsi 跳转至 +108
   ——————————————————————————————————————————————————————————————————————————————————————————————
   0x000000000040116f <+123>:	mov    $0x0,%esi                    //rax == rsi 则esi = 0
   0x0000000000401174 <+128>:	jmp    0x401197 <phase_6+163>       //跳转至 +163
   ————————————————————————————————————————————————————————————————————————————————————————————————
   0x0000000000401176 <+130>:	mov    0x8(%rdx),%rdx               //rdx + 8的值移至rdx
                                                                  //注意看下文的数组,rdx+8的内存值是一个新的地址
   0x000000000040117a <+134>:	add    $0x1,%eax                    //eax+=1
   0x000000000040117d <+137>:	cmp    %ecx,%eax
   0x000000000040117f <+139>:	jne    0x401176 <phase_6+130>       //eax != ecx 跳转至+130,回到链表内循环的开头
   0x0000000000401181 <+141>:	jmp    0x401188 <phase_6+148>       //eax == ecx 则跳转至+148,回到外层循环
   ————————————————————————————————————————————————————————————————————————————————————————————————
   0x0000000000401183 <+143>:	mov    $0x6032d0,%edx               //edx = $0x6032d0
   ——————————————————————————————————————————————————————————————————————————————————————————————————
   0x0000000000401188 <+148>:	mov    %rdx,0x20(%rsp,%rsi,2)       //rsp + rsi*2 + 0x20 = rdx
   0x000000000040118d <+153>:	add    $0x4,%rsi                    //rsi+=4(字节)
   0x0000000000401191 <+157>:	cmp    $0x18,%rsi
   0x0000000000401195 <+161>:	je     0x4011ab <phase_6+183>       //rsi == 0x18(24)跳转到+183
   0x0000000000401197 <+163>:	mov    (%rsp,%rsi,1),%ecx           //ecx = rsp+rsi的值,即依次为我们输入的数据
   0x000000000040119a <+166>:	cmp    $0x1,%ecx
   0x000000000040119d <+169>:	jle    0x401183 <phase_6+143>       //ecx <=1 则转至+143
   0x000000000040119f <+171>:	mov    $0x1,%eax                    //ecx >1 则 eax = 1
   0x00000000004011a4 <+176>:	mov    $0x6032d0,%edx               //edx = $0x6032d0
   0x00000000004011a9 <+181>:	jmp    0x401176 <phase_6+130>       //跳转至+130
   0x00000000004011ab <+183>:	mov    0x20(%rsp),%rbx              //rbx = rsp+0x20,这里rbx为之前覆盖后的数组开头指针
   0x00000000004011b0 <+188>:	lea    0x28(%rsp),%rax              //rax = rsp+0x28
   0x00000000004011b5 <+193>:	lea    0x50(%rsp),%rsi              //rsi = rsp + 0x50
   0x00000000004011ba <+198>:	mov    %rbx,%rcx                    //rcx = rbx
   ————————————————————————————————————————————————————————————————————————————————————————————————
   0x00000000004011bd <+201>:	mov    (%rax),%rdx                  //rdx = rax的值
   0x00000000004011c0 <+204>:	mov    %rdx,0x8(%rcx)               //rcx+0x8的值 = rdx, 这一小段的主要目的为把地址换成值
   0x00000000004011c4 <+208>:	add    $0x8,%rax                    //rax += 8
   0x00000000004011c8 <+212>:	cmp    %rsi,%rax
   0x00000000004011cb <+215>:	je     0x4011d2 <phase_6+222>       //rax == rsi 跳转至+222
   0x00000000004011cd <+217>:	mov    %rdx,%rcx                    //rcx = rdx
   0x00000000004011d0 <+220>:	jmp    0x4011bd <phase_6+201>       //跳转至+201
   ——————————————————————————————————————————————————————————————————————————————————————————————
   0x00000000004011d2 <+222>:	movq   $0x0,0x8(%rdx)               //rdx + 0x8 = 0
   0x00000000004011da <+230>:	mov    $0x5,%ebp                    //ebp = 5
   0x00000000004011df <+235>:	mov    0x8(%rbx),%rax               //rax = rbx+0x8的值,即当前指针的下一位
   0x00000000004011e3 <+239>:	mov    (%rax),%eax                  //eax = rax的值(32位截断)
   0x00000000004011e5 <+241>:	cmp    %eax,(%rbx)
   0x00000000004011e7 <+243>:	jge    0x4011ee <phase_6+250>       //rbx的值>= eax 则跳转至+250,否则爆炸
   0x00000000004011e9 <+245>:	callq  0x40143a <explode_bomb>      //所以推断出rbx指向的数组,每一位前面的都需要比后面的大
   ——————————————————————————————————————————————————————————————————————————————————————————————
   0x00000000004011ee <+250>:	mov    0x8(%rbx),%rbx               //rbx = rbx+0x8的值——数组指针后移
   0x00000000004011f2 <+254>:	sub    $0x1,%ebp
   0x00000000004011f5 <+257>:	jne    0x4011df <phase_6+235>       //ebp != 1则跳转至+235
   0x00000000004011f7 <+259>:	add    $0x50,%rsp
   0x00000000004011fb <+263>:	pop    %rbx
   0x00000000004011fc <+264>:	pop    %rbp
   0x00000000004011fd <+265>:	pop    %r12
   0x00000000004011ff <+267>:	pop    %r13
   0x0000000000401201 <+269>:	pop    %r14
   0x0000000000401203 <+271>:	retq

key: 开头是一个二层循环,让输入的六个数满足:每个数不相等且都小于等于6。之后一个一层循环,让当前位置值x = 7-x key2(s):mov %rdx,0x20(%rsp,%rsi,2) //rsp + rsi*2 + 0x20 = rdx,即rsp+0x20开始,按照之前输入的数写入0x6032d0之后的值。 我们使用x/12x 访问 0x6032d0,得到

//注意是大端编址,
0x6032d0 <node1>:	   0x4c	0x01	0x00	0x00	0x01	0x00	0x00	0x00
0x6032d8 <node1+8>:	0xe0	0x32	0x60	0x00	0x00	0x00	0x00	0x00
0x6032e0 <node2>:	   0xa8	0x00	0x00	0x00	0x02	0x00	0x00	0x00
0x6032e8 <node2+8>:	0xf0	0x32	0x60	0x00	0x00	0x00	0x00	0x00
0x6032f0 <node3>:	   0x9c	0x03	0x00	0x00	0x03	0x00	0x00	0x00
0x6032f8 <node3+8>:	0x00	0x33	0x60	0x00	0x00	0x00	0x00	0x00
0x603300 <node4>:	   0xb3	0x02	0x00	0x00	0x04	0x00	0x00	0x00
0x603308 <node4+8>:	0x10	0x33	0x60	0x00	0x00	0x00	0x00	0x00
0x603310 <node5>:	   0xdd	0x01	0x00	0x00	0x05	0x00	0x00	0x00
0x603318 <node5+8>:	0x20	0x33	0x60	0x00	0x00	0x00	0x00	0x00
0x603320 <node6>:	   0xbb	0x01	0x00	0x00	0x06	0x00	0x00	0x00
0x603328 <node6+8>:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x0

注意后文有32位截断,假设输入1 2 3 4 5 6即:rsp+0x20写入0x6032d0的值(0x0000014c),rsp+0x28写入0x6032e0的值(0x00000a8) rsp+0x30写入0x0000039c,rsp+0x38写入0x0000023b,rsp+0x40写入0x000001dd,rsp+0x48写入0x000001dd 如果输入2 1 …… 则rsp+0x20写入写入0x6032e0的值(0x00000a8), rsp+0x28写入0x6032d0的值(0x0000014c)

key3:最后一层循环,要求每一个前面的值比后面的值大,否则爆炸

answer: 综合key123,我们对数值进行排序,得到(3) 39c  (4) 2b3  (5) 1dd  (6) 1bb  (1) 14c  (2) a8 所以最终输入应为 4 3 2 1 6 5

第六题实战

代码

   0x000055555555546e <+0>:	push   %r13
   0x0000555555555470 <+2>:	push   %r12
   0x0000555555555472 <+4>:	push   %rbp
   0x0000555555555473 <+5>:	push   %rbx
   0x0000555555555474 <+6>:	sub    $0x68,%rsp
   0x0000555555555478 <+10>:	mov    %fs:0x28,%rax
   0x0000555555555481 <+19>:	mov    %rax,0x58(%rsp)     // rsp+0x58存储金丝雀值
   0x0000555555555486 <+24>:	xor    %eax,%eax           // eax = 0
   0x0000555555555488 <+26>:	mov    %rsp,%r12           // r12 = rsp
   0x000055555555548b <+29>:	mov    %r12,%rsi           // rsi = rsp
   0x000055555555548e <+32>:	callq  0x555555555992 <read_six_numbers>
   0x0000555555555493 <+37>:	mov    $0x0,%r13d          // r13d = 0
   0x0000555555555499 <+43>:	jmp    0x5555555554c0 <phase_6+82>     //跳转至+82
   0x000055555555549b <+45>:	callq  0x555555555956 <explode_bomb>
   0x00005555555554a0 <+50>:	jmp    0x5555555554cf <phase_6+97>
   0x00005555555554a2 <+52>:	add    $0x1,%ebx
   0x00005555555554a5 <+55>:	cmp    $0x5,%ebx
   0x00005555555554a8 <+58>:	jg     0x5555555554bc <phase_6+78>
   0x00005555555554aa <+60>:	movslq %ebx,%rax           // rax = ebx
   0x00005555555554ad <+63>:	mov    (%rsp,%rax,4),%eax  // eax = rsp + 4*rax即我们依次输入的数
   0x00005555555554b0 <+66>:	cmp    %eax,0x0(%rbp)
   0x00005555555554b3 <+69>:	jne    0x5555555554a2 <phase_6+52>     // eax != rbp的值跳转至+52
                                                                     // rbp是当前数指针
                                                                     // 所以每个数都不相同
   0x00005555555554b5 <+71>:	callq  0x555555555956 <explode_bomb>
   0x00005555555554ba <+76>:	jmp    0x5555555554a2 <phase_6+52>
   0x00005555555554bc <+78>:	add    $0x4,%r12
   0x00005555555554c0 <+82>:	mov    %r12,%rbp           // rbp = r12
   0x00005555555554c3 <+85>:	mov    (%r12),%eax         // eax = r12的值
   0x00005555555554c7 <+89>:	sub    $0x1,%eax           // eax -= 1
   0x00005555555554ca <+92>:	cmp    $0x5,%eax
   0x00005555555554cd <+95>:	ja     0x55555555549b <phase_6+45>  // eax>5跳转至+45爆炸
                                                                  // 说明每个输入数都<=6
   0x00005555555554cf <+97>:	add    $0x1,%r13d                   // r13d += 1
   0x00005555555554d3 <+101>:	cmp    $0x6,%r13d
   0x00005555555554d7 <+105>:	je     0x55555555550e <phase_6+160> // r13d==6跳转至+160跳出循环
   0x00005555555554d9 <+107>:	mov    %r13d,%ebx                   // ebx = r13d
   0x00005555555554dc <+110>:	jmp    0x5555555554aa <phase_6+60>  // 跳转至+60
   ——————————————————————————————————————————————————————————————————————————————————————
   0x00005555555554de <+112>:	mov    0x8(%rdx),%rdx               // rdx = rdx+8的值
   0x00005555555554e2 <+116>:	add    $0x1,%eax                    // eax +=1
   0x00005555555554e5 <+119>:	cmp    %ecx,%eax
   0x00005555555554e7 <+121>:	jne    0x5555555554de <phase_6+112> // eax!= ecx跳转至+112
   0x00005555555554e9 <+123>:	mov    %rdx,0x20(%rsp,%rsi,8)       // rsp + rsi*8 + 0x20写入rdx
   0x00005555555554ee <+128>:	add    $0x1,%rsi                    // rsi+=1
   0x00005555555554f2 <+132>:	cmp    $0x6,%rsi
   0x00005555555554f6 <+136>:	je     0x555555555515 <phase_6+167> // rsi==6跳转至+167退出循环
   0x00005555555554f8 <+138>:	mov    (%rsp,%rsi,4),%ecx        // ecx = rsp+4*rsi
   0x00005555555554fb <+141>:	mov    $0x1,%eax                 // eax = 1
   0x0000555555555500 <+146>:	lea    0x202d29(%rip),%rdx       // 0x555555758230 <node1>
   0x0000555555555507 <+153>:	cmp    $0x1,%ecx
   0x000055555555550a <+156>:	jg     0x5555555554de <phase_6+112> // ecx>1跳转至+112
   0x000055555555550c <+158>:	jmp    0x5555555554e9 <phase_6+123> // 否则跳转至+123
   0x000055555555550e <+160>:	mov    $0x0,%esi                 // esi = 0
   0x0000555555555513 <+165>:	jmp    0x5555555554f8 <phase_6+138>    // 跳转至+138
——————————————————————————————————————————————————————————————————————————————————————
   0x0000555555555515 <+167>:	mov    0x20(%rsp),%rbx        // rbx = rsp+0x20的值
   0x000055555555551a <+172>:	mov    0x28(%rsp),%rax        // rax = rsp+0x28的值
   0x000055555555551f <+177>:	mov    %rax,0x8(%rbx)         // rbx+8的值 = rax
   0x0000555555555523 <+181>:	mov    0x30(%rsp),%rdx        // rdx = rsp+0x30的值
   0x0000555555555528 <+186>:	mov    %rdx,0x8(%rax)         // rax+8的值 = rdx
   0x000055555555552c <+190>:	mov    0x38(%rsp),%rax        // rax = rsp+0x38的值
   0x0000555555555531 <+195>:	mov    %rax,0x8(%rdx)         // rdx+8的值 = rax
   0x0000555555555535 <+199>:	mov    0x40(%rsp),%rdx        // rdx = rsp+0x40的值
   0x000055555555553a <+204>:	mov    %rdx,0x8(%rax)         // rax+8的值 = rdx
   0x000055555555553e <+208>:	mov    0x48(%rsp),%rax        // rax = rsp+0x48的值
   0x0000555555555543 <+213>:	mov    %rax,0x8(%rdx)         // rdx+8的值 = rax
   0x0000555555555547 <+217>:	movq   $0x0,0x8(%rax)         // rax+8的值 = 0
   0x000055555555554f <+225>:	mov    $0x5,%ebp              // ebp = 5
   0x0000555555555554 <+230>:	jmp    0x55555555555f <phase_6+241>    // 跳转至+241
   0x0000555555555556 <+232>:	mov    0x8(%rbx),%rbx                  // rbx = rbx+8的值
   0x000055555555555a <+236>:	sub    $0x1,%ebp                       // ebp -= 1
   0x000055555555555d <+239>:	je     0x555555555570 <phase_6+258>    // ebp == 0 则退出
   0x000055555555555f <+241>:	mov    0x8(%rbx),%rax                  // rax = rbx+8的值
   0x0000555555555563 <+245>:	mov    (%rax),%eax                     // eax = rax的值
   0x0000555555555565 <+247>:	cmp    %eax,(%rbx)
   0x0000555555555567 <+249>:	jge    0x555555555556 <phase_6+232>    // rbx的值>eax跳转至+232
   0x0000555555555569 <+251>:	callq  0x555555555956 <explode_bomb>   // 否则爆炸
   0x000055555555556e <+256>:	jmp    0x555555555556 <phase_6+232>
   0x0000555555555570 <+258>:	mov    0x58(%rsp),%rax
   0x0000555555555575 <+263>:	xor    %fs:0x28,%rax
   0x000055555555557e <+272>:	jne    0x55555555558b <phase_6+285>
   0x0000555555555580 <+274>:	add    $0x68,%rsp
   0x0000555555555584 <+278>:	pop    %rbx
   0x0000555555555585 <+279>:	pop    %rbp
   0x0000555555555586 <+280>:	pop    %r12
   0x0000555555555588 <+282>:	pop    %r13
   0x000055555555558a <+284>:	retq
   0x000055555555558b <+285>:	callq  0x555555554e50 <__stack_chk_fail@plt>

key1:输入6个0~6的数,每个数不相同 key2: mov %rdx,0x20(%rsp,%rsi,8) 即rdx的值有选择地依次赋到rsp+20开始的6个数(如题目六所示) 假设输入1 2 ……即:rsp+0x20写入0x58230的值(0x0000034c),rsp+0x28写入0x58240的值(0x000001f5) 6个数分别为0x034c(第2大), 0x01f5(第5大), 0x03c8(第1大), 0x0343(第3大), 0x022f(第4大), 不存在(注意后面会赋值为0) rdx的值如下:

0x555555758230 <node1>:	0x4c	0x03	0x00	0x00	0x01	0x00	0x00	0x00
0x555555758238 <node1+8>:	0x40	0x82	0x75	0x55	0x55	0x55	0x00	0x00
0x555555758240 <node2>:	0xf5	0x01	0x00	0x00	0x02	0x00	0x00	0x00
0x555555758248 <node2+8>:	0x50	0x82	0x75	0x55	0x55	0x55	0x00	0x00
0x555555758250 <node3>:	0xc8	0x03	0x00	0x00	0x03	0x00	0x00	0x00
0x555555758258 <node3+8>:	0x60	0x82	0x75	0x55	0x55	0x55	0x00	0x00
0x555555758260 <node4>:	0x43	0x03	0x00	0x00	0x04	0x00	0x00	0x00
0x555555758268 <node4+8>:	0x70	0x82	0x75	0x55	0x55	0x55	0x00	0x00
0x555555758270 <node5>:	0x2f	0x02	0x00	0x00	0x05	0x00	0x00	0x00
0x555555758278 <node5+8>:	0x10	0x81	0x75	0x55	0x55	0x55	0x00	0x00

key3:只有5个node,最后一个赋0 key4:最后一层循环,要求每一个前面的值比后面的值大,否则爆炸。

answer: 3 1 4 5 2 6

结果合集

Border relations with Canada have never been better.
1 2 4 8 16 32
0 207
7 0
ionuvw
4 3 2 1 6 5

实战结果集合

I am not part of the problem. I am a Republican.
0 1 1 2 3 5
0 271
6 6
bbbbbi
3 1 4 5 2 6