Loading

ustc-caspp-lab2-bomb

准备

环境配置

推荐使用linux
这里用使用ubuntu,vm中创建即可,如何创建此处不记录

我们需要安装一些工具

sudo apt install gcc
sudo apt install make
sudo apt install gcc-multilib
sudo apt install gdb

资源

csapp官方
http://csapp.cs.cmu.edu/3e/labs.html

ustc 给出的实验代码是修改过的,你的和本文章的可能不一样,这里提供思路
直接看我贴出的汇编代码即可

前置知识

首先是x86寄存器的介绍,下面将会频繁使用

需要注意的是函数调用参数的传递寄存器
esp,ebp,eax

实验提供好编译好的程序是 32位的,我们只需要关心e开头,同时如果如果linux没有32位库,会无法运行,如果没有需要下载

需要注意的汇编指令
跳转指令

leal -28(%ebp), %eax 代表将ebp的内容-28,送到eax中;

mov -0x1c(%ebp,%eax,4),%edx 其中 base(offset, index, i),等于 base+offset+index*i

gdb的使用
gdb bomb 对bomb进行调试
set args xxxx 设置命令参数 等于执行 ./bomb xxx
b point 设置断点,可以是地址,函数名,例如b phase_1b *0x44ff
run运行,直到断点
continue 继续运行到下一个断点
si 单条指令执行
layout asm 显示汇编
x/参数 <地址> 访问地址的内存,s是输出为字符串,d为输出为十进制,x为输出为十六进制,b、w、l、q控制输出字节,默认是w,四字节,s字符串不受这个控制除外。
delete 删除所有断点

通过简单的读bomb.c的内容可以看到,有6和函数phase_1 到phase_6,每个都需要一输入,然后来判断是否会“爆炸”,也就是能否通过测试。但是我们不知道这6个函数的源码,没发直接判断。我们需要通过反编译bomb,通过汇编层面破解这个程序。

phase1

08048b80 <phase_1>:
 8048b80:       55                      push   %ebp
 8048b81:       89 e5                   mov    %esp,%ebp
 8048b83:       83 ec 08                sub    $0x8,%esp
 8048b86:       c7 44 24 04 58 99 04    movl   $0x8049958,0x4(%esp)
 8048b8d:       08
 8048b8e:       8b 45 08                mov    0x8(%ebp),%eax
 8048b91:       89 04 24                mov    %eax,(%esp)
 8048b94:       e8 fa 04 00 00          call   8049093 <strings_not_equal>
 8048b99:       85 c0                   test   %eax,%eax
 8048b9b:       74 05                   je     8048ba2 <phase_1+0x22>
 8048b9d:       e8 b8 0a 00 00          call   804965a <explode_bomb>
 8048ba2:       c9                      leave
 8048ba3:       c3                      ret

我们输入的是一个字符串,所以寄存器中存的基本都是地址。
我们首先能看到 <strings_not_equal>,其返回结果在eax(默认)中,然后我们通过对eax的判断来决定是否“爆炸”
基本逻辑也就清楚了,用我们的输入和另一个字符串做对比,通过gdb可以看到eax是我们输入的内容,那么$0x8049958就是另一个字符串的地址
查看其值即可

phase2

