bomblab实验-bomb1~6and隐藏关

bomb1:

08048ae0 <phase_1>:

8048ae0:       55                      push   %ebp

8048ae1:       89 e5                   mov    %esp,%ebp   //压栈操作

8048ae3:       83 ec 18                sub    $0x18,%esp  //开辟栈空间(24个字节)

8048ae6:       c7 44 24 04 48 a1 04    movl   $0x804a148,0x4(%esp)//向栈中存储0x804a148处的数据

8048aed:       08

8048aee:       8b 45 08                mov    0x8(%ebp),%eax//将栈帧中数据传入eax(写入参数)

  8048af1:       89 04 24                mov    %eax,(%esp)   //进栈

  8048af4:       e8 59 04 00 00          call   8048f52 <strings_not_equal>//调用函数

  8048af9:       85 c0                   test   %eax,%eax   //进行匹配比较

  8048afb:       74 05                   je     8048b02 <phase_1+0x22>    //跳转到phase_2

  8048afd:       e8 73 06 00 00          call   8049175 <explode_bomb>    //引爆炸弹

  8048b02:       c9                      leave         //释放局部变量

  8048b03:       c3                      ret       //返回函数调用

通过call可知在phase_1中调用了 strings_not_equal() 函数,其作用为判断字符串是否匹配。可知0x804a148处的字符串应该为被匹配的字符串,eax中为传入的参数,即0x804a148处字符串为该题答案。

输入查看eax中test之后为0,所以答案正确!

bomb2:

08048b04 <phase_2>:

 8048b04:       55                      push   %ebp

 8048b05:       89 e5                   mov    %esp,%ebp    //压栈

 8048b07:       56                      push   %esi        

 8048b08:       53                      push   %ebx         //esi,ebx进栈

 8048b09:       83 ec 30                sub    $0x30,%esp   //开辟栈空间(48字节)

 8048b0c:       8d 45 e0                lea    -0x20(%ebp),%eax  //取地址(ebp-0x20)到eax

 8048b0f:       89 44 24 04             mov    %eax,0x4(%esp)    //将eax中内容(地址)存入栈

 8048b13:       8b 45 08                mov    0x8(%ebp),%eax    //ebp+8处的元素存入eax

 8048b16:       89 04 24                mov    %eax,(%esp)       //存入栈中

 8048b19:       e8 99 06 00 00          call   80491b7 <read_six_numbers>//调用函数(读6个数字)

 8048b1e:       83 7d e0 31             cmpl   $0x31,-0x20(%ebp)     //比较0x31和ebp-0x20处的值进行比较【第一个数字a[0]放在了ebp-0x20】

 8048b22:       7f 20                   jg     8048b44 <phase_2+0x40>     //若大于,跳转到8048b44(进入循环体),即第一个数据大于0x31

 8048b24:       e8 4c 06 00 00          call   8049175 <explode_bomb>     //引爆炸弹

 8048b29:       eb 19                   jmp    8048b44 <phase_2+0x40>     //无条件跳转到8048b44(跳转进入循环体)

 8048b2b:       8b 43 fc                mov    -0x4(%ebx),%eax //前一个参数放入eax

 8048b2e:       8d 44 00 01             lea    0x1(%eax,%eax,1),%eax//取eax+eax*1+1放入eax

 8048b32:       39 03                   cmp    %eax,(%ebx)  //比较a[0]和eax中数据

//【a[i]=2*a[i-1]+1】

 8048b34:       74 05                   je     8048b3b <phase_2+0x37> //等于跳转到8048b3b

 8048b36:       e8 3a 06 00 00          call   8049175 <explode_bomb> //则引爆炸弹

 8048b3b:       83 c3 04                add    $0x4,%ebx    //ebx=ebx+4

 8048b3e:       39 f3                   cmp    %esi,%ebx    //比较esi和ebx

 8048b40:       75 e9                   jne    8048b2b <phase_2+0x27>//不相等,跳转到8048b2b

 8048b42:       eb 08                   jmp    8048b4c <phase_2+0x48> //无条件跳转到8048b4c

 8048b44:       8d 5d e4               lea    -0x1c(%ebp),%ebx //(a[1]) ebp-0x1c的地址到ebx

 8048b47:       8d 75 f8                lea    -0x8(%ebp),%esi

 8048b4a:       eb df                  jmp    8048b2b <phase_2+0x27>//无条件跳转到8048b2b(循环)

 8048b4c:       83 c4 30                add    $0x30,%esp//esp+0x30

 8048b4f:       5b                      pop    %ebx

 8048b50:       5e                      pop    %esi

 8048b51:       5d                      pop    %ebp

 8048b52:       c3                      ret

 

