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
————————————————————————————————————————————————————————————————————一个switch表
0x0000555555555339 <+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