//测试输入1 2 3 4 5 6
08048ba4 <phase_2>:
 8048ba4:       55                      push   %ebp
 8048ba5:       89 e5                   mov    %esp,%ebp
 8048ba7:       83 ec 28                sub    $0x28,%esp
 8048baa:       8d 45 e4                lea    -0x1c(%ebp),%eax
 8048bad:       89 44 24 04             mov    %eax,0x4(%esp)
 8048bb1:       8b 45 08                mov    0x8(%ebp),%eax
 8048bb4:       89 04 24                mov    %eax,(%esp)
 8048bb7:       e8 44 04 00 00          call   8049000 <read_six_numbers>
 8048bbc:       c7 45 fc 01 00 00 00    movl   $0x1,-0x4(%ebp)   //初始循环变量i值为1
 8048bc3:       eb 1e                   jmp    8048be3 <phase_2+0x3f>

 8048bc5:       8b 45 fc                mov    -0x4(%ebp),%eax  // eax=-0x4(%ebp)  eax=i
 8048bc8:       8b 54 85 e4             mov    -0x1c(%ebp,%eax,4),%edx //edx=ebp+eax*4-28, edx=arr[i]
 8048bcc:       8b 45 fc                mov    -0x4(%ebp),%eax  //eax=i
 8048bcf:       48                      dec    %eax  // eax=i--
 8048bd0:       8b 44 85 e4             mov    -0x1c(%ebp,%eax,4),%eax //eax=ebp+eax*4-28, eax=arr[i],前一个元素
 8048bd4:       83 c0 05                add    $0x5,%eax  //eax=前一个元素+5
 8048bd7:       39 c2                   cmp    %eax,%edx  // 相当于判断arr[i]==arr[i-1]+5
 8048bd9:       74 05                   je     8048be0 <phase_2+0x3c> //相同,进入下一个循环
 8048bdb:       e8 7a 0a 00 00          call   804965a <explode_bomb> //不相同 bomb

 8048be0:       ff 45 fc                incl   -0x4(%ebp) //循环变量++
 8048be3:       83 7d fc 05             cmpl   $0x5,-0x4(%ebp) //循环退出条件 i<=5
 8048be7:       7e dc                   jle    8048bc5<phase_2+0x21>

 8048be9:       c9                      leave
 8048bea:       c3                      ret



 08049000 <read_six_numbers>:
 8049000:       55                      push   %ebp
 8049001:       89 e5                   mov    %esp,%ebp
 8049003:       56                      push   %esi
 8049004:       53                      push   %ebx
 8049005:       83 ec 30                sub    $0x30,%esp
 8049008:       8b 45 0c                mov    0xc(%ebp),%eax  //eax 是str的地址 “1 2 3 4 5 6”
 804900b:       83 c0 14                add    $0x14,%eax  // ->6  指向6所在的地址
 804900e:       8b 55 0c                mov    0xc(%ebp),%edx 
 8049011:       83 c2 10                add    $0x10,%edx  // ->5
 8049014:       8b 4d 0c                mov    0xc(%ebp),%ecx
 8049017:       83 c1 0c                add    $0xc,%ecx   // ->4
 804901a:       8b 5d 0c                mov    0xc(%ebp),%ebx
 804901d:       83 c3 08                add    $0x8,%ebx   // ->3
 8049020:       8b 75 0c                mov    0xc(%ebp),%esi
 8049023:       83 c6 04                add    $0x4,%esi   // ->2
 8049026:       89 44 24 1c             mov    %eax,0x1c(%esp)  //  在栈中保存
 804902a:       89 54 24 18             mov    %edx,0x18(%esp)  
 804902e:       89 4c 24 14             mov    %ecx,0x14(%esp)  
 8049032:       89 5c 24 10             mov    %ebx,0x10(%esp)  
 8049036:       89 74 24 0c             mov    %esi,0xc(%esp)   
 804903a:       8b 45 0c                mov    0xc(%ebp),%eax   
 804903d:       89 44 24 08             mov    %eax,0x8(%esp)   
 8049041:       c7 44 24 04 85 9c 04    movl   $0x8049c85,0x4(%esp)
 8049048:       08
 8049049:       8b 45 08                mov    0x8(%ebp),%eax
 804904c:       89 04 24                mov    %eax,(%esp)
 804904f:       e8 14 f8 ff ff          call   8048868 <sscanf@plt>  //格式化为int
 8049054:       89 45 f4                mov    %eax,-0xc(%ebp)
 8049057:       83 7d f4 05             cmpl   $0x5,-0xc(%ebp)
 804905b:       7f 05                   jg     8049062 <read_six_numbers+0x62>
 804905d:       e8 f8 05 00 00          call   804965a <explode_bomb>

 8049062:       83 c4 30                add    $0x30,%esp
 8049065:       5b                      pop    %ebx
 8049066:       5e                      pop    %esi
 8049067:       5d                      pop    %ebp
 8049068:       c3                      ret

大部分逻辑都写到了代码注释上,突破点在<read_six_numbers>,也就是读6个数字,展开分析,其中并没有做太多操作,主要是sscanf

C 库函数 int sscanf(const char *str, const char *format, ...) 从字符串读取格式化输入。返回值为成功格式化的个数

接着向下分析,能看到movl $0x1,-0x4(%ebp) 在一个地址上放了0x1,然后进行跳转,然后进行了增加,和5进行判断,再决定跳转。如何符合条件,会执行中间那一段,其又回跳转到8048be0,形成了循环。我们大致能判断这是一个for,在分析for内部干了什么,具体看代码注释

phase3