080491b7 <read_six_numbers>:

 80491b7:       55                      push   %ebp

 80491b8:       89 e5                   mov    %esp,%ebp         //压栈

 80491ba:       83 ec 28                sub    $0x28,%esp        //栈指针向下移动40个字节

 80491bd:       8b 45 0c                mov    0xc(%ebp),%eax    //数组a地址存入eax

 80491c0:       8d 50 14                lea    0x14(%eax),%edx   //a+5

 80491c3:       89 54 24 1c             mov    %edx,0x1c(%esp)

 80491c7:       8d 50 10                lea    0x10(%eax),%edx   //a+4

 80491ca:       89 54 24 18             mov    %edx,0x18(%esp)

 80491ce:       8d 50 0c                lea    0xc(%eax),%edx    //a+3

 80491d1:       89 54 24 14             mov    %edx,0x14(%esp)

 80491d5:       8d 50 08                lea    0x8(%eax),%edx    //a+2

 80491d8:       89 54 24 10             mov    %edx,0x10(%esp)

 80491dc:       8d 50 04                lea    0x4(%eax),%edx    //a+1

 80491df:       89 54 24 0c             mov    %edx,0xc(%esp)

 80491e3:       89 44 24 08             mov    %eax,0x8(%esp)

 80491e7:       c7 44 24 04 e5 a3 04    movl   $0x804a3e5,0x4(%esp)//a所在地址

 80491ee:       08

 80491ef:       8b 45 08                mov    0x8(%ebp),%eax

 80491f2:       89 04 24                mov    %eax,(%esp)

 80491f5:       e8 e6 f5 ff ff          call   80487e0 <__isoc99_sscanf@plt>   //调用sscanf

 80491fa:       83 f8 05                cmp    $0x5,%eax  //sscanf从input中读取的数据个数

 80491fd:       7f 05                   jg     8049204 <read_six_numbers+0x4d>//5大于输入,跳转到8049204

 80491ff:       e8 71 ff ff ff          call   8049175 <explode_bomb>     //小于等于5,爆炸

 8049204:       c9                      leave

 8049205:       c3                      ret

入栈eax,ebx 可以看出是两个地址,而 read_six_numbers 可以看出这个关卡的答案是 6 个数字。

phase_2汇编到调用函数之前为以下状况,由此可知 read_six_number 的参数除输入的内容外,还有一个 ebp-0x20,结合后面代码以及考虑到栈中还有很多空间开辟后未使用,可推出读取的六个数字以类似数组形式存储在了 ebp-0x20 开始的连续空间中

可以看出,该题为一个循环。第一个数字要大于0x31即49(10),后续数字需要满足a[i]=(a[i]+a[i]*1)+1

所以,设定第一个数字为50,得到结果:50 101 203 407 815 1631(结果不唯一,第一个数字大于49即可)

成功解除炸弹2!

bomb3:

08048b53 <phase_3>:

 8048b53:       55                      push   %ebp

 8048b54:       89 e5                   mov    %esp,%ebp

 8048b56:       83 ec 28                sub    $0x28,%esp

 8048b59:       8d 45 f0                lea    -0x10(%ebp),%eax//第二个数

 8048b5c:       89 44 24 0c             mov    %eax,0xc(%esp)

 8048b60:       8d 45 f4                lea    -0xc(%ebp),%eax//第一个数

 8048b63:       89 44 24 08             mov    %eax,0x8(%esp)

 8048b67:       c7 44 24 04 f1 a3 04    movl   $0x804a3f1,0x4(%esp)//通过x/s查看为 %d %d

 8048b6e:       08

 8048b6f:       8b 45 08                mov    0x8(%ebp),%eax

 8048b72:       89 04 24                mov    %eax,(%esp)

 8048b75:       e8 66 fc ff ff          call   80487e0 <__isoc99_sscanf@plt>//调用sscanf()

 8048b7a:       83 f8 01                cmp    $0x1,%eax

 8048b7d:       7f 05                  jg     8048b84 <phase_3+0x31>//函数输入参数个数大于1

 8048b7f:       e8 f1 05 00 00          call   8049175 <explode_bomb>//不然爆炸

 8048b84:       83 7d f4 07             cmpl   $0x7,-0xc(%ebp)

 8048b88:       77 1f                   ja     8048ba9 <phase_3+0x56>//大于7爆炸,-0xc(%ebp)数不超过7

 8048b8a:       8b 45 f4                mov    -0xc(%ebp),%eax

 8048b8d:       ff 24 85 c0 a1 04 08    jmp    *0x804a1c0(,%eax,4)//跳转到4*eax+0x804a1c0基址加比例变址->应该是一个switch跳转语句。通过x/s可得基址为98(10)

 8048b94:       b8 72 03 00 00          mov    $0x372,%eax  //0x372->eax

 8048b99:       eb 1f                   jmp    8048bba <phase_3+0x67> //跳转到8048bba

 8048b9b:       b8 44 02 00 00          mov    $0x244,%eax 

 8048ba0:       eb 18                   jmp    8048bba <phase_3+0x67> //

 8048ba2:       b8 a4 03 00 00          mov    $0x3a4,%eax

 8048ba7:       eb 11                   jmp    8048bba <phase_3+0x67> //

 8048ba9:       e8 c7 05 00 00          call   8049175 <explode_bomb>

 8048bae:       b8 00 00 00 00          mov    $0x0,%eax//0->eax

 8048bb3:       eb 30                   jmp    8048be5 <phase_3+0x92>//跳转进行操作

 8048bb5:       b8 16 02 00 00          mov    $0x216,%eax  //eax=0x216

 8048bba:       83 e0 c0                and    $0xffffffc0,%eax //跟踪调试为0x1f5与之与(跳转而来)

 8048bbd:       3b 45 f0                cmp    -0x10(%ebp),%eax //eax此时为0x1c0,查看此时的ebp-0x10中内容就是对应的第二个参数值

 8048bc0:       74 28                   je     8048bea <phase_3+0x97> //相等,则跳出

 8048bc2:       e8 ae 05 00 00          call   8049175 <explode_bomb> //不等,爆炸

 8048bc7:       eb 21                   jmp    8048bea <phase_3+0x97> //跳出

 8048bc9:       b8 f5 01 00 00          mov    $0x1f5,%eax

 8048bce:       66 90                   xchg   %ax,%ax   //交换操作数数据

 8048bd0:       eb e8                   jmp    8048bba <phase_3+0x67>

 8048bd2:       b8 77 03 00 00          mov    $0x377,%eax

 8048bd7:       eb e1                   jmp    8048bba <phase_3+0x67>

 8048bd9:       b8 5c 00 00 00          mov    $0x5c,%eax

 8048bde:       eb 05                   jmp    8048be5 <phase_3+0x92>

 8048be0:       b8 04 01 00 00          mov    $0x104,%eax

 8048be5:       83 e0 7f                and    $0x7f,%eax

 8048be8:       eb d3                   jmp    8048bbd <phase_3+0x6a>

 8048bea:       c9                      leave

 8048beb:       c3                      ret

