实验概述:该实验就是通过分析汇编代码,并使用GDB调试,找到每一题的通关钥匙
第一关:(key=“He is evil and fits easily into most overhead storage bins.”)
简单解析:比较简单,字符串比较问题,找到比较地址中存储的字符串即可。
(1)分析:
(2)运行:
第二关:(key=1 2 4 8 16 32)
简单解析:循环输入六个值问题,按循环条件观察变化即可。
(1)分析:
(2)运行:
第三关:(key=0,276)
简单解析:switch跳转问题,按部就班,比较简单。
(1)分析:
08048c02 <phase_3>:
8048c02: 83 ec 2c sub $0x2c,%esp//开辟栈帧
8048c05: 8d 44 24 1c lea 0x1c(%esp),%eax
8048c09: 89 44 24 0c mov %eax,0xc(%esp)
8048c0d: 8d 44 24 18 lea 0x18(%esp),%eax
8048c11: 89 44 24 08 mov %eax,0x8(%esp)
8048c15: c7 44 24 04 17 a3 04 movl $0x804a317,0x4(%esp)//查看该地址中的内容
说明应该输入两个数字
8048c1c: 08
8048c1d: 8b 44 24 30 mov 0x30(%esp),%eax
8048c21: 89 04 24 mov %eax,(%esp)
8048c24: e8 37 fc ff ff call 8048860 <__isoc99_sscanf@plt>//调用函数
8048c29: 83 f8 01 cmp $0x1,%eax //
8048c2c: 7f 05 jg 8048c33 <phase_3+0x31>//输入参数个数大于1个
8048c2e:e8 22 05 00 00 call 8049155 <explode_bomb>
8048c33: 83 7c 24 18 07 cmpl $0x7,0x18(%esp)//第一个参数值<=7,否则跳转到炸弹处(可以输入0 1 2 3 4 5 6 7)
8048c38: 77 66 ja 8048ca0 <phase_3+0x9e>//无符号数比较
8048c3a: 8b 44 24 18 mov 0x18(%esp),%eax
8048c3e: ff 24 85 d8 a1 04 08 jmp *0x804a1d8(,%eax,4)//跳转到以*0x804a1d8为基址的跳转表中,如果此时第一个输入数为0,由此看出跳转到0x8048c4c地址
8048c45: b8 00 00 00 00 mov $0x0,%eax
8048c4a: eb 05 jmp 8048c51 <phase_3+0x4f>
8048c4c: b8 33 03 00 00 mov $0x333,%eax//第一个输入数为0就跳转到了这里
8048c51: 2d ea 00 00 00 sub $0xea,%eax //eax=0x333-0xea继续跳转
8048c56: eb 05 jmp 8048c5d <phase_3+0x5b>
8048c58: b8 00 00 00 00 mov $0x0,%eax
8048c5d: 05 0f 02 00 00 add $0x20f,%eax //eax=0x333-0xea+0x20f
8048c62: eb 05 jmp 8048c69 <phase_3+0x67>
8048c64: b8 00 00 00 00 mov $0x0,%eax
8048c69: 2d 44 03 00 00 sub $0x344,%eax //eax=0x333-0xea+0x20f-0x344
8048c6e: eb 05 jmp 8048c75 <phase_3+0x73>
8048c70: b8 00 00 00 00 mov $0x0,%eax
8048c75: 05 44 03 00 00 add $0x344,%eax //eax=0x333-0xea+0x20f-0x344+0x344
8048c7a: eb 05 jmp 8048c81 <phase_3+0x7f>
8048c7c: b8 00 00 00 00 mov $0x0,%eax
8048c81: 2d 44 03 00 00 sub $0x344,%eax //eax=0x333-0xea+0x20f-0x344+0x344-0x344
8048c86: eb 05 jmp 8048c8d <phase_3+0x8b>
8048c88: b8 00 00 00 00 mov $0x0,%eax
8048c8d: 05 44 03 00 00 add $0x344,%eax //eax=0x333-0xea+0x20f-0x344+0x344-0x344+0x344
8048c92: eb 05 jmp 8048c99 <phase_3+0x97>
8048c94: b8 00 00 00 00 mov $0x0,%eax
8048c99: 2d 44 03 00 00 sub $0x344,%eax //eax=0x333-0xea+0x20f-0x344+0x344-0x344+0x344-0x344
8048c9e: eb 0a jmp 8048caa <phase_3+0xa8>
8048ca0: e8 b0 04 00 00 call 8049155 <explode_bomb>
8048ca5: b8 00 00 00 00 mov $0x0,%eax
8048caa: 83 7c 24 18 05 cmpl $0x5,0x18(%esp) //说明第一个输入数小于等于5
8048caf: 7f 06 jg 8048cb7 <phase_3+0xb5>
8048cb1: 3b 44 24 1c cmp 0x1c(%esp),%eax //第二个输入数就是输入第一个数后 跳转完毕的结果
8048cb5: 74 05 je 8048cbc <phase_3+0xba>
8048cb7: e8 99 04 00 00 call 8049155 <explode_bomb>
8048cbc: 83 c4 2c add $0x2c,%esp
8048cbf: 90 nop
8048cc0: c3 ret
(2)运行:
(3)总结:
综上可知,第一个数的输入限制为:小于等于5,又因为经过排查,当第一个
数为0,3,才可以找到在跳转表中的地址。又因为当第一个数为3时,最终结果
为-309,不符合开头时要求无符号数的要求,所以Password为:(0,276)。
跳转示意:
第四关:(key=0,11或1,11)
简单解析:递归和二分问题,注意递归和二分条件和递归的返回值,还要注意递归的结束条件。
08048d1e <phase_4>:
8048d1e: 83 ec 2c sub $0x2c,%esp
8048d21: 8d 44 24 1c lea 0x1c(%esp),%eax
8048d25: 89 44 24 0c mov %eax,0xc(%esp)
8048d29: 8d 44 24 18 lea 0x18(%esp),%eax
8048d2d: 89 44 24 08 mov %eax,0x8(%esp)
8048d31: c7 44 24 04 17 a3 04 movl $0x804a317,0x4(%esp) //要求输入两个数
8048d38: 08
8048d39: 8b 44 24 30 mov 0x30(%esp),%eax
8048d3d: 89 04 24 mov %eax,(%esp)
8048d40: e8 1b fb ff ff call 8048860 <__isoc99_sscanf@plt>//调用函数
8048d45: 83 f8 02 cmp $0x2,%eax //说明输入个数为2,否则会爆炸
8048d48: 75 07 jne 8048d51 <phase_4+0x33>
8048d4a: 83 7c 24 18 0e cmpl $0xe,0x18(%esp)
8048d4f: 76 05 jbe 8048d56 <phase_4+0x38>//小于等于就跳转,否则爆炸,说明
第一个输入数<=14
8048d51: e8 ff 03 00 00 call 8049155 <explode_bomb>
8048d56: c7 44 24 08 0e 00 00 movl $0xe,0x8(%esp)
8048d5d: 00
8048d5e: c7 44 24 04 00 00 00 movl $0x0,0x4(%esp)
8048d65: 00
8048d66: 8b 44 24 18 mov 0x18(%esp),%eax
8048d6a: 89 04 24 mov %eax,(%esp)// 将第一个输入数作为参数传入并调用func4
8048d6d: e8 4f ff ff ff call 8048cc1 <func4>// 此时将目光转到func4
8048d72: 83 f8 0b cmp $0xb,%eax // func4()应该返回值为11,根据func(x)=11,推出x
即可
8048d75: 75 07 jne 8048d7e <phase_4+0x60>
8048d77: 83 7c 24 1c 0b cmpl $0xb,0x1c(%esp) //第二个输入数一定为11
8048d7c: 74 05 je 8048d83 <phase_4+0x65>
8048d7e: e8 d2 03 00 00 call 8049155 <explode_bomb>
8048d83: 83 c4 2c add $0x2c,%esp
8048d86: c3 ret
//接下来查看func4函数的功能
08048cc1 <func4>:
8048cc1: 56 push %esi
8048cc2: 53 push %ebx
8048cc3: 83 ec 14 sub $0x14,%esp
8048cc6: 8b 54 24 20 mov 0x20(%esp),%edx //传入参数
8048cca: 8b 44 24 24 mov 0x24(%esp),%eax //e
8048cce: 8b 74 24 28 mov 0x28(%esp),%esi //0
8048cd2: 89 f1 mov %esi,%ecx
8048cd4: 29 c1 sub %eax,%ecx
8048cd6: 89 cb mov %ecx,%ebx
8048cd8: c1 eb 1f shr $0x1f,%ebx //逻辑右移31位
8048cdb: 01 d9 add %ebx,%ecx
8048cdd: d1 f9 sar %ecx//对于二分的右边界值,算数右移一位,就是除以2
8048cdf: 8d 1c 01 lea (%ecx,%eax,1),%ebx
8048ce2: 39 d3 cmp %edx,%ebx//比较右边界值和参数的大小
8048ce4: 7e 17 jle 8048cfd <func4+0x3c>
8048ce6: 8d 4b ff lea -0x1(%ebx),%ecx //大于参数时就对该边界值-1,继续进行递归二分
8048ce9: 89 4c 24 08 mov %ecx,0x8(%esp)
8048ced: 89 44 24 04 mov %eax,0x4(%esp)
8048cf1: 89 14 24 mov %edx,(%esp)
8048cf4: e8 c8 ff ff ff call 8048cc1 <func4>
8048cf9: 01 d8 add %ebx,%eax//将之前二分的值累加到eax作为返回结果
8048cfb: eb 1b jmp 8048d18 <func4+0x57>
8048cfd: 89 d8 mov %ebx,%eax
8048cff: 39 d3 cmp %edx,%ebx
8048d01: 7d 15 jge 8048d18 <func4+0x57>
8048d03: 89 74 24 08 mov %esi,0x8(%esp)
8048d07: 8d 43 01 lea 0x1(%ebx),%eax//等于传入参数就退出递归返回值
大于参数时就对该边界值+1,继续进行递归二分
8048d0a: 89 44 24 04 mov %eax,0x4(%esp)
8048d0e: 89 14 24 mov %edx,(%esp)
8048d11: e8 ab ff ff ff call 8048cc1 <func4>
8048d16: 01 d8 add %ebx,%eax
8048d18: 83 c4 14 add $0x14,%esp
8048d1b: 5b pop %ebx
8048d1c: 5e pop %esi
8048d1d: c3 ret
综上:func4()的功能就是递归二分,并将每次二分中间值保留累加,作为返回值,直到二分中间值=传入参数。示意:
(2)运行结果:
第五关:(key=mfcdhg)
简单解析:利用输入字符ASCII码低四位作为偏置,去某个地址查找对应字符,以便组成所需字符串,注意小端法存储问题。
- 分析:
08048d87 <phase_5>:
8048d87: 53 push %ebx
8048d88: 83 ec 28 sub $0x28,%esp
8048d8b: 8b 5c 24 30 mov 0x30(%esp),%ebx
8048d8f: 65 a1 14 00 00 00 mov %gs:0x14,%eax
8048d95: 89 44 24 1c mov %eax,0x1c(%esp)
8048d99: 31 c0 xor %eax,%eax//清零
8048d9b: 89 1c 24 mov %ebx,(%esp)
8048d9e: e8 88 02 00 00 call 804902b <string_length>
8048da3: 83 f8 06 cmp $0x6,%eax // 要求输入一个长度为6的字符串
8048da6: 74 4a je 8048df2 <phase_5+0x6b>//满足条件就跳转
8048da8: e8 a8 03 00 00 call 8049155 <explode_bomb>
8048dad: 8d 76 00 lea 0x0(%esi),%esi
8048db0: eb 40 jmp 8048df2 <phase_5+0x6b>
8048db2: 0f b6 14 03 movzbl (%ebx,%eax,1),%edx //从这儿开始一个小循环
8048db6: 83 e2 0f and $0xf,%edx
8048db9: 0f b6 92 f8 a1 04 08 movzbl 0x804a1f8(%edx),%edx
//保存输入字符的低八位,并将低四位作为偏置,查找基址0x804a1f8中保存的对应字符,组合拼装成目的字符串“bruins”即可。
由此看出,其中存的字符为:maduiersnfotvbyl
对应偏置为:0 1 2 3 4 5 6 7 8 9 a b c d e f
8048dc0: 88 54 04 15 mov %dl,0x15(%esp,%eax,1)
8048dc4: 83 c0 01 add $0x1,%eax //加1
8048dc7: 83 f8 06 cmp $0x6,%eax//意思是处理完六个字符,保存完毕偏置就退出循环
8048dca: 75 e6 jne 8048db2 <phase_5+0x2b>
8048dcc: c6 44 24 1b 00 movb $0x0,0x1b(%esp)
8048dd1: c7 44 24 04 ce a1 04 movl $0x804a1ce,0x4(%esp)//查看内容
所以目的字符串为:bruins
因此可知:需要的偏置为:d 6 3 4 8 7,又因为我们要输入长度为6的字符串,且取该字符串中的低四位为偏置,因此根据下表可以得知,输入应该为:m、f、c、d、h、g(其中一种情况)
8048dd8: 08
8048dd9: 8d 44 24 15 lea 0x15(%esp),%eax
8048ddd: 89 04 24 mov %eax,(%esp)
8048de0: e8 65 02 00 00 call 804904a <strings_not_equal>
8048de5: 85 c0 test %eax,%eax //
8048de7: 74 10 je 8048df9 <phase_5+0x72>
8048de9: e8 67 03 00 00 call 8049155 <explode_bomb>
8048dee: 66 90 xchg %ax,%ax
8048df0: eb 07 jmp 8048df9 <phase_5+0x72>
8048df2: b8 00 00 00 00 mov $0x0,%eax //跳转到这儿并赋初值0给eax
8048df7: eb b9 jmp 8048db2 <phase_5+0x2b>//再跳转回去
8048df9: 8b 44 24 1c mov 0x1c(%esp),%eax
8048dfd: 65 33 05 14 00 00 00 xor %gs:0x14,%eax
8048e04: 74 05 je 8048e0b <phase_5+0x84>
8048e06: e8 b5 f9 ff ff call 80487c0 <__stack_chk_fail@plt>
8048e0b: 83 c4 28 add $0x28,%esp
8048e0e: 5b pop %ebx
8048e0f: 90 nop
8048e10: c3 ret
2.运行结果:
第六关(链表):
简单解析:有六个节点,每个节点中存储一个值,把结点1-6按顺序输入,保证其中结点的值按要求顺序排列即可。
(1)分析:
08048e11 <phase_6>:
8048e11: 56 push %esi
8048e12: 53 push %ebx
8048e13: 83 ec 44 sub $0x44,%esp
8048e16: 8d 44 24 10 lea 0x10(%esp),%eax
8048e1a: 89 44 24 04 mov %eax,0x4(%esp)
8048e1e: 8b 44 24 50 mov 0x50(%esp),%eax
8048e22: 89 04 24 mov %eax,(%esp)
8048e25: e8 52 03 00 00 call 804917c <read_six_numbers>//输入6个数字
8048e2a: be 00 00 00 00 mov $0x0,%esi
8048e2f: 8b 44 b4 10 mov 0x10(%esp,%esi,4),%eax
8048e33: 83 e8 01 sub $0x1,%eax
8048e36: 83 f8 05 cmp $0x5,%eax
8048e39: 76 05 jbe 8048e40 <phase_6+0x2f>//输入数字为无符号数
且<=6.可知输入数字必然为1-6,顺序未知
8048e3b: e8 15 03 00 00 call 8049155 <explode_bomb>
8048e40: 83 c6 01 add $0x1,%esi
8048e43: 83 fe 06 cmp $0x6,%esi
8048e46: 75 07 jne 8048e4f <phase_6+0x3e>
8048e48: bb 00 00 00 00 mov $0x0,%ebx
8048e4d: eb 38 jmp 8048e87 <phase_6+0x76>
8048e4f: 89 f3 mov %esi,%ebx
8048e51: 8b 44 9c 10 mov 0x10(%esp,%ebx,4),%eax
8048e55: 39 44 b4 0c cmp %eax,0xc(%esp,%esi,4)
8048e59: 75 05 jne 8048e60 <phase_6+0x4f>
8048e5b: e8 f5 02 00 00 call 8049155 <explode_bomb>
8048e60: 83 c3 01 add $0x1,%ebx
8048e63: 83 fb 05 cmp $0x5,%ebx
8048e66: 7e e9 jle 8048e51 <phase_6+0x40>
8048e68: eb c5 jmp 8048e2f <phase_6+0x1e>
//到这儿,其实以上操作用了双层for说明不能有重复数字出现,因此可知输入数字一定为1,2,3,4,5,6,顺序未知,因此接下来讨论顺序问题
8048e6a: 8b 52 08 mov 0x8(%edx),%edx
8048e6d: 83 c0 01 add $0x1,%eax
8048e70: 39 c8 cmp %ecx,%eax
8048e72: 75 f6 jne 8048e6a <phase_6+0x59>
8048e74: eb 05 jmp 8048e7b <phase_6+0x6a>
8048e76: ba 3c c1 04 08 mov $0x804c13c,%edx
8048e7b: 89 54 b4 28 mov %edx,0x28(%esp,%esi,4)
8048e7f: 83 c3 01 add $0x1,%ebx
8048e82: 83 fb 06 cmp $0x6,%ebx
8048e85: 74 17 je 8048e9e <phase_6+0x8d>
8048e87: 89 de mov %ebx,%esi
8048e89: 8b 4c 9c 10 mov 0x10(%esp,%ebx,4),%ecx
8048e8d: 83 f9 01 cmp $0x1,%ecx
8048e90: 7e e4 jle 8048e76 <phase_6+0x65>
8048e92: b8 01 00 00 00 mov $0x1,%eax
8048e97: ba 3c c1 04 08 mov $0x804c13c,%edx //以0x804c13c为基址进行
后续操作
8048e9c: eb cc jmp 8048e6a <phase_6+0x59>
8048e9e: 8b 5c 24 28 mov 0x28(%esp),%ebx
8048ea2: 8d 44 24 2c lea 0x2c(%esp),%eax
8048ea6: 8d 74 24 40 lea 0x40(%esp),%esi
8048eaa: 89 d9 mov %ebx,%ecx
8048eac: 8b 10 mov (%eax),%edx
8048eae: 89 51 08 mov %edx,0x8(%ecx)
8048eb1: 83 c0 04 add $0x4,%eax
8048eb4: 39 f0 cmp %esi,%eax
8048eb6: 74 04 je 8048ebc <phase_6+0xab>
8048eb8: 89 d1 mov %edx,%ecx
8048eba: eb f0 jmp 8048eac <phase_6+0x9b>
8048ebc: c7 42 08 00 00 00 00 movl $0x0,0x8(%edx)
8048ec3: be 05 00 00 00 mov $0x5,%esi
8048ec8: 8b 43 08 mov 0x8(%ebx),%eax//
8048ecb: 8b 00 mov (%eax),%eax
8048ecd: 39 03 cmp %eax,(%ebx)
8048ecf: 7d 05 jge 8048ed6 <phase_6+0xc5>//说明后一个数得<=
前一个数,就是说,根据我们输入的序列,对应的偏移地址中存储的值应该从大到小排列
8048ed1: e8 7f 02 00 00 call 8049155 <explode_bomb>
8048ed6: 8b 5b 08 mov 0x8(%ebx),%ebx
8048ed9: 83 ee 01 sub $0x1,%esi
8048edc: 75 ea jne 8048ec8 <phase_6+0xb7>//全部判断完毕就退出
8048ede: 83 c4 44 add $0x44,%esp
8048ee1: 5b pop %ebx
8048ee2: 5e pop %esi
8048ee3: c3 ret
总结:
(2)运行示意:
隐藏关(树):
(1)寻找入口:
080492c6 <phase_defused>:
80492c6: 81 ec 8c 00 00 00 sub $0x8c,%esp
80492cc: 65 a1 14 00 00 00 mov %gs:0x14,%eax
80492d2: 89 44 24 7c mov %eax,0x7c(%esp)
80492d6: 31 c0 xor %eax,%eax
80492d8: 83 3d c8 c3 04 08 06 cmpl $0x6,0x804c3c8//如果前六关过了,就进入,否
则直接结束
80492df: 75 72 jne 8049353 <phase_defused+0x8d>
80492e1: 8d 44 24 2c lea 0x2c(%esp),%eax
80492e5: 89 44 24 10 mov %eax,0x10(%esp)
80492e9: 8d 44 24 28 lea 0x28(%esp),%eax
80492ed: 89 44 24 0c mov %eax,0xc(%esp)
80492f1: 8d 44 24 24 lea 0x24(%esp),%eax
80492f5: 89 44 24 08 mov %eax,0x8(%esp)
80492f9: c7 44 24 04 71 a3 04 movl $0x804a371,0x4(%esp)//查询该地址:
说明此时输入两个数字,一个字符串,继续向下看
8049300: 08
8049301: c7 04 24 d0 c4 04 08 movl $0x804c4d0,(%esp)
8049308: e8 53 f5 ff ff call 8048860 <__isoc99_sscanf@plt>//发现第四关中,
同样调用了该函数,因此可知,第四关中输入两个数字后,还得输入一个字符串
804930d: 83 f8 03 cmp $0x3,%eax
8049310: 75 35 jne 8049347 <phase_defused+0x81>
8049312: c7 44 24 04 7a a3 04 movl $0x804a37a,0x4(%esp)
//查看该地址中的内容:,找到入场券:“DrEvil”
8049319: 08
804931a: 8d 44 24 2c lea 0x2c(%esp),%eax
804931e: 89 04 24 mov %eax,(%esp)
8049321: e8 24 fd ff ff call 804904a <strings_not_equal>
8049326: 85 c0 est %eax,%eax
8049328: 75 1d jne 8049347 <phase_defused+0x81>
804932a: c7 04 24 40 a2 04 08 movl $0x804a240,(%esp)
8049331: e8 ba f4 ff ff call 80487f0 <puts@plt>
8049336: c7 04 24 68 a2 04 08 movl $0x804a268,(%esp)
804933d: e8 ae f4 ff ff call 80487f0 <puts@plt>
8049342: e8 ee fb ff ff call 8048f35 <secret_phase>//这里显示进入秘密关卡
8049347: c7 04 24 a0 a2 04 08 movl $0x804a2a0,(%esp)
804934e: e8 9d f4 ff ff call 80487f0 <puts@plt>
8049353: 8b 44 24 7c mov 0x7c(%esp),%eax
8049357: 65 33 05 14 00 00 00 xor %gs:0x14,%eax
804935e: 74 05 je 8049365 <phase_defused+0x9f>
8049360: e8 5b f4 ff ff call 80487c0 <__stack_chk_fail@plt>
8049365: 81 c4 8c 00 00 00 add $0x8c,%esp
804936b: c3 ret
804936c: 66 90 xchg %ax,%ax
804936e: 66 90 xchg %ax,%ax
成功进入秘密关卡:(入场券“DrEvil”)
(2)解秘密关:
08048f35 <secret_phase>:
8048f35: 53 push %ebx
8048f36: 83 ec 18 sub $0x18,%esp
8048f39: e8 8e 02 00 00 call 80491cc <read_line>//读入一行
8048f3e: c7 44 24 08 0a 00 00 movl $0xa,0x8(%esp)
8048f45: 00
8048f46: c7 44 24 04 00 00 00 movl $0x0,0x4(%esp)
8048f4d: 00
8048f4e: 89 04 24 mov %eax,(%esp)//返回值作为参数之一
8048f51: e8 7a f9 ff ff call 80488d0 <strtol@plt>
8048f56: 89 c3 mov %eax,%ebx
8048f58: 8d 40 ff lea -0x1(%eax),%eax
8048f5b: 3d e8 03 00 00 cmp $0x3e8,%eax//0x3e8=1000
8048f60: 76 05 jbe 8048f67 <secret_phase+0x32>//以上语句说明输入一个十进制数且<=1000
8048f62: e8 ee 01 00 00 call 8049155 <explode_bomb>
8048f67: 89 5c 24 04 mov %ebx,0x4(%esp)
8048f6b: c7 04 24 88 c0 04 08 movl $0x804c088,(%esp)//将输入数传入作为参数之一,另外一个为 0x24=36
8048f72: e8 6d ff ff ff call 8048ee4 <fun7>//将目光转到fun7
8048f77: 83 f8 02 cmp $0x2,%eax//函数返回值应该是2
8048f7a: 74 05 je 8048f81 <secret_phase+0x4c>
8048f7c: e8 d4 01 00 00 call 8049155 <explode_bomb>
8048f81: c7 04 24 a8 a1 04 08 movl $0x804a1a8,(%esp)
8048f88: e8 63 f8 ff ff call 80487f0 <puts@plt>
8048f8d: e8 34 03 00 00 call 80492c6 <phase_defused>
8048f92: 83 c4 18 add $0x18,%esp
8048f95: 5b pop %ebx
8048f96: c3 ret
8048f97: 66 90 xchg %ax,%ax
8048f99: 66 90 xchg %ax,%ax
8048f9b: 66 90 xchg %ax,%ax
8048f9d: 66 90 xchg %ax,%ax
8048f9f: 90 nop
//分析fun7
08048ee4 <fun7>:
8048ee4: 53 push %ebx
8048ee5: 83 ec 18 sub $0x18,%esp
8048ee8: 8b 54 24 20 mov 0x20(%esp),%edx
8048eec: 8b 4c 24 24 mov 0x24(%esp),%ecx
8048ef0: 85 d2 test %edx,%edx//这里说明递归最深处返回值为0时,就退出递归并返回值
8048ef2: 74 37 je 8048f2b <fun7+0x47>
8048ef4: 8b 1a mov (%edx),%ebx
8048ef6: 39 cb cmp %ecx,%ebx
8048ef8: 7e 13 jle 8048f0d <fun7+0x29>
8048efa: 89 4c 24 04 mov %ecx,0x4(%esp)
8048efe: 8b 42 04 mov 0x4(%edx),%eax
8048f01: 89 04 24 mov %eax,(%esp)
8048f04: e8 db ff ff ff call 8048ee4 <fun7>//如果*x>36,以(x+4)作为地址进入下一层递归
8048f09: 01 c0 add %eax,%eax //返回值*=2
8048f0b: eb 23 jmp 8048f30 <fun7+0x4c>
8048f0d: b8 00 00 00 00 mov $0x0,%eax
8048f12: 39 cb cmp %ecx,%ebx
8048f14: 74 1a je 8048f30 <fun7+0x4c>
8048f16: 89 4c 24 04 mov %ecx,0x4(%esp)
8048f1a: 8b 42 08 mov 0x8(%edx),%eax
8048f1d: 89 04 24 mov %eax,(%esp)
8048f20: e8 bf ff ff ff call 8048ee4 <fun7>//如果*x<=36,(x+8)作为地址进入下一层递归
8048f25: 8d 44 00 01 lea 0x1(%eax,%eax,1),%eax//返回值=返回值*2+1
8048f29: eb 05 jmp 8048f30 <fun7+0x4c>
8048f2b: b8 ff ff ff ff mov $0xffffffff,%eax
8048f30: 83 c4 18 add $0x18,%esp
8048f33: 5b pop %ebx
8048f34: c3 ret
因此可得:(key=22)
(2)运行结果:
总结:
phase 1:He is evil and fits easily into most overhead storage bins.
phase 2:1 2 4 8 16 32
phase 3:0 276
phase 4:0 11 DrEvil或1 11 DrEvil
phase 5:mfcdhg
phase 6:2 1 4 5 6 3