08048beb <phase_3>:
 8048beb:       55                      push   %ebp
 8048bec:       89 e5                   mov    %esp,%ebp
 8048bee:       83 ec 28                sub    $0x28,%esp
 8048bf1:       c7 45 f8 00 00 00 00    movl   $0x0,-0x8(%ebp)  
 8048bf8:       c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%ebp)
 8048bff:       8d 45 f0                lea    -0x10(%ebp),%eax
 8048c02:       89 44 24 0c             mov    %eax,0xc(%esp)
 8048c06:       8d 45 f4                lea    -0xc(%ebp),%eax
 8048c09:       89 44 24 08             mov    %eax,0x8(%esp)
 8048c0d:       c7 44 24 04 89 99 04    movl   $0x8049989,0x4(%esp)  //"%d %d",我们需要两个数字
 8048c14:       08
 8048c15:       8b 45 08                mov    0x8(%ebp),%eax 
 8048c18:       89 04 24                mov    %eax,(%esp)
 8048c1b:       e8 48 fc ff ff          call   8048868 <sscanf@plt>
 8048c20:       89 45 fc                mov    %eax,-0x4(%ebp)
 8048c23:       83 7d fc 01             cmpl   $0x1,-0x4(%ebp)   
 8048c27:       7f 05                   jg     8048c2e <phase_3+0x43>  //判断格式化的个数是否>1
 8048c29:       e8 2c 0a 00 00          call   804965a <explode_bomb>

 8048c2e:       8b 45 f4                mov    -0xc(%ebp),%eax     //eax=第一个参数
 8048c31:       89 45 ec                mov    %eax,-0x14(%ebp)
 8048c34:       83 7d ec 07             cmpl   $0x7,-0x14(%ebp)    
 8048c38:       77 40                   ja     8048c7a <phase_3+0x8f>   // >7 bomb
 8048c3a:       8b 55 ec                mov    -0x14(%ebp),%edx  //4
 8048c3d:       8b 04 95 90 99 04 08    mov    0x8049990(,%edx,4),%eax // 
 8048c44:       ff e0                   jmp    *%eax
 8048c46:       83 45 f8 75             addl   $0x75,-0x8(%ebp)   //=0 ->-426 -1062
 8048c4a:       81 6d f8 a0 03 00 00    subl   $0x3a0,-0x8(%ebp)  //=1 ->-49b -1179
 8048c51:       81 45 f8 40 02 00 00    addl   $0x240,-0x8(%ebp)  //=2 ->-fb -251
 8048c58:       81 6d f8 6e 01 00 00    subl   $0x16e,-0x8(%ebp)  //=3 ->-33b -827
 8048c5f:       83 45 f8 6d             addl   $0x6d,-0x8(%ebp)   //=4 ->-1cd -461
 8048c63:       81 6d f8 94 01 00 00    subl   $0x194,-0x8(%ebp)  //=5 ->-23a -570
 8048c6a:       81 45 f8 94 01 00 00    addl   $0x194,-0x8(%ebp)  //=6 ->-a6 -166
 8048c71:       81 6d f8 3a 02 00 00    subl   $0x23a,-0x8(%ebp)  //=7 ->-23a -570
 8048c78:       eb 05                   jmp    8048c7f <phase_3+0x94>

 8048c7a:       e8 db 09 00 00          call   804965a <explode_bomb>

 8048c7f:       8b 45 f4                mov    -0xc(%ebp),%eax  //eax=第一个参数
 8048c82:       83 f8 05                cmp    $0x5,%eax   //
 8048c85:       7f 08                   jg     8048c8f <phase_3+0xa4>  // 大于5 bomb
 8048c87:       8b 45 f0                mov    -0x10(%ebp),%eax   //第二个参数
 8048c8a:       39 45 f8                cmp    %eax,-0x8(%ebp)    //对比另一个数时
 8048c8d:       74 05                   je     8048c94 <phase_3+0xa9>   

 8048c8f:       e8 c6 09 00 00          call   804965a <explode_bomb>

 8048c94:       c9                      leave
 8048c95:       c3                      ret

首先看到sscanf@plt我们知道要格式化参数了,上方有一个地址,我们看一下地址的内容

这个是sscanf的参数,说明我们将会格式化两个数组。
然后我们对返回结果进行判断,是否大于>1,也就是我们必须输出2个以上数字,超出2的数字在格式化的时候会被忽略。
之后我们对第一个参数进行的判断,第一个限制条件 第一个参数 args_1<=7
8048c44处进行了无条件转移,我们看一下eax存的什么,当输入4的时候

转换16进制为0x8048c5f,跳转之后,我们对一个变量【-0x8(%ebp)】进行了一些了操作,最后结果为-461
接着我们我们又对参数进行了判断,第二个条件,args_1<=5
然后判断第二个参数args_2和【-0x8(%ebp)】是否相等,在args_1==4时,其为-461。
其他的可行解相同逻辑,不在展开。

phase_4

08048cca <phase_4>:
 8048cca:       55                      push   %ebp
 8048ccb:       89 e5                   mov    %esp,%ebp
 8048ccd:       83 ec 28                sub    $0x28,%esp
 8048cd0:       8d 45 f4                lea    -0xc(%ebp),%eax 
 8048cd3:       89 44 24 08             mov    %eax,0x8(%esp)
 8048cd7:       c7 44 24 04 b0 99 04    movl   $0x80499b0,0x4(%esp) //"%d"
 8048cde:       08
 8048cdf:       8b 45 08                mov    0x8(%ebp),%eax
 8048ce2:       89 04 24                mov    %eax,(%esp)
 8048ce5:       e8 7e fb ff ff          call   8048868 <sscanf@plt>
 8048cea:       89 45 fc                mov    %eax,-0x4(%ebp)
 8048ced:       83 7d fc 01             cmpl   $0x1,-0x4(%ebp)
 8048cf1:       75 07                   jne    8048cfa <phase_4+0x30>  //判断是否格式化一个数字
 8048cf3:       8b 45 f4                mov    -0xc(%ebp),%eax  //eax=输入参数
 8048cf6:       85 c0                   test   %eax,%eax 
 8048cf8:       7f 05                   jg     8048cff <phase_4+0x35> //是否大于0

 8048cfa:       e8 5b 09 00 00          call   804965a <explode_bomb>

 8048cff:       8b 45 f4                mov    -0xc(%ebp),%eax //参数
 8048d02:       89 04 24                mov    %eax,(%esp)
 8048d05:       e8 8c ff ff ff          call   8048c96 <func4> 
 8048d0a:       89 45 f8                mov    %eax,-0x8(%ebp) 
 8048d0d:       81 7d f8 c1 f6 57 00    cmpl   $0x57f6c1,-0x8(%ebp)
 8048d14:       74 05                   je     8048d1b <phase_4+0x51>
 8048d16:       e8 3f 09 00 00          call   804965a <explode_bomb>

 8048d1b:       c9                      leave
 8048d1c:       c3                      ret