movl $0x804a3f1,0x4(%esp)//通过x/s查看为 %d %d,获得读取参数

得知,密码应该是两个整数

cmpl $0x7,-0xc(%ebp) 即输入的第一个参数值必须不大于 7。然后看到 jmp    *0x804a1c0(,%eax,4)这是典型的 switch 跳转语句,即跳转到以地址 * 0x804a1c0 为基址的跳转表中。用 x/s*0x804a1c0,读出 switch 跳转基值为0x98

在代码中找到该处指令,得到第一个输入为 1 时对应的第二个输入为 0x1c0, 转换成十进制为 448。经调试后结果正确。



bomb4:

08048bec <func4>:

 8048bec:       55                      push   %ebp

 8048bed:       89 e5                   mov    %esp,%ebp

 8048bef:       56                      push   %esi //函数内临时变量1

 8048bf0:       53                      push   %ebx //函数内临时变量2

 8048bf1:       83 ec 10                sub    $0x10,%esp //开辟空间

 8048bf4:       8b 55 08                mov    0x8(%ebp),%edx //edx->a

 8048bf7:       8b 45 0c                mov    0xc(%ebp),%eax

 8048bfa:       8b 5d 10                mov    0x10(%ebp),%ebx //ebx->b

 8048bfd:       89 d9                   mov    %ebx,%ecx //ecx->c

 8048bff:       29 c1                   sub    %eax,%ecx  // x=c-b (用x代替ebx)*/

 8048c01:       89 ce                   mov    %ecx,%esi  //

 8048c03:       c1 ee 1f                shr    $0x1f,%esi //

 8048c06:       01 f1                   add    %esi,%ecx  //

 8048c08:       d1 f9                   sar    %ecx       //x = (x>>31 + x) >> 1

 8048c0a:       01 c1                   add    %eax,%ecx  //x=[(x>>31 + x) >> 1]+b

 8048c0c:       39 d1                   cmp    %edx,%ecx  //a和x比较

 8048c0e:       7e 17                   jle    8048c27 <func4+0x3b>//a<=x跳转.。。。。。。。。

 8048c10:       83 e9 01                sub    $0x1,%ecx      

 8048c13:       89 4c 24 08             mov    %ecx,0x8(%esp)  //ecx->c

 8048c17:       89 44 24 04             mov    %eax,0x4(%esp) 

 8048c1b:       89 14 24                mov    %edx,(%esp)     //edx->a

 8048c1e:       e8 c9 ff ff ff          call   8048bec <func4>//调用自身(递归)

 8048c23:       01 c0                   add    %eax,%eax

 8048c25:       eb 20                   jmp    8048c47 <func4+0x5b>

 8048c27:       b8 00 00 00 00          mov    $0x0,%eax //eax为返回值

 8048c2c:       39 d1                   cmp    %edx,%ecx //a和x比较

 8048c2e:       7d 17                   jge    8048c47 <func4+0x5b>//a>=转移

 8048c30:       89 5c 24 08             mov    %ebx,0x8(%esp)

 8048c34:       83 c1 01                add    $0x1,%ecx

 8048c37:       89 4c 24 04             mov    %ecx,0x4(%esp)

 8048c3b:       89 14 24                mov    %edx,(%esp)

 8048c3e:       e8 a9 ff ff ff          call   8048bec <func4>//调用自身(递归)

 8048c43:       8d 44 00 01             lea    0x1(%eax,%eax,1),%eax

 8048c47:       83 c4 10                add    $0x10,%esp

 8048c4a:       5b                      pop    %ebx

 8048c4b:       5e                      pop    %esi

 8048c4c:       5d                      pop    %ebp

 8048c4d:       c3                      ret

08048c4e <phase_4>:

 8048c4e:       55                      push   %ebp

 8048c4f:       89 e5                   mov    %esp,%ebp //压栈

 8048c51:       83 ec 28                sub    $0x28,%esp //开辟空间

 8048c54:       8d 45 f0                lea    -0x10(%ebp),%eax 参数num2

 8048c57:       89 44 24 0c             mov    %eax,0xc(%esp) //& [ebp-0x10]->栈

 8048c5b:       8d 45 f4                lea    -0xc(%ebp),%eax 参数num1

 8048c5e:       89 44 24 08             mov    %eax,0x8(%esp) //& [ebp-0xc]->栈

 8048c62:       c7 44 24 04 f1 a3 04    movl   $0x804a3f1,0x4(%esp)// %d,%d

 8048c69:       08

 8048c6a:       8b 45 08                mov    0x8(%ebp),%eax

 8048c6d:       89 04 24                mov    %eax,(%esp)// [val1]->栈

 8048c70:       e8 6b fb ff ff          call   80487e0 <__isoc99_sscanf@plt>//调用sscanf()

 8048c75:       83 f8 02                cmp    $0x2,%eax  //eax中为参数个数

 8048c78:       75 06                   jne    8048c80 <phase_4+0x32>//不等于2跳转爆炸

 8048c7a:       83 7d f4 0e             cmpl   $0xe,-0xc(%ebp)

 8048c7e:       76 05                   jbe    8048c85 <phase_4+0x37>// val1<=0xc

 8048c80:       e8 f0 04 00 00          call   8049175 <explode_bomb>

 8048c85:       c7 44 24 08 0e 00 00    movl   $0xe,0x8(%esp) //func4一个函数参数

 8048c8c:       00

 8048c8d:       c7 44 24 04 00 00 00    movl   $0x0,0x4(%esp) //func4一个函数参数

 8048c94:       00

 8048c95:       8b 45 f4                mov    -0xc(%ebp),%eax//phase_4返回值->eax

 8048c98:       89 04 24                mov    %eax,(%esp) eax->地址为esp的寄存器  

 8048c9b:       e8 4c ff ff ff          call   8048bec <func4> //调用函数func4

 8048ca0:       83 f8 04                cmp    $0x4,%eax //eax中为0x4:func4返回值为0x4

 8048ca3:       75 06                   jne    8048cab <phase_4+0x5d> //不等跳转爆炸

 8048ca5:       83 7d f0 04             cmpl   $0x4,-0x10(%ebp) 参数必须为0x4才能结束

 8048ca9:       74 05                   je     8048cb0 <phase_4+0x62>

 8048cab:       e8 c5 04 00 00          call   8049175 <explode_bomb>

 8048cb0:       c9                      leave

 8048cb1:       c3                      ret

movl   $0x804a3f1,0x4(%esp)//通过x/s查看为 %d %d,获得读取参数为2个

先从我们的输入中获取两个 int 型整数。我们命令为 num1 和 num2。接着判断 sscanf 函数的返回值,如果不等于 2 (输入为2个数)则触发炸弹,否则继续。接下来的几条指令看出[cmpl $0xe,-0xc(%ebp)],num1 必须小于等于 12,否则触发炸弹

接下来调用函数 func4,参数分别为 num1,0 和 14。

cmp    $0x4,%eax检验函数func4()返回值应该为4. cmpl   $0x4,-0x10(%ebp)表明num2应该为0x4.

再关注func4:

可以看到func()中有调用自己,所以为递归函数 且func4 的原型应该是 int func4(int a, int b, int c);根据计算结果,反推c语言代码如下:

要其返回值为4,所以可以得到num1应该为2

所以该题结果为2  4

bomb5:

08048cb2 <phase_5>:

 8048cb2:       55                      push   %ebp

 8048cb3:       89 e5                   mov    %esp,%ebp

 8048cb5:       53                      push   %ebx

 8048cb6:       83 ec 14                sub    $0x14,%esp

 8048cb9:       8b 5d 08                mov    0x8(%ebp),%ebx//输入的数num1

 8048cbc:       89 1c 24                mov    %ebx,(%esp)

 8048cbf:       e8 6c 02 00 00          call   8048f30 <string_length>//猜测字符串长度

 8048cc4:       83 f8 06                cmp    $0x6,%eax

 8048cc7:       74 05                   je     8048cce <phase_5+0x1c> //字符串长度为6

 8048cc9:       e8 a7 04 00 00          call   8049175 <explode_bomb>

 8048cce:       ba 00 00 00 00          mov    $0x0,%edx

 8048cd3:       b8 00 00 00 00          mov    $0x0,%eax

 8048cd8:       0f b6 0c 03           movzbl (%ebx,%eax,1),%ecx //一个字节->双字 ebx+eax->ecx【对num1进行扩展为32位】

 8048cdc:       83 e1 0f                and    $0xf,%ecx   //保留后四位,前28位变为0

 8048cdf:       03 14 8d e0 a1 04 08    add    0x804a1e0(,%ecx,4),%edx //基址+寄存器寻址

 8048ce6:       83 c0 01                add    $0x1,%eax  //猜测eax为字符串数组的下标

 8048ce9:       83 f8 06                cmp    $0x6,%eax (循环6次)

 8048cec:       75 ea                   jne    8048cd8 <phase_5+0x26>

 8048cee:       83 fa 2e                cmp    $0x2e,%edx//返回值要为0x2e即46

 8048cf1:       74 05                   je     8048cf8 <phase_5+0x46>

 8048cf3:       e8 7d 04 00 00          call   8049175 <explode_bomb>

 8048cf8:       83 c4 14                add    $0x14,%esp

 8048cfb:       5b                      pop    %ebx

 8048cfc:       5d                      pop    %ebp

 8048cfd:       c3                      ret