有了上面的经验,我们又看到了sscanf,看一下内存地址中的数据

这次我们只需要一个数字,然后判断格式化是否成功。
限制参数>0
接下来调用了一个函数,func4,然后用返回值和0x57f6c1进行比较。

接下来我们看func4

 08048c96 <func4>:
 8048c96:       55                      push   %ebp
 8048c97:       89 e5                   mov    %esp,%ebp
 8048c99:       83 ec 08                sub    $0x8,%esp
 8048c9c:       83 7d 08 00             cmpl   $0x0,0x8(%ebp)
 8048ca0:       7f 09                   jg     8048cab <func4+0x15>  //>0
 8048ca2:       c7 45 fc 01 00 00 00    movl   $0x1,-0x4(%ebp) //
 8048ca9:       eb 1a                   jmp    8048cc5 <func4+0x2f>
//参数>0
 8048cab:       8b 45 08                mov    0x8(%ebp),%eax  //参数
 8048cae:       48                      dec    %eax //参数--
 8048caf:       89 04 24                mov    %eax,(%esp)
 8048cb2:       e8 df ff ff ff          call   8048c96 <func4> //递归
 8048cb7:       89 c2                   mov    %eax,%edx //
 8048cb9:       89 d0                   mov    %edx,%eax  //
 8048cbb:       c1 e0 03                shl    $0x3,%eax // 参数左移3位 
 8048cbe:       89 c1                   mov    %eax,%ecx //
 8048cc0:       29 d1                   sub    %edx,%ecx //左移三位结果-原参数,等效x7
 8048cc2:       89 4d fc                mov    %ecx,-0x4(%ebp) 
//参数<=0
 8048cc5:       8b 45 fc                mov    -0x4(%ebp),%eax //递归退出 
 8048cc8:       c9                      leave
 8048cc9:       c3                      ret

这是一个递归函数

int fun4(int num){
  if(num>0){
  num--
  res=fun4(num)
  res*=7
  return res
}
return 1
}

也就是func4(n)带条7*n,0x57f6c1=7^8。即,结果为8

phase5

08048d1d <phase_5>:
 8048d1d:       55                      push   %ebp
 8048d1e:       89 e5                   mov    %esp,%ebp
 8048d20:       83 ec 18                sub    $0x18,%esp
 8048d23:       8b 45 08                mov    0x8(%ebp),%eax
 8048d26:       89 04 24                mov    %eax,(%esp)
 8048d29:       e8 3b 03 00 00          call   8049069 <string_length>
 8048d2e:       89 45 fc                mov    %eax,-0x4(%ebp)
 8048d31:       83 7d fc 06             cmpl   $0x6,-0x4(%ebp)
 8048d35:       74 05                   je     8048d3c <phase_5+0x1f>
 8048d37:       e8 1e 09 00 00          call   804965a <explode_bomb>

 8048d3c:       c7 45 f8 00 00 00 00    movl   $0x0,-0x8(%ebp) //sum
 8048d43:       c7 45 f4 00 00 00 00    movl   $0x0,-0xc(%ebp) // i
 8048d4a:       eb 1c                   jmp    8048d68 <phase_5+0x4b>

 8048d4c:       8b 45 f4                mov    -0xc(%ebp),%eax  //eax=0
 8048d4f:       03 45 08                add    0x8(%ebp),%eax //eax直线输入的字符串的char
 8048d52:       0f b6 00                movzbl (%eax),%eax //0x00000061    //零扩展 > unsigned int 
 8048d55:       0f be c0                movsbl %al,%eax //0x00000061    //al是eax的低8位,符号扩展 > int
 8048d58:       83 e0 0f                and    $0xf,%eax //低4位
 8048d5b:       8b 04 85 c0 a5 04 08    mov    0x804a5c0(,%eax,4),%eax //arr[i]
 8048d62:       01 45 f8                add    %eax,-0x8(%ebp) //sum+arr[i]
 8048d65:       ff 45 f4                incl   -0xc(%ebp) / i++

 8048d68:       83 7d f4 05             cmpl   $0x5,-0xc(%ebp)
 8048d6c:       7e de                   jle    8048d4c <phase_5+0x2f>
 8048d6e:       83 7d f8 32             cmpl   $0x32,-0x8(%ebp)  //sum=50
 8048d72:       74 05                   je     8048d79 <phase_5+0x5c>
 8048d74:       e8 e1 08 00 00          call   804965a <explode_bomb>

 8048d79:       c9                      leave
 8048d7a:       c3                      ret

从<string_length>和下面判断,得到我们需要传入6个字符,接下来便利6个字符,将字符的最低8位作符号扩展,然后再将最低4位作为数组的下标【index】,计算sum+=arr[index]。最后sum=50就能解除炸弹。
其中arr为长16数组(超出16也没有意义)

接下来我们就需要凑数了,10+10+10+10+1+9是合适的,对照ascii表找到合适的就可以。此处提供一个aaaacf

phase_6

这是最长的一段代码,也是最难的,一眼看过去众多跳转至零,也就是其中有可能有for和if

08048d7b <phase_6>:
 8048d7b:       55                      push   %ebp
 8048d7c:       89 e5                   mov    %esp,%ebp
 8048d7e:       83 ec 48                sub    $0x48,%esp
 8048d81:       c7 45 f0 3c a6 04 08    movl   $0x804a63c,-0x10(%ebp)
 8048d88:       8d 45 d8                lea    -0x28(%ebp),%eax
 8048d8b:       89 44 24 04             mov    %eax,0x4(%esp)
 8048d8f:       8b 45 08                mov    0x8(%ebp),%eax
 8048d92:       89 04 24                mov    %eax,(%esp)  //设置参数
 8048d95:       e8 66 02 00 00          call   8049000 <read_six_numbers>
 8048d9a:       c7 45 f8 00 00 00 00    movl   $0x0,-0x8(%ebp) // i=0
 8048da1:       eb 48                   jmp    8048deb <phase_6+0x70>  -->l6
l1
 8048da3:       8b 45 f8                mov    -0x8(%ebp),%eax
 8048da6:       8b 44 85 d8             mov    -0x28(%ebp,%eax,4),%eax //eax=arr[i]
 8048daa:       85 c0                   test   %eax,%eax 
 8048dac:       7e 0c                   jle    8048dba <phase_6+0x3f>  // <=0  -->l2
 8048dae:       8b 45 f8                mov    -0x8(%ebp),%eax
 8048db1:       8b 44 85 d8             mov    -0x28(%ebp,%eax,4),%eax //eax=arr[i]
 8048db5:       83 f8 06                cmp    $0x6,%eax 
 8048db8:       7e 05                   jle    8048dbf <phase_6+0x44> //<=6 -->l3
l2
 8048dba:       e8 9b 08 00 00          call   804965a <explode_bomb>
l3
 8048dbf:       8b 45 f8                mov    -0x8(%ebp),%eax
 8048dc2:       40                      inc    %eax //i++
 8048dc3:       89 45 fc                mov    %eax,-0x4(%ebp)
 8048dc6:       eb 1a                   jmp    8048de2 <phase_6+0x67> -->l5
l4  //
 8048dc8:       8b 45 f8                mov    -0x8(%ebp),%eax  //0
 8048dcb:       8b 54 85 d8             mov    -0x28(%ebp,%eax,4),%edx //arr[i]
 8048dcf:       8b 45 fc                mov    -0x4(%ebp),%eax //1
 8048dd2:       8b 44 85 d8             mov    -0x28(%ebp,%eax,4),%eax
 8048dd6:       39 c2                   cmp    %eax,%edx
 8048dd8:       75 05                   jne    8048ddf <phase_6+0x64>
 8048dda:       e8 7b 08 00 00          call   804965a <explode_bomb>
 8048ddf:       ff 45 fc                incl   -0x4(%ebp)
 l5
 8048de2:       83 7d fc 05             cmpl   $0x5,-0x4(%ebp)
 8048de6:       7e e0                   jle    8048dc8 <phase_6+0x4d>  -->l4
 8048de8:       ff 45 f8                incl   -0x8(%ebp)
l6
 8048deb:       83 7d f8 05             cmpl   $0x5,-0x8(%ebp)   // 5次
 8048def:       7e b2                   jle    8048da3 <phase_6+0x28>   -->l1
 8048df1:       c7 45 f8 00 00 00 00    movl   $0x0,-0x8(%ebp)
 8048df8:       eb 34                   jmp    8048e2e <phase_6+0xb3>  -->l10
l7
 8048dfa:       8b 45 f0                mov    -0x10(%ebp),%eax
 8048dfd:       89 45 f4                mov    %eax,-0xc(%ebp)
 8048e00:       c7 45 fc 01 00 00 00    movl   $0x1,-0x4(%ebp)
 8048e07:       eb 0c                   jmp    8048e15 <phase_6+0x9a>  -->l9
l8
 8048e09:       8b 45 f4                mov    -0xc(%ebp),%eax
 8048e0c:       8b 40 08                mov    0x8(%eax),%eax
 8048e0f:       89 45 f4                mov    %eax,-0xc(%ebp)
 8048e12:       ff 45 fc                incl   -0x4(%ebp)