由题意可以得知为一个6个字符的字符串

循环段读取含义为分别截取每个字符的后四位放入ecx,将其作为偏移量,将0x804a1e0+(ecx*4)加入edx。6次循环后,edx中的值应该等于0x2e,即(46)10。

 

查看0x804a1e0开始的连续字符(32位)

可得到当选中如下数据最后和为0x2e。则偏移量ecx应该分别为(0x):1 2 4 6 8 B.即选取字符串的6个字符ascii码的二进制编码后4位需要满足上面的关系。所以,取a(0x61),b(0x62),d(0x64),f(0x66),h(0x68),k(0x6B)

运行检验运行,答案正确。

bomb6:

08048cfe <phase_6>:

 8048cfe:       55                      push   %ebp

 8048cff:       89 e5                   mov    %esp,%ebp

 8048d01:       56                      push   %esi

 8048d02:       53                      push   %ebx

 8048d03:       83 ec 40                sub    $0x40,%esp

 8048d06:       8d 45 e0                lea    -0x20(%ebp),%eax  /eax=num/

 8048d09:       89 44 24 04             mov    %eax,0x4(%esp)

 8048d0d:       8b 45 08                mov    0x8(%ebp),%eax

 8048d10:       89 04 24                mov    %eax,(%esp)

 8048d13:       e8 9f 04 00 00          call   80491b7 <read_six_numbers> //读6个数

 8048d18:       be 00 00 00 00          mov    $0x0,%esi

 8048d1d:       8b 44 b5 e0        mov    -0x20(%ebp,%esi,4),%eax  //   a[esi]->eax

 8048d21:       83 e8 01                sub    $0x1,%eax  //eax=a[i]-1

 8048d24:       83 f8 05                cmp    $0x5,%eax

 8048d27:       76 05                   jbe    8048d2e <phase_6+0x30> 

 8048d29:       e8 47 04 00 00          call   8049175 <explode_bomb> //保证num[esi]<=5

 8048d2e:       83 c6 01                add    $0x1,%esi 

 8048d31:       83 fe 06                cmp    $0x6,%esi  //esi为计数器(循环6次)

 8048d34:       74 1c                   je     8048d52 <phase_6+0x54>

 8048d36:       89 f3                   mov    %esi,%ebx

 8048d38:       8b 44 9d e0             mov    -0x20(%ebp,%ebx,4),%eax //ebx=esi+1,eax=a[ebx]

 8048d3c:       39 44 b5 dc             cmp    %eax,-0x24(%ebp,%esi,4)

 8048d40:       75 05                   jne    8048d47 <phase_6+0x49>

 

这里控制6个数据都互不相同(对所有进行扫描保证不同)

 8048d42:       e8 2e 04 00 00          call   8049175 <explode_bomb>//确保num[ebx]!=num[esi]即两个相邻的数不相等

 8048d47:       83 c3 01                add    $0x1,%ebx

 8048d4a:       83 fb 05                cmp    $0x5,%ebx

 8048d4d:       7e e9                   jle    8048d38 <phase_6+0x3a>

 8048d4f:       90                      nop

 8048d50:       eb cb                   jmp    8048d1d <phase_6+0x1f>

 8048d52:       8d 45 e0                lea    -0x20(%ebp),%eax  /eax=num/

 8048d55:       8d 5d f8                lea    -0x8(%ebp),%ebx   /ebx=p/

 8048d58:       b9 07 00 00 00          mov    $0x7,%ecx      //ecx=7

 8048d5d:       89 ca                   mov    %ecx,%edx   

 8048d5f:       2b 10                   sub    (%eax),%edx 

 8048d61:       89 10                   mov    %edx,(%eax) 

 8048d63:       83 c0 04                add    $0x4,%eax    //eax=p-num+0x4

 8048d66:       39 d8                   cmp    %ebx,%eax

 8048d68:       75 f3                  jne    8048d5d <phase_6+0x5f> //p(ebx)不指向eax继续计算

 8048d6a:       bb 00 00 00 00          mov    $0x0,%ebx

 8048d6f:       eb 1d                   jmp    8048d8e <phase_6+0x90> //p(ebx)指向eax

 

 8048d71:       8b 52 08                mov    0x8(%edx),%edx

 8048d74:       83 c0 01                add    $0x1,%eax

 8048d77:       39 c8                   cmp    %ecx,%eax  ecp->指向其next

 8048d79:       75 f6                   jne    8048d71 <phase_6+0x73> //不等重新计算

 8048d7b:       eb 05                   jmp    8048d82 <phase_6+0x84> //等于则跳转

 8048d7d:       ba 54 c1 04 08          mov    $0x804c154,%edx

 8048d82:       89 54 b5 c8             mov    %edx,-0x38(%ebp,%esi,4)

 8048d86:       83 c3 01                add    $0x1,%ebx               //ebx+=1

 8048d89:       83 fb 06                cmp    $0x6,%ebx

 8048d8c:       74 17                   je     8048da5 <phase_6+0xa7>//6个元素之间链表建立成功,则跳转下一步。

 8048d8e:       89 de                   mov    %ebx,%esi

 8048d90:       8b 4c 9d e0             mov    -0x20(%ebp,%ebx,4),%ecx /ecx=p->next /

 8048d94:       83 f9 01                cmp    $0x1,%ecx   

 