l9
 8048e15:       8b 45 f8                mov    -0x8(%ebp),%eax
 8048e18:       8b 44 85 d8             mov    -0x28(%ebp,%eax,4),%eax  
 8048e1c:       3b 45 fc                cmp    -0x4(%ebp),%eax
 8048e1f:       7f e8                   jg     8048e09 <phase_6+0x8e>   -->l8
 8048e21:       8b 55 f8                mov    -0x8(%ebp),%edx
 8048e24:       8b 45 f4                mov    -0xc(%ebp),%eax
 8048e27:       89 44 95 c0             mov    %eax,-0x40(%ebp,%edx,4)
 8048e2b:       ff 45 f8                incl   -0x8(%ebp)
l10
 8048e2e:       83 7d f8 05             cmpl   $0x5,-0x8(%ebp)
 8048e32:       7e c6                   jle    8048dfa <phase_6+0x7f>  -->l7
 8048e34:       8b 45 c0                mov    -0x40(%ebp),%eax
 8048e37:       89 45 f0                mov    %eax,-0x10(%ebp)
 8048e3a:       8b 45 f0                mov    -0x10(%ebp),%eax
 8048e3d:       89 45 f4                mov    %eax,-0xc(%ebp)
 8048e40:       c7 45 f8 01 00 00 00    movl   $0x1,-0x8(%ebp)
 8048e47:       eb 19                   jmp    8048e62 <phase_6+0xe7>  -->l12
l11
 8048e49:       8b 45 f8                mov    -0x8(%ebp),%eax
 8048e4c:       8b 54 85 c0             mov    -0x40(%ebp,%eax,4),%node2
 8048e50:       8b 45 f4                mov    -0xc(%ebp),%eax  //nod1
 8048e53:       89 50 08                mov    %edx,0x8(%eax) 
 8048e56:       8b 45 f4                mov    -0xc(%ebp),%eax
 8048e59:       8b 40 08                mov    0x8(%eax),%eax
 8048e5c:       89 45 f4                mov    %eax,-0xc(%ebp)
 8048e5f:       ff 45 f8                incl   -0x8(%ebp)
l12
 8048e62:       83 7d f8 05             cmpl   $0x5,-0x8(%ebp)
 8048e66:       7e e1                   jle    8048e49 <phase_6+0xce>  -->l11
 8048e68:       8b 45 f4                mov    -0xc(%ebp),%eax
 8048e6b:       c7 40 08 00 00 00 00    movl   $0x0,0x8(%eax)
 8048e72:       8b 45 f0                mov    -0x10(%ebp),%eax
 8048e75:       89 45 f4                mov    %eax,-0xc(%ebp)
 8048e78:       c7 45 f8 00 00 00 00    movl   $0x0,-0x8(%ebp)
 8048e7f:       eb 22                   jmp    8048ea3 <phase_6+0x128>  -->l15
l13
 8048e81:       8b 45 f4                mov    -0xc(%ebp),%eax
 8048e84:       8b 10                   mov    (%eax),%edx
 8048e86:       8b 45 f4                mov    -0xc(%ebp),%eax
 8048e89:       8b 40 08                mov    0x8(%eax),%eax
 8048e8c:       8b 00                   mov    (%eax),%eax
 8048e8e:       39 c2                   cmp    %eax,%edx
 8048e90:       7d 05                   jge    8048e97 <phase_6+0x11c> --l14
 8048e92:       e8 c3 07 00 00          call   804965a <explode_bomb>
l14
 8048e97:       8b 45 f4                mov    -0xc(%ebp),%eax
 8048e9a:       8b 40 08                mov    0x8(%eax),%eax
 8048e9d:       89 45 f4                mov    %eax,-0xc(%ebp)
 8048ea0:       ff 45 f8                incl   -0x8(%ebp)
l15
 8048ea3:       83 7d f8 04             cmpl   $0x4,-0x8(%ebp)
 8048ea7:       7e d8                   jle    8048e81 <phase_6+0x106>  -->l13
 8048ea9:       c9                      leave
 8048eaa:       c3                      ret


首先是两个循环嵌套,对输入的数字最判断,1-6之间(包含),不能有重复元素

8048e47开始我们进入了新的循环 l11为其循环体,参数倒过来倒过去看不清在干啥。先看看eax和edx中存了啥


eax地址指向一个node,那我们可以合理猜测这步在构建链表。
我们跳出这个循环,直接看他构建好的链表什么样子,记着 0x804a63c 是node1地址.在8048e68打上断点查看

明显能看出第三列是链接地址。前面是数据

接着就进入下一个循环,l13是其循环体
比较的是两个节点前4个字节的大小,并且要保证 前一个节点大于等于后一个
节点数据如下