这里为对6个元素建立链表部分

 8048d97:       7e e4                   jle    8048d7d <phase_6+0x7f> //指向不正确,重新计算

 8048d99:       b8 01 00 00 00          mov    $0x1,%eax

 8048d9e:       ba 54 c1 04 08          mov    $0x804c154,%edx

 8048da3:       eb cc                   jmp    8048d71 <phase_6+0x73>

 

 8048da5:       8b 5d c8                mov    -0x38(%ebp),%ebx

 8048da8:       8d 45 cc                lea    -0x34(%ebp),%eax

 8048dab:       8d 75 e0                lea    -0x20(%ebp),%esi

 8048dae:       89 d9                   mov    %ebx,%ecx

 8048db0:       8b 10                   mov    (%eax),%edx

 8048db2:       89 51 08                mov    %edx,0x8(%ecx)

 8048db5:       83 c0 04                add    $0x4,%eax

 8048db8:       39 f0                   cmp    %esi,%eax

 8048dba:       74 04                   je     8048dc0 <phase_6+0xc2>

 8048dbc:       89 d1                   mov    %edx,%ecx

 8048dbe:       eb f0                   jmp    8048db0 <phase_6+0xb2>

 8048dc0:       c7 42 08 00 00 00 00    movl   $0x0,0x8(%edx)

 8048dc7:       be 05 00 00 00          mov    $0x5,%esi

 8048dcc:       8b 43 08                mov    0x8(%ebx),%eax eax=ebx->next

 8048dcf:       8b 00                   mov    (%eax),%eax

 8048dd1:       39 03                   cmp    %eax,(%ebx) 比较eax和ebx->value

 8048dd3:       7d 05                   jge    8048dda <phase_6+0xdc>

 8048dd5:       e8 9b 03 00 00         call   8049175 <explode_bomb>//链表元素出现升序,爆炸【即排列好的数据要完全降序排列】

 8048dda:       8b 5b 08                mov    0x8(%ebx),%ebx

 8048ddd:       83 ee 01                sub    $0x1,%esi

 8048de0:       75 ea                   jne    8048dcc <phase_6+0xce>

 8048de2:       83 c4 40                add    $0x40,%esp

 8048de5:       5b                      pop    %ebx

 8048de6:       5e                      pop    %esi

 8048de7:       5d                      pop    %ebp

 8048de8:       c3                      ret

输入假设样例1 2 3 4 5 6

用 gdb 查看 0x804c154 附近的内容:

可以确定结构由三个元素组成, 两个整形数据, 一个结构类型的指针, 重复操作可以发现这是一个有 6 个元素的链表, 称此结构为 node

读取顺序为从后往前,此时的链表为:

node6-> node5-> node4-> node3-> node2-> node1-> NULL 

typedef struct node{

    int value;

    int idx;

struct node *next;

}node;

node node1={0x27e,   1,   NULL,   0x73};

node node2={0x73,    2,   &node1,     0x3d3};

node node3={0x3d3,   3,   &node2,     0x1ab};

node node4={0x1ab,   4,   &node3,   0x255};

node node5={0x255,   5,   &node4,   0x248};

node node6={0x248,   6,   &node5,   0x00};

分析代码为:对其按照value值0x3d3,0x255,0x27e,0x1ab,0x248,0x73由大到小排序,重新链接得到链表如下,C语言代码如下:

node3-> node1-> node5-> node6-> node4-> node2-> NULL

从后往前找最大,放在加入链表,形成降序排列。

从6--à1找,最大的0x3d3为最大,是第四个,次大之0x27e为第6个。。。。以此类推

所以,num=4 6 2 1 3 5

隐藏关:

进入方法:

搜索整个汇编代码, 发现只在 phase_defuse 函数中调用过 secret_phase 函数, 所以先分析这个函数.