0x804a63c <node1>:	0x00000234	0x00000001	0x0804a630	0x000003e9
0x804a630 <node2>:	0x00000180	0x00000002	0x0804a624	0x00000234
0x804a624 <node3>:	0x00000312	0x00000003	0x0804a618	0x00000180
0x804a618 <node4>:	0x00000189	0x00000004	0x0804a60c	0x00000312
0x804a60c <node5>:	0x0000011e	0x00000005	0x0804a600	0x00000189
0x804a600 <node6>:	0x00000189	0x00000006	0x00000000	0x0000011e

重新排列是其满足条件,3,1,4,6,2,5 或者3,1,6,4,2,5

secret_phase

这部分在bomb.c中做出来提示,我们在汇编中在phase_6下方有个func7。这个显然是有用的。
向上追溯发现在<secret_phase>调用,<secret_phase>在<phase_defused>中调用

先看<phase_defused>

08049684 <phase_defused>: 
 8049684:       55                      push   %ebp
 8049685:       89 e5                   mov    %esp,%ebp
 8049687:       83 ec 78                sub    $0x78,%esp
 804968a:       a1 4c a8 04 08          mov    0x804a84c,%eax  //
 804968f:       83 f8 06                cmp    $0x6,%eax             // 输入的行数,也就是我们完成6个才能开启
 8049692:       75 6e                   jne    8049702 <phase_defused+0x7e>
 8049694:       b8 50 a9 04 08          mov    $0x804a950,%eax   //0x804a950 对应phase_4输入
 8049699:       89 c2                   mov    %eax,%edx
 804969b:       8d 45 ac                lea    -0x54(%ebp),%eax
 804969e:       89 44 24 0c             mov    %eax,0xc(%esp)
 80496a2:       8d 45 a8                lea    -0x58(%ebp),%eax
 80496a5:       89 44 24 08             mov    %eax,0x8(%esp)
 80496a9:       c7 44 24 04 50 9e 04    movl   $0x8049e50,0x4(%esp)   //"%d %s" 
 80496b0:       08
 80496b1:       89 14 24                mov    %edx,(%esp)
 80496b4:       e8 af f1 ff ff          call   8048868 <sscanf@plt>
 80496b9:       89 45 fc                mov    %eax,-0x4(%ebp)
 80496bc:       83 7d fc 02             cmpl   $0x2,-0x4(%ebp)
 80496c0:       75 34                   jne    80496f6 <phase_defused+0x72>
 80496c2:       c7 44 24 04 56 9e 04    movl   $0x8049e56,0x4(%esp)   //"austinpowers"
 80496c9:       08
 80496ca:       8d 45 ac                lea    -0x54(%ebp),%eax
 80496cd:       89 04 24                mov    %eax,(%esp)
 80496d0:       e8 be f9 ff ff          call   8049093 <strings_not_equal>
 80496d5:       85 c0                   test   %eax,%eax
 80496d7:       75 1d                   jne    80496f6 <phase_defused+0x72>
 80496d9:       c7 04 24 64 9e 04 08    movl   $0x8049e64,(%esp)
 80496e0:       e8 e3 f0 ff ff          call   80487c8 <puts@plt>
 80496e5:       c7 04 24 8c 9e 04 08    movl   $0x8049e8c,(%esp)
 80496ec:       e8 d7 f0 ff ff          call   80487c8 <puts@plt>
 80496f1:       e8 23 f8 ff ff          call   8048f19 <secret_phase>
 80496f6:       c7 04 24 c4 9e 04 08    movl   $0x8049ec4,(%esp)
 80496fd:       e8 c6 f0 ff ff          call   80487c8 <puts@plt>
 8049702:       c9                      leave
 8049703:       c3                      ret

其中有参数检查我们输入的行数,等于6,也就解决了6个问题才能触发这个secret。
然后我们打印0x804a950内容,会发现他和phase_4的输入是相同。
根据下面的格式化,我们确定pahse_4需要输入两个字符,一个数字一个字符串
且字符串等于austinpowers,保存在了0x8049e56中。
满足这个条件之后我们才能进入<secret_phase>
再看<secret_phase>

 08048f19 <secret_phase>:
 8048f19:       55                      push   %ebp
 8048f1a:       89 e5                   mov    %esp,%ebp
 8048f1c:       83 ec 18                sub    $0x18,%esp
 8048f1f:       e8 aa 03 00 00          call   80492ce <read_line>
 8048f24:       89 45 f4                mov    %eax,-0xc(%ebp)
 8048f27:       8b 45 f4                mov    -0xc(%ebp),%eax
 8048f2a:       89 04 24                mov    %eax,(%esp)
 8048f2d:       e8 26 f9 ff ff          call   8048858 <atoi@plt>  //atoi 说明我们需要输入一个数
 8048f32:       89 45 f8                mov    %eax,-0x8(%ebp)
 8048f35:       83 7d f8 00             cmpl   $0x0,-0x8(%ebp)
 8048f39:       7e 09                   jle    8048f44 <secret_phase+0x2b>  //输入参数要>0

 8048f3b:       81 7d f8 e9 03 00 00    cmpl   $0x3e9,-0x8(%ebp)   //输入参数要<=1001
 8048f42:       7e 05                   jle    8048f49 <secret_phase+0x30>

 8048f44:       e8 11 07 00 00          call   804965a <explode_bomb>

 8048f49:       8b 45 f8                mov    -0x8(%ebp),%eax
 8048f4c:       89 44 24 04             mov    %eax,0x4(%esp)     //输入参数
 8048f50:       c7 04 24 f0 a6 04 08    movl   $0x804a6f0,(%esp)  //<n1>类型,应该是一个结构体
 8048f57:       e8 4f ff ff ff          call   8048eab <fun7>
 8048f5c:       89 45 fc                mov    %eax,-0x4(%ebp)
 8048f5f:       83 7d fc 07             cmpl   $0x7,-0x4(%ebp)  //fun7返回结果要等于7
 8048f63:       74 05                   je     8048f6a <secret_phase+0x51>

 8048f65:       e8 f0 06 00 00          call   804965a <explode_bomb>

 8048f6a:       c7 04 24 b4 99 04 08    movl   $0x80499b4,(%esp)
 8048f71:       e8 52 f8 ff ff          call   80487c8 <puts@plt>
 8048f76:       e8 09 07 00 00          call   8049684 <phase_defused>
 8048f7b:       c9                      leave
 8048f7c:       c3                      ret

解释写到注释中,也就是我们还需要输入一行,且是一个数,大于0小于等于1001。
将这个数和n1结构体传入fun7,判断返回结果是否是7。
而且这个结构体是个二叉树类型,能明显看出有两个地址

最后看fun7

 08048eab <fun7>:
 8048eab:       55                      push   %ebp
 8048eac:       89 e5                   mov    %esp,%ebp
 8048eae:       83 ec 0c                sub    $0xc,%esp
 8048eb1:       83 7d 08 00             cmpl   $0x0,0x8(%ebp) 
 8048eb5:       75 09                   jne    8048ec0 <fun7+0x15>   
 8048eb7:       c7 45 fc ff ff ff ff    movl   $0xffffffff,-0x4(%ebp)  //return -1
 8048ebe:       eb 54                   jmp    8048f14 <fun7+0x69>

 8048ec0:       8b 45 08                mov    0x8(%ebp),%eax
 8048ec3:       8b 00                   mov    (%eax),%eax  
 8048ec5:       3b 45 0c                cmp    0xc(%ebp),%eax  
 8048ec8:       7e 1c                   jle    8048ee6 <fun7+0x3b>
 8048eca:       8b 45 08                mov    0x8(%ebp),%eax  
 8048ecd:       8b 50 04                mov    0x4(%eax),%edx  
 8048ed0:       8b 45 0c                mov    0xc(%ebp),%eax
 8048ed3:       89 44 24 04             mov    %eax,0x4(%esp)
 8048ed7:       89 14 24                mov    %edx,(%esp)  
 8048eda:       e8 cc ff ff ff          call   8048eab <fun7>
 8048edf:       01 c0                   add    %eax,%eax  //  return res*2
 8048ee1:       89 45 fc                mov    %eax,-0x4(%ebp)
 8048ee4:       eb 2e                   jmp    8048f14 <fun7+0x69>

 8048ee6:       8b 45 08                mov    0x8(%ebp),%eax
 8048ee9:       8b 00                   mov    (%eax),%eax
 8048eeb:       3b 45 0c                cmp    0xc(%ebp),%eax
 8048eee:       75 09                   jne    8048ef9 <fun7+0x4e>
 8048ef0:       c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%ebp)// return 0
 8048ef7:       eb 1b                   jmp    8048f14 <fun7+0x69>

 8048ef9:       8b 45 08                mov    0x8(%ebp),%eax
 8048efc:       8b 50 08                mov    0x8(%eax),%edx
 8048eff:       8b 45 0c                mov    0xc(%ebp),%eax
 8048f02:       89 44 24 04             mov    %eax,0x4(%esp)
 8048f06:       89 14 24                mov    %edx,(%esp)
 8048f09:       e8 9d ff ff ff          call   8048eab <fun7>
 8048f0e:       01 c0                   add    %eax,%eax
 8048f10:       40                      inc    %eax  // return res*2+1
 8048f11:       89 45 fc                mov    %eax,-0x4(%ebp)

 8048f14:       8b 45 fc                mov    -0x4(%ebp),%eax   
 8048f17:       c9                      leave
 8048f18:       c3                      ret

这又是一个递归函数

 int fun(node,c){
    if node==0{
        return -1
    }else{
        if node=c{
            return 0
        }
        if node<c{
            res=d(node.right,c)
            return res*2+1
        }
        if node >c {
            res=d(node.left,c)
            return 2*res
        }
    }
 }

然后我们需要画出上面n1为根的二叉树

可以看出1001是符合条件的

posted @ 2023-04-18 23:29  北方Cc  阅读(163)  评论(0)    收藏  举报