0804933e <phase_defused>:

 804933e:       55                      push   %ebp

 804933f:       89 e5                   mov    %esp,%ebp

 8049341:       81 ec 88 00 00 00       sub    $0x88,%esp

 8049347:       c7 04 24 01 00 00 00    movl   $0x1,(%esp)

 804934e:       e8 4b fd ff ff          call   804909e <send_msg>

 8049353:       83 3d e8 c7 04 08 06    cmpl   $0x6,0x804c7e8 //

 804935a:       75 7a                   jne    80493d6 <phase_defused+0x98>

 804935c:       8d 45 a8                lea    -0x58(%ebp),%eax

 804935f:       89 44 24 10             mov    %eax,0x10(%esp)

 8049363:       8d 45 a0                lea    -0x60(%ebp),%eax

 8049366:       89 44 24 0c             mov    %eax,0xc(%esp)

 804936a:       8d 45 a4                lea    -0x5c(%ebp),%eax

 804936d:       89 44 24 08             mov    %eax,0x8(%esp)

 8049371:       c7 44 24 04 4b a4 04    movl   $0x804a44b,0x4(%esp)

 8049378:       08

 8049379:       c7 04 24 f0 c8 04 08    movl   $0x804c8f0,(%esp)

 8049380:       e8 5b f4 ff ff          call   80487e0 <__isoc99_sscanf@plt>

 8049385:       83 f8 03                cmp    $0x3,%eax

 8049388:       75 34                   jne    80493be <phase_defused+0x80>

 804938a:       c7 44 24 04 54 a4 04    movl   $0x804a454,0x4(%esp)

 8049391:       08

 8049392:       8d 45 a8                lea    -0x58(%ebp),%eax

 8049395:       89 04 24                mov    %eax,(%esp)

 8049398:       e8 b5 fb ff ff          call   8048f52 <strings_not_equal>

 804939d:       85 c0                   test   %eax,%eax

 804939f:       75 1d                  jne    80493be <phase_defused+0x80>//不匹配跳过隐藏关

 80493a1:       c7 04 24 a0 a2 04 08    movl   $0x804a2a0,(%esp)

 80493a8:       e8 d3 f3 ff ff          call   8048780 <puts@plt>

 80493ad:       c7 04 24 c8 a2 04 08    movl   $0x804a2c8,(%esp)

 80493b4:       e8 c7 f3 ff ff          call   8048780 <puts@plt>

 80493b9:       e8 7e fa ff ff          call   8048e3c <secret_phase>

 80493be:       c7 04 24 00 a3 04 08    movl   $0x804a300,(%esp)

 80493c5:       e8 b6 f3 ff ff          call   8048780 <puts@plt>

 80493ca:       c7 04 24 2c a3 04 08    movl   $0x804a32c,(%esp)

 80493d1:       e8 aa f3 ff ff          call   8048780 <puts@plt>

 80493d6:       c9                      leave

 80493d7:       c3                      ret

 80493d8:       66 90                   xchg   %ax,%ax

 80493da:       66 90                   xchg   %ax,%ax

 80493dc:       66 90                   xchg   %ax,%ax

 80493de:       66 90                   xchg   %ax,%ax

在 phase_defused 函数中有 cmpl   $0x6,0x804c7e8 语句, 搜索 0x804c7e8 发现这个内存的值在每读入一条字符串后就会加 1,

则显然 secret_phase 是在第 6 条字符串之后输入. 又发现 cmp    $0x3,%eax, 语句, 此时的 %eax 是 sscanf 读取的参数个数。sscanf 读取的参数格式保存在0x804a44b 位置处, 为 "%d %d %s", 待读取的参数存放在 0x804c8f0 内存处,

用 x/s 0x804b770 看时发现这个内存位置的字符串为 " ", 什么都没有, 从后面的调用
strings_not_equal 来看, 还要读入的字符保存在0x804a454 中, 查看为DrEvil

查看0x804a2a0发现提示:

之后在前面结果中插入DrEvil测试,发现在phase_4这样就可以正确执行到 secret_phase 函数调用位置处了.

08048e3c <secret_phase>:

 8048e3c:       55                      push   %ebp

 8048e3d:       89 e5                   mov    %esp,%ebp

 8048e3f:       53                      push   %ebx

 8048e40:       83 ec 14                sub    $0x14,%esp

 8048e43:       e8 be 03 00 00          call   8049206 <read_line>//读取一行

 8048e48:       c7 44 24 08 0a 00 00    movl   $0xa,0x8(%esp)

 8048e4f:       00

 8048e50:       c7 44 24 04 00 00 00    movl   $0x0,0x4(%esp)

 8048e57:       00

 8048e58:       89 04 24                mov    %eax,(%esp) //eax为read_line()返回值

 8048e5b:       e8 e0 f9 ff ff          call   8048840 <strtol@plt>//返回值 %eax 作为函数 <strtol@plt> 的参数之一,另外两个参数分别是 0xa 和 0x0

 8048e60:       89 c3                   mov    %eax,%ebx

 8048e62:       8d 40 ff                lea    -0x1(%eax),%eax /*

 8048e65:       3d e8 03 00 00          cmp    $0x3e8,%eax  

 8048e6a:       76 05                   jbe    8048e71 <secret_phase+0x35>

 8048e6c:       e8 04 03 00 00          call   8049175 <explode_bomb>输入的十进制数要小于等于 1001*/

 8048e71:       89 5c 24 04             mov    %ebx,0x4(%esp)

 8048e75:       c7 04 24 a0 c0 04 08    movl   $0x804c0a0,(%esp)

 8048e7c:       e8 68 ff ff ff          call   8048de9 <fun7>

//随后将所输入的数作为 <fun7> 的参数之一。另外一个参数来自 0x804c178,查看为 0x55。

 8048e81:       83 f8 05                cmp    $0x5,%eax

 8048e84:       74 05                   je     8048e8b <secret_phase+0x4f>

 8048e86:       e8 ea 02 00 00          call   8049175 <explode_bomb>

 8048e8b:       c7 04 24 94 a1 04 08    movl   $0x804a194,(%esp)

 8048e92:       e8 e9 f8 ff ff          call   8048780 <puts@plt>

 8048e97:       e8 a2 04 00 00          call   804933e <phase_defused>

 8048e9c:       83 c4 14                add    $0x14,%esp

 8048e9f:       5b                      pop    %ebx

 8048ea0:       5d                      pop    %ebp

 8048ea1:       c3                      ret

 8048ea2:       66 90                   xchg   %ax,%ax

 8048ea4:       66 90                   xchg   %ax,%ax

 8048ea6:       66 90                   xchg   %ax,%ax

 8048ea8:       66 90                   xchg   %ax,%ax

 8048eaa:       66 90                   xchg   %ax,%ax

 8048eac:       66 90                   xchg   %ax,%ax

 8048eae:       66 90                   xchg   %ax,%ax

08048de9 <fun7>:

 8048de9:       55                      push   %ebp

 8048dea:       89 e5                   mov    %esp,%ebp

 8048dec:       53                      push   %ebx

 8048ded:       83 ec 14                sub    $0x14,%esp

 8048df0:       8b 55 08                mov    0x8(%ebp),%edx  // 第一个参数 A

 8048df3:       8b 4d 0c                mov    0xc(%ebp),%ecx   // 第二个参数 B 即输入

 8048df6:       85 d2                   test   %edx,%edx       

 8048df8:       74 37                   je     8048e31 <fun7+0x48>// 递归终止,返回 %edx=0

 8048dfa:       8b 1a                   mov    (%edx),%ebx

 8048dfc:       39 cb                   cmp    %ecx,%ebx

 8048dfe:       7e 13                   jle    8048e13 <fun7+0x2a>// 若 * A>b,将 (A+4) 作为地址进入递归

 8048e00:       89 4c 24 04             mov    %ecx,0x4(%esp)

 8048e04:       8b 42 04                mov    0x4(%edx),%eax

 8048e07:       89 04 24                mov    %eax,(%esp)

 8048e0a:       e8 da ff ff ff          call   8048de9 <fun7>//递归

 8048e0f:       01 c0                   add    %eax,%eax  //递归返回值加倍

 8048e11:       eb 23                   jmp    8048e36 <fun7+0x4d>

 8048e13:       b8 00 00 00 00          mov    $0x0,%eax

 8048e18:       39 cb                   cmp    %ecx,%ebx

 8048e1a:       74 1a                   je     8048e36 <fun7+0x4d>// 若 * A<B,将 (A+8) 作为地址进入递归

 8048e1c:       89 4c 24 04             mov    %ecx,0x4(%esp)

 8048e20:       8b 42 08                mov    0x8(%edx),%eax

 8048e23:       89 04 24                mov    %eax,(%esp)

 8048e26:       e8 be ff ff ff          call   8048de9 <fun7>

// 在此处将递归返回值加倍后在加 1

 8048e2b:       8d 44 00 01             lea    0x1(%eax,%eax,1),%eax

 8048e2f:       eb 05                   jmp    8048e36 <fun7+0x4d>

 8048e31:       b8 ff ff ff ff          mov    $0xffffffff,%eax

 8048e36:       83 c4 14                add    $0x14,%esp

 8048e39:       5b                      pop    %ebx

 8048e3a:       5d                      pop    %ebp

 8048e3b:       c3                      ret

在调用完 <fun7> 之后,紧跟着 cmp   $0x5,%eax,即返回值必须为 5。<fun7> 分析如上,为递归函数,与第四题十分相似。递归最深处的返回值肯定为 0,最外层返回值为 5,可得出如下反递归过程:

A*2+1=5 - ->A=2    即有 * A<B

A*2=2  -->A=1    有 * A>B

A*2+1=1 - ->A=0    即有 * A<B

也就是说在这三次递归中两次执行了 “若 * A<B 将(A+8) 作为地址进入递归”系列代码,一次执行了 “若 * A>b,将(A+4) 作为地址进入递归”系列代码。使用 gdb 查询储存值:

最后得到 0x2f,即使我们要输入的十进制值 47。

运行结果,找出了所有关的答案:

发布了6 篇原创文章 · 获赞 1 · 访问量 2512

猜你喜欢

转载自blog.csdn.net/Mu_Xiaoye/article/details/81225418