Datalab实验_Bomblab

Datalab实验_Bomblab

1.phase_1(字符串比较)

  • 思路:首先在gdb中输入disassemble phase_1:
   0x08048ae0 <+0>:     push   %ebp// 入栈
   0x08048ae1 <+1>:     mov    %esp,%ebp// 形成帧底 
   0x08048ae3 <+3>:     sub    $0x18,%esp// esp - 24 生成栈帧
   0x08048ae6 <+6>:     movl   $0x804a128,0x4(%esp)// 将立即数存放在 esp+4 的位置
   0x08048aee <+14>:    mov    0x8(%ebp),%eax
   0x08048af1 <+17>:    mov    %eax,(%esp)// 准备入口参数
   0x08048af4 <+20>:    call   0x8048f22 er// 调用函数 
   0x08048af9 <+25>:    test   %eax,%eax// 设置标志位 eax与自己按位相与 判断是否等于0
   0x08048afb <+27>:    je     0x8048b02 <phase_1+34>// 根据标志位判断是否跳转 若ZF == 0 则跳过引爆炸弹的程序
   0x08048afd <+29>:    call   0x8049145 <explode_bomb>// 炸弹引爆
   0x08048b02 <+34>:    leave// 退栈
   0x08048b03 <+35>:    ret// 返回地址

画出调用函数strings_not_equal之前phase_1内部的栈帧情况:

+--------------------------+
|         其他              |(底部)
+--------------------------+
|        输入的参数          |通过eax转移到%ebp + 0x8的地方
+--------------------------+
|       返回值(%eax)        |
+--------------------------+
|                          |<———— ebp
+--------------------------+
|        ... ...           |
+--------------------------+
|       $0x804a128         |
+--------------------------+
|       %ebp + 0x8         |<———— esp
+--------------------------+

而函数strings_not_equal的功能是判断两个参数是是否相等,所以只需要输入$0x804a128中对应的内容即可
在这里插入图片描述

2.phase_2(循环)

  • 思路:
    首先调出phase_2的反汇编:
   0x08048b04 <+0>:     push   %ebp
   0x08048b05 <+1>:     mov    %esp,%ebp
   0x08048b07 <+3>:     push   %esi
   0x08048b08 <+4>:     push   %ebx // esi和ebx为调用者保存寄存器,因为后面的循环用到了者两个寄存器,因此在这里需要压栈保存
   0x08048b09 <+5>:     sub    $0x30,%esp///esp-48 生成栈帧
   0x08048b0c <+8>:     lea    -0x20(%ebp),%eax// 加载有效地址 
   0x08048b0f <+11>:    mov    %eax,0x4(%esp)
   0x08048b13 <+15>:    mov    0x8(%ebp),%eax
   0x08048b16 <+18>:    mov    %eax,(%esp)// 准备入口参数
   0x08048b19 <+21>:    call   0x8049187 <read_six_numbers>// 调用函数读入6个数字
   0x08048b1e <+26>:    cmpl   $0x1,-0x20(%ebp)// 比较立即数0x1与ebp - 32的值   第一个数存放在ebp - 32的位置 应该是0x1
   0x08048b22 <+30>:    je     0x8048b42 <phase_2+62>// 如果上述比较结果相等(ZF==1)跳转
   0x08048b24 <+32>:    call   0x8049145 <explode_bomb>// 引爆炸弹
   0x08048b29 <+37>:    jmp    0x8048b42 <phase_2+62>// 无条件转移
   0x08048b2b <+39>:    mov    -0x4(%ebx),%eax
   0x08048b2e <+42>:    add    %eax,%eax
   0x08048b30 <+44>:    cmp    %eax,(%ebx)
   0x08048b32 <+46>:    je     0x8048b39 <phase_2+53>//  如果上述比较结果相等(ZF==1)跳转
   0x08048b34 <+48>:    call   0x8049145 <explode_bomb>// 引爆炸弹
   0x08048b39 <+53>:    add    $0x4,%ebx
   0x08048b3c <+56>:    cmp    %esi,%ebx// 比较esi与ebx寄存器的值
   0x08048b3e <+58>:    jne    0x8048b2b <phase_2+39>// 如果上述比较结果不相等(ZF==0)跳转
   0x08048b40 <+60>:    jmp    0x8048b4a <phase_2+70>// 无条件转移
   0x08048b42 <+62>:    lea    -0x1c(%ebp),%ebx// 赋ebx寄存器的初值
   0x08048b45 <+65>:    lea    -0x8(%ebp),%esi// 赋esi寄存器的初值
   0x08048b48 <+68>:    jmp    0x8048b2b <phase_2+39>// 无条件转移
   0x08048b4a <+70>:    add    $0x30,%esp
   0x08048b4d <+73>:    pop    %ebx
   0x08048b4e <+74>:    pop    %esi
   0x08048b4f <+75>:    pop    %ebp
   0x08048b50 <+76>:    ret

将读入的6个数字设为数组num[6]中的数,则在调用函数read_six_numbers后的栈帧为:

      +--------------------------+
ebp   |                          |
      +--------------------------+                                      
ebp-4 |                          |
      +--------------------------+
ebp-8 |                          |
      +--------------------------+
ebp-12|num[6]                    |<———— esi的初值
      +--------------------------+
ebp-16|num[5]                    |
      +--------------------------+
ebp-20|num[4]                    |
      +--------------------------+
ebp-20|num[3]                    |
      +--------------------------+
ebp-24|num[2]                    |
      +--------------------------+
ebp-28|num[1]                    |<———— ebx 初值
      +--------------------------+
ebp-32|num[0]                 	 |<———— eax 初值
      +--------------------------+
      |         ... ..           |
      +--------------------------+
esp   |                          |
      +--------------------------+

调用函数后

	0x08048b1e <+26>:    cmpl   $0x1,-0x20(%ebp)// 比较立即数0x1与ebp - 32的值   第一个数存放在ebp - 32的位置 应该是0x1
	0x08048b22 <+30>:    je     0x8048b42 <phase_2+62>// 如果上述比较结果相等(ZF==1)跳转

判断出num[0] = 0x1

   0x08048b42 <+62>:    lea    -0x1c(%ebp),%ebx// 赋ebx寄存器的初值
   0x08048b45 <+65>:    lea    -0x8(%ebp),%esi// 赋esi寄存器的初值

将ebx与esi赋初值(esi的地址相当于num[6],为了确保只取了6个数,防止溢出)

   0x08048b2b <+39>:    mov    -0x4(%ebx),%eax
   0x08048b2e <+42>:    add    %eax,%eax
   0x08048b30 <+44>:    cmp    %eax,(%ebx)
   0x08048b32 <+46>:    je     0x8048b39 <phase_2+53>//  如果上述比较结果相等(ZF==1)跳转
   0x08048b34 <+48>:    call   0x8049145 <explode_bomb>// 引爆炸弹
   0x08048b39 <+53>:    add    $0x4,%ebx
   0x08048b3c <+56>:    cmp    %esi,%ebx// 比较esi与ebx寄存器的值
   0x08048b3e <+58>:    jne    0x8048b2b <phase_2+39>// 如果上述比较结果不相等(ZF==0)跳转

当第一次循环的时候ebx=num[1],eax=num[0],为了满足46行的条件判断je 0x8048b39 <phase_2+53>必须有num[1] = 2num[0],然后ebx+4直到ebx == esi结束,所以6个数后一个是前一个的2倍,即:

for(int i = 0; i < 5; i++)
    num[i + 1] = num[i] * 2;// num[0] == 1

最终结果是:

1 2 4 8 16 32

3.phase_3(条件/分支:含switch语句)

  • 思路:
    调出phase_3的反汇编:
   0x08048b51 <+0>:     push   %ebp
   0x08048b52 <+1>:     mov    %esp,%ebp
   0x08048b54 <+3>:     sub    $0x28,%esp
   0x08048b57 <+6>:     lea    -0x10(%ebp),%eax
   0x08048b5a <+9>:     mov    %eax,0xc(%esp)
   0x08048b5e <+13>:    lea    -0xc(%ebp),%eax
   0x08048b61 <+16>:    mov    %eax,0x8(%esp)
   0x08048b65 <+20>:    movl   $0x804a3d1,0x4(%esp)
   0x08048b6d <+28>:    mov    0x8(%ebp),%eax
   0x08048b70 <+31>:    mov    %eax,(%esp)
   0x08048b73 <+34>:    call   0x80487d0 <__isoc99_sscanf@plt>
   0x08048b78 <+39>:    cmp    $0x1,%eax
   0x08048b7b <+42>:    jg     0x8048b82 <phase_3+49>
   0x08048b7d <+44>:    call   0x8049145 <explode_bomb>
   0x08048b82 <+49>:    cmpl   $0x7,-0xc(%ebp)
   0x08048b86 <+53>:    ja     0x8048bc3 <phase_3+114> 
   0x08048b88 <+55>:    mov    -0xc(%ebp),%eax
   0x08048b8b <+58>:    jmp    *0x804a1a0(,%eax,4)
   0x08048b92 <+65>:    mov    $0x164,%eax
   0x08048b97 <+70>:    jmp    0x8048bd4 <phase_3+131>
   0x08048b99 <+72>:    mov    $0x2a2,%eax
   0x08048b9e <+77>:    jmp    0x8048bd4 <phase_3+131>
   0x08048ba0 <+79>:    mov    $0x255,%eax
   0x08048ba5 <+84>:    jmp    0x8048bd4 <phase_3+131>
   0x08048ba7 <+86>:    mov    $0x77,%eax
   0x08048bac <+91>:    jmp    0x8048bd4 <phase_3+131>
   0x08048bae <+93>:    mov    $0x30e,%eax
   0x08048bb3 <+98>:    jmp    0x8048bd4 <phase_3+131>
   0x08048bb5 <+100>:   mov    $0x271,%eax
   0x08048bba <+105>:   jmp    0x8048bd4 <phase_3+131>
   0x08048bbc <+107>:   mov    $0x389,%eax
   0x08048bc1 <+112>:   jmp    0x8048bd4 <phase_3+131>
   0x08048bc3 <+114>:   call   0x8049145 <explode_bomb>
   0x08048bc8 <+119>:   mov    $0x0,%eax
   0x08048bcd <+124>:   jmp    0x8048bd4 <phase_3+131>
   0x08048bcf <+126>:   mov    $0xa4,%eax
   0x08048bd4 <+131>:   cmp    -0x10(%ebp),%eax
   0x08048bd7 <+134>:   je     0x8048bde <phase_3+141>
   0x08048bd9 <+136>:   call   0x8049145 <explode_bomb>
   0x08048bde <+141>:   leave
   0x08048bdf <+142>:   ret

在第20行有命令:movl $0x804a3d1,0x4(%esp),将一个立即数送入到esp寄存器中,所以查看立即数代表的值:在这里插入图片描述
说明需要输入两个int型的字符num_1,num_2的分别存放在esp+0x8和esp+0xc处

   0x08048b78 <+39>:    cmp    $0x1,%eax
   0x08048b82 <+49>:    cmpl   $0x7,-0xc(%ebp)
   0x08048b86 <+53>:    ja     0x8048bc3 <phase_3+114> 

说明输入数的个数为2个,而且需要小于等于0x7才行

   0x08048b88 <+55>:    mov    -0xc(%ebp),%eax
   0x08048b8b <+58>:    jmp    *0x804a1a0(,%eax,4)

这段代码是将esp-0xc的值存放到eax中,然后跳转到eax*4 + *0x804a1a0的地址处,所以我查看了0x804a1a0的内容:
在这里插入图片描述
跳转对应地址的代码为:

   0x08048b97 <+70>:    jmp    0x8048bd4 <phase_3+131>
   0x08048b99 <+72>:    mov    $0x2a2,%eax
   0x08048b9e <+77>:    jmp    0x8048bd4 <phase_3+131>
   0x08048ba0 <+79>:    mov    $0x255,%eax
   0x08048ba5 <+84>:    jmp    0x8048bd4 <phase_3+131>
   0x08048ba7 <+86>:    mov    $0x77,%eax
   0x08048bac <+91>:    jmp    0x8048bd4 <phase_3+131>
   0x08048bae <+93>:    mov    $0x30e,%eax
   0x08048bb3 <+98>:    jmp    0x8048bd4 <phase_3+131>
   0x08048bb5 <+100>:   mov    $0x271,%eax
   0x08048bba <+105>:   jmp    0x8048bd4 <phase_3+131>
   0x08048bbc <+107>:   mov    $0x389,%eax
   0x08048bc1 <+112>:   jmp    0x8048bd4 <phase_3+131>
   0x08048bc3 <+114>:   call   0x8049145 <explode_bomb>
   0x08048bc8 <+119>:   mov    $0x0,%eax
   0x08048bcd <+124>:   jmp    0x8048bd4 <phase_3+131>
   0x08048bcf <+126>:   mov    $0xa4,%eax

所以这也是一个switch语句,参数就是eax里的值,整理下可以得到:

num_1    	num_2          eax     jmp      
0           0x164 = 356    0       0x08048b92
1           0xa4 = 164     1       0x08048bcf 
2           0x2a2 = 674    2       0x08048b99
3           0x255 = 597    3       0x08048ba0
4           0x77 = 119     4       0x08048ba7
5           0x30e = 782    5       0x08048bae
6           0x271 = 625    6       0x08048bb5
7           0x389 = 905    7       0x08048bbc

switch语句为 :

switch(num_1)
{
    case 0:
        if(num_2 != 356)	Boom();
        break;
	... ...  
}

4.phase_4(递归调用和栈)

  • 思路:
    调出phase_4的反汇编:
   0x08048c42 <+0>:     push   %ebp
   0x08048c43 <+1>:     mov    %esp,%ebp
   0x08048c45 <+3>:     sub    $0x28,%esp
   0x08048c48 <+6>:     lea    -0x10(%ebp),%eax
   0x08048c4b <+9>:     mov    %eax,0xc(%esp)// 将ebp-16处的地址赋给esp+12 num_2
   0x08048c4f <+13>:    lea    -0xc(%ebp),%eax
   0x08048c52 <+16>:    mov    %eax,0x8(%esp)// 将ebp-12处的地址赋给esp+8 num_1
   0x08048c56 <+20>:    movl   $0x804a3d1,0x4(%esp)
   0x08048c5e <+28>:    mov    0x8(%ebp),%eax
   0x08048c61 <+31>:    mov    %eax,(%esp)
   0x08048c64 <+34>:    call   0x80487d0 <__isoc99_sscanf@plt>
   0x08048c69 <+39>:    cmp    $0x2,%eax
   0x08048c6c <+42>:    jne    0x8048c74 <phase_4+50>// eax != 0x2
   0x08048c6e <+44>:    cmpl   $0xe,-0xc(%ebp)//比较ebp-12处的值与0xe(14)的大小 
   0x08048c72 <+48>:    jbe    0x8048c79 <phase_4+55>
   0x08048c74 <+50>:    call   0x8049145 <explode_bomb>
   0x08048c79 <+55>:    movl   $0xe,0x8(%esp)// 0xe(14)赋值给esp+8
   0x08048c81 <+63>:    movl   $0x0,0x4(%esp)// 0x0赋值给esp+4
   0x08048c89 <+71>:    mov    -0xc(%ebp),%eax// eax = num_1
   0x08048c8c <+74>:    mov    %eax,(%esp)// 准备参数
   0x08048c8f <+77>:    call   0x8048be0 <func4>// 调用递归函数
   0x08048c94 <+82>:    cmp    $0x4,%eax// eax为函数func4的返回值
   0x08048c97 <+85>:    jne    0x8048c9f <phase_4+93>// eax要等于0x4,否则引爆炸弹
   0x08048c99 <+87>:    cmpl   $0x4,-0x10(%ebp)
   0x08048c9d <+91>:    je     0x8048ca4 <phase_4+98>// -0x10(%ebp) == 0x4
   0x08048c9f <+93>:    call   0x8049145 <explode_bomb>
   0x08048ca4 <+98>:    leave
   0x08048ca5 <+99>:    ret

先查询第20行命令movl $0x804a3d1,0x4(%esp)中立即数:
在这里插入图片描述

   0x08048c69 <+39>:    cmp    $0x2,%eax
   0x08048c6c <+42>:    jne    0x8048c74 <phase_4+50>// eax != 0x2

所以我需要输入两个int型的数num_1, num_2

   0x08048c6e <+44>:    cmpl   $0xe,-0xc(%ebp)//比较ebp-12处的值与0xe(14)的大小 
   0x08048c72 <+48>:    jbe    0x8048c79 <phase_4+55>
   0x08048c99 <+87>:    cmpl   $0x4,-0x10(%ebp)
   0x08048c9d <+91>:    je     0x8048ca4 <phase_4+98>// -0x10(%ebp) == 0x4

这段代码确定了输入的第一个参数num_1需要小于14,第二个参数num_2为0x4

   0x08048c79 <+55>:    movl   $0xe,0x8(%esp)// 0xe(14)赋值给esp+8
   0x08048c81 <+63>:    movl   $0x0,0x4(%esp)// 0x0赋值给esp+4
   0x08048c89 <+71>:    mov    -0xc(%ebp),%eax// eax = num_1
   0x08048c8c <+74>:    mov    %eax,(%esp)// 准备参数
   0x08048c8f <+77>:    call   0x8048be0 <func4>// 调用递归函数
   0x08048c94 <+82>:    cmp    $0x4,%eax// eax为函数func4的返回值
   0x08048c97 <+85>:    jne    0x8048c9f <phase_4+93>// eax要等于0x4,否则引爆炸弹

调用递归函数func4,传入的参数依次为: num_1, 0, 14;而且需要在调用函数后eax的值等于4,所以函数的返回值应为4,所以我需要查看func4函数:

   0x8048be0 <func4>:   push   %ebp
   0x8048be1 <func4+1>: mov    %esp,%ebp
   0x8048be3 <func4+3>: push   %esi
   0x8048be4 <func4+4>: push   %ebx// ebx和esi是被调用保存寄存器
   0x8048be5 <func4+5>: sub    $0x10,%esp// 开栈
   0x8048be8 <func4+8>: mov    0x8(%ebp),%edx// ebp+8 赋值给 edx edx = 14 保存参数f_1
   0x8048beb <func4+11>:        mov    0xc(%ebp),%eax// 保存f_2 
   0x8048bee <func4+14>:        mov    0x10(%ebp),%ebx// 保存f_3
   0x8048bf1 <func4+17>:        mov    %ebx,%ecx// ecx寄存器其到一个展示保存结果的作用
   0x8048bf3 <func4+19>:        sub    %eax,%ecx// ecx -= eax 
   0x8048bf5 <func4+21>:        mov    %ecx,%esi
   0x8048bf7 <func4+23>:        shr    $0x1f,%esi// 逻辑右移31位 esi = ecx >> 31
   0x8048bfa <func4+26>:        add    %esi,%ecx// 
   0x8048bfc <func4+28>:        sar    %ecx//算数右移 没有参数默认移动一位 
   0x8048bfe <func4+30>:        add    %eax,%ecx// ecx += eax
   0x8048c00 <func4+32>:        cmp    %edx,%ecx
   0x8048c02 <func4+34>:        jle    0x8048c1b <func4+59>// 如果edx >= ecx
   0x8048c04 <func4+36>:        sub    $0x1,%ecx// ecx -= 0x1
   0x8048c07 <func4+39>:        mov    %ecx,0x8(%esp)
   0x8048c0b <func4+43>:        mov    %eax,0x4(%esp)
   0x8048c0f <func4+47>:        mov    %edx,(%esp)
   0x8048c12 <func4+50>:        call   0x8048be0 <func4>// 递归调用自身
   0x8048c17 <func4+55>:        add    %eax,%eax// eax *= 2;
   0x8048c19 <func4+57>:        jmp    0x8048c3b <func4+91>
   0x8048c1b <func4+59>:        mov    $0x0,%eax// eax = 0
   0x8048c20 <func4+64>:        cmp    %edx,%ecx
   0x8048c22 <func4+66>:        jge    0x8048c3b <func4+91>
   0x8048c24 <func4+68>:        mov    %ebx,0x8(%esp)
   0x8048c28 <func4+72>:        add    $0x1,%ecx
   0x8048c2b <func4+75>:        mov    %ecx,0x4(%esp)
   0x8048c2f <func4+79>:        mov    %edx,(%esp)
   0x8048c32 <func4+82>:        call   0x8048be0 <func4>
   0x8048c37 <func4+87>:        lea    0x1(%eax,%eax,1),%eax// eax = eax + eax * 1 + 1
   0x8048c3b <func4+91>:        add    $0x10,%esp//增加栈
   0x8048c3e <func4+94>:        pop    %ebx
   0x8048c3f <func4+95>:        pop    %esi
   0x8048c40 <func4+96>:        pop    %ebp
   0x8048c41 <func4+97>:        ret

设传入func4的参数为f_1,f_2,f_3, 则:

   0x8048bf1 <func4+17>:        mov    %ebx,%ecx// ecx寄存器其到一个展示保存结果的作用
   0x8048bf3 <func4+19>:        sub    %eax,%ecx// ecx -= eax 
   0x8048bf5 <func4+21>:        mov    %ecx,%esi
   0x8048bf7 <func4+23>:        shr    $0x1f,%esi// 逻辑右移31位 esi = ecx >> 31
   0x8048bfa <func4+26>:        add    %esi,%ecx// 
   0x8048bfc <func4+28>:        sar    %ecx//算数右移 没有参数默认移动一位 
   0x8048bfe <func4+30>:        add    %eax,%ecx// ecx += eax

上面的代码的作用是计算((((f_3 - f_2) >> 31) + (f_3 - f_2))>> 1) + f_2的结果保存在寄存器ecx(temp)中,下面是在不同的情况下不同的操作:

​ (1) 当edx>=ecx(f_1 >= temp)的情况下时:令eax=0,判断edx与ecx的值是否相等,相等直接返回eax的值,不能则递归调用自己,即:(eax = f_2, edx = f_1, ecx = temp)

   0x8048c00 <func4+32>:        cmp    %edx,%ecx
   0x8048c02 <func4+34>:        jle    0x8048c1b <func4+59>// 如果edx >= ecx
   0x8048c1b <func4+59>:        mov    $0x0,%eax// eax = 0
   /* edx == ecx */
   0x8048c20 <func4+64>:        cmp    %edx,%ecx
   0x8048c22 <func4+66>:        jge    0x8048c3b <func4+91>
   0x8048c24 <func4+68>:        mov    %ebx,0x8(%esp)
   0x8048c28 <func4+72>:        add    $0x1,%ecx
   /*  edx > ecx */
   0x8048c2b <func4+75>:        mov    %ecx,0x4(%esp)
   0x8048c2f <func4+79>:        mov    %edx,(%esp)
   0x8048c32 <func4+82>:        call   0x8048be0 <func4>
   0x8048c37 <func4+87>:        lea    0x1(%eax,%eax,1),%eax// eax = eax + eax * 1 + 1

用C语言表示为:

   f_2 = 0;      
   if(temp == f_1)
       return f_2;
   else
   {
       temp ++;
       return (func4(f_1, temp, f_3) * 2 + 1);
   }

(2) 当edx>=ecx时,ecx的值减1,在调用自身:

   0x8048c04 <func4+36>:        sub    $0x1,%ecx// ecx -= 0x1
   0x8048c07 <func4+39>:        mov    %ecx,0x8(%esp)
   0x8048c0b <func4+43>:        mov    %eax,0x4(%esp)
   0x8048c0f <func4+47>:        mov    %edx,(%esp)
   0x8048c12 <func4+50>:        call   0x8048be0 <func4>// 递归调用自身
   0x8048c17 <func4+55>:        add    %eax,%eax// eax *= 2;

用C语言表示为:

    temp --;
    return (func4(f_1, f_2, temp) * 2);

综上,func4的函数用C语言表示为:

int func4(int f_1, int f_2, int f_3)
{/*           %edx     %eax     %ebx*/
    int temp = f_3;

    temp = ((((f_3 - f_2) >> 31) + (f_3 - f_2))>> 1) + f_2;
    if(temp <= f_1)
    {
        f_2 = 0;      
        if(temp == f_1)
            return f_2;
        else
        {
            temp ++;
            return (func4(f_1, temp, f_3) * 2 + 1);
        }
    }
    else
    {
        temp --;
        return (func4(f_1, f_2, temp) * 2);
    }   
}

为了求出第一个输入参数num_1的值,我写了一个程序运行求结果

int func4(int f_1, int f_2, int f_3)
{
    int temp = f_3;

    temp = ((((f_3 - f_2) >> 31) + (f_3 - f_2))>> 1) + f_2;
    if(temp <= f_1)
    {
        f_2 = 0;      
        if(temp == f_1)
            return f_2;
        else
        {
            temp ++;
            return (func4(f_1, temp, f_3) * 2 + 1);
        }
    }
    else
    {
        temp --;
        return (func4(f_1, f_2, temp) * 2);
    }   
}

int main()
{
    int i = 0, r = 0;

    for(i = 0; i < 14; i++)
    {
        r = func4(i, 0, 14);
        if(r == 0x4)
            printf("%d\n",i);
    }
    return 0;
}

最终的结果是:2 4

5.phase_5(指针)

  • 思路:
    调出phase_5的反汇编:
   0x08048ca6 <+0>:     push   %ebp
   0x08048ca7 <+1>:     mov    %esp,%ebp
   0x08048ca9 <+3>:     push   %ebx
   0x08048caa <+4>:     sub    $0x14,%esp
   0x08048cad <+7>:     mov    0x8(%ebp),%ebx
   0x08048cb0 <+10>:    mov    %ebx,(%esp)
   0x08048cb3 <+13>:    call   0x8048f00 <string_length>
   0x08048cb8 <+18>:    cmp    $0x6,%eax
   0x08048cbb <+21>:    je     0x8048cc2 <phase_5+28>
   0x08048cbd <+23>:    call   0x8049145 <explode_bomb>
   0x08048cc2 <+28>:    mov    $0x0,%edx
   0x08048cc7 <+33>:    mov    $0x0,%eax
   0x08048ccc <+38>:    movzbl (%ebx,%eax,1),%ecx
   0x08048cd0 <+42>:    and    $0xf,%ecx
   0x08048cd3 <+45>:    add    0x804a1c0(,%ecx,4),%edx
   0x08048cda <+52>:    add    $0x1,%eax
   0x08048cdd <+55>:    cmp    $0x6,%eax
   0x08048ce0 <+58>:    jne    0x8048ccc <phase_5+38>
   0x08048ce2 <+60>:    cmp    $0x32,%edx
   0x08048ce5 <+63>:    je     0x8048cec <phase_5+70>
   0x08048ce7 <+65>:    call   0x8049145 <explode_bomb>
   0x08048cec <+70>:    add    $0x14,%esp
   0x08048cef <+73>:    pop    %ebx
   0x08048cf0 <+74>:    pop    %ebp
   0x08048cf1 <+75>:    ret

在调用完string_length函数后让eax与6比较可得知需要输入6个字符,为了了解程序运行的过程,我在0x08048ccc<+38>处设置断点,运行程序后输入123456:
在这里插入图片描述
查看ecx寄存器的值:
在这里插入图片描述
当ecx的值为0x31是继续往下执行:

   0x08048cd0 <+42>:    and    $0xf,%ecx
   0x08048cd3 <+45>:    add    0x804a1c0(,%ecx,4),%edx
   0x08048cda <+52>:    add    $0x1,%eax  

把ecx的值与0xf相与在把地址ecx * 4 + 0x804a1c0的值赋值给edx寄存器,所以需要查看立即数0x804a1c0里的值:
在这里插入图片描述
整理后可得:

and    $0xf,%ecx        0x804a1c0(,%ecx,4)
        0               0x2 = 2
        1               0xa = 10
        2               0x6 = 6
        3               0x1 = 1
        4               0xc = 12
        5               0x1 = 1
        6               0x9 = 9
        7               0x3 = 3
        8               0x4 = 4
        9               0x7 = 7
        10              0xe = 14
        11              0x5 = 5
        12              0xb = 11
        13              0x8 = 8
        14              0xf = 15
        15              0xd = 13

所以下面这个代码段是一个循环,一次取出我输入的字符存放到ecx中并与 0x相与,然后求出ecx*4+0x804a1c0对应的值,累加后存放到edx中

   0x08048ccc <+38>:    movzbl (%ebx,%eax,1),%ecx
   0x08048cd0 <+42>:    and    $0xf,%ecx
   0x08048cd3 <+45>:    add    0x804a1c0(,%ecx,4),%edx
   0x08048cda <+52>:    add    $0x1,%eax
   0x08048cdd <+55>:    cmp    $0x6,%eax
   0x08048ce0 <+58>:    jne    0x8048ccc <phase_5+38>

当eax的值为6是代表已经运行了6次,此时跳出循环继续往下执行:

   0x08048ce2 <+60>:    cmp    $0x32,%edx
   0x08048ce5 <+63>:    je     0x8048cec <phase_5+70>
   0x08048ce7 <+65>:    call   0x8049145 <explode_bomb>

把累加后的edx的值与0x32(50)比较,如果相等则不引爆炸弹。
所以整个phase_5首先依次取出输入的值,不同的值对应不同的数字,循环6次取出所有输入后把累加的结果与50比较,如果相等就不引爆炸弹。
为了简单,取50 = 8 + 8 + 8 + 8 + 8 + 10
在循环中若要edx=8,则and $0xf,%ecx的值应该是0xD(13), 同理edx=10对应0x1
查找ASCII码表可知:
最低位为0xD的字符为:‘-’ ‘=’ ‘M’ ‘]’ ‘m’ ‘}’
最低位为0x1的字符为: ‘!’ ‘1’ ‘A’ ‘Q’ ‘a’ ‘q’
所以只要在0xD中任取5个字符,0x1中任取1个字符组成输入的密码即可,即输入MMMMMA

6.phase_6(链表/指针/结构)

  • 思路:
    调出phase_6的反汇编:(把输入的数记做num[0…5])
   0x08048cf2 <+0>:     push   %ebp
   0x08048cf3 <+1>:     mov    %esp,%ebp
   0x08048cf5 <+3>:     push   %esi
   0x08048cf6 <+4>:     push   %ebx
   0x08048cf7 <+5>:     sub    $0x40,%esp
   0x08048cfa <+8>:     lea    -0x20(%ebp),%eax
   0x08048cfd <+11>:    mov    %eax,0x4(%esp)
   0x08048d01 <+15>:    mov    0x8(%ebp),%eax
   0x08048d04 <+18>:    mov    %eax,(%esp)
   0x08048d07 <+21>:    call   0x8049187 <read_six_numbers>
   0x08048d0c <+26>:    mov    $0x0,%esi// eis初始化

/*判断输入的数应该在1-6之间 而且各不相等*/
   0x08048d11 <+31>:    mov    -0x20(%ebp,%esi,4),%eax
   0x08048d15 <+35>:    sub    $0x1,%eax
   0x08048d18 <+38>:    cmp    $0x5,%eax
   0x08048d1b <+41>:    jbe    0x8048d22 <phase_6+48>//如果eax减为负数时会大于0x5 这时会引爆
   0x08048d1d <+43>:    call   0x8049145 <explode_bomb>
   0x08048d22 <+48>:    add    $0x1,%esi// 计数 esi ++
   0x08048d25 <+51>:    cmp    $0x6,%esi
   0x08048d28 <+54>:    jne    0x8048d31 <phase_6+63>// 不足6次
   0x08048d2a <+56>:    mov    $0x0,%ebx// 如果完成了6次
   0x08048d2f <+61>:    jmp    0x8048d69 <phase_6+119>
   0x08048d31 <+63>:    mov    %esi,%ebx// ebx = esi
   0x08048d33 <+65>:    mov    -0x20(%ebp,%ebx,4),%eax
   0x08048d37 <+69>:    cmp    %eax,-0x24(%ebp,%esi,4)
   0x08048d3b <+73>:    jne    0x8048d42 <phase_6+80>// 如果num[ebx] 等于 num[esi - 1] 引爆
   0x08048d3d <+75>:    call   0x8049145 <explode_bomb>
   0x08048d42 <+80>:    add    $0x1,%ebx// 计数 ebx ++
   0x08048d45 <+83>:    cmp    $0x5,%ebx
   0x08048d48 <+86>:    jle    0x8048d33 <phase_6+65>// ebx <= 0x5
   0x08048d4a <+88>:    jmp    0x8048d11 <phase_6+31>// 

/*小端方式压栈 如:$0x804c154 压入-0x38(%ebp,%esi,4)*/
   0x08048d4c <+90>:    mov    0x8(%edx),%edx
   0x08048d4f <+93>:    add    $0x1,%eax// eax ++
   0x08048d52 <+96>:    cmp    %ecx,%eax
   0x08048d54 <+98>:    jne    0x8048d4c <phase_6+90>// 不相等
   0x08048d56 <+100>:   jmp    0x8048d5d <phase_6+107>// 相等则跳转
   0x08048d58 <+102>:   mov    $0x804c154,%edx// *** ecx == 1
   0x08048d5d <+107>:   mov    %edx,-0x38(%ebp,%esi,4)// 压栈
   0x08048d61 <+111>:   add    $0x1,%ebx
   0x08048d64 <+114>:   cmp    $0x6,%ebx
   0x08048d67 <+117>:   je     0x8048d80 <phase_6+142>// 相等
   0x08048d69 <+119>:   mov    %ebx,%esi// ebx = esi
   0x08048d6b <+121>:   mov    -0x20(%ebp,%ebx,4),%ecx// ecx = num[edx]
   0x08048d6f <+125>:   cmp    $0x1,%ecx
   0x08048d72 <+128>:   jle    0x8048d58 <phase_6+102>// ecx <= 1
   0x08048d74 <+130>:   mov    $0x1,%eax
   0x08048d79 <+135>:   mov    $0x804c154,%edx// 
   0x08048d7e <+140>:   jmp    0x8048d4c <phase_6+90>

  /*node5->next = &node4*/ 
   0x08048d80 <+142>:   mov    -0x38(%ebp),%ebx// num[0]
   0x08048d83 <+145>:   lea    -0x34(%ebp),%eax// num[1]
   0x08048d86 <+148>:   lea    -0x20(%ebp),%esi
   0x08048d89 <+151>:   mov    %ebx,%ecx
   0x08048d8b <+153>:   mov    (%eax),%edx
   0x08048d8d <+155>:   mov    %edx,0x8(%ecx)// ecx+8是节点存储的第三个数据
   0x08048d90 <+158>:   add    $0x4,%eax// 下一个地址
   0x08048d93 <+161>:   cmp    %esi,%eax
   0x08048d95 <+163>:   je     0x8048d9b <phase_6+169>
   0x08048d97 <+165>:   mov    %edx,%ecx
   0x08048d99 <+167>:   jmp    0x8048d8b <phase_6+153>


   0x08048d9b <+169>:   movl   $0x0,0x8(%edx)//node6->next = NULL
   0x08048da2 <+176>:   mov    $0x5,%esi
   0x08048da7 <+181>:   mov    0x8(%ebx),%eax
   0x08048daa <+184>:   mov    (%eax),%eax
   0x08048dac <+186>:   cmp    %eax,(%ebx)
   0x08048dae <+188>:   jle    0x8048db5 <phase_6+195>// node1.num <= node1.num
   0x08048db0 <+190>:   call   0x8049145 <explode_bomb>
   0x08048db5 <+195>:   mov    0x8(%ebx),%ebx
   0x08048db8 <+198>:   sub    $0x1,%esi
   0x08048dbb <+201>:   jne    0x8048da7 <phase_6+181>// !=0
   0x08048dbd <+203>:   add    $0x40,%esp
   0x08048dc0 <+206>:   pop    %ebx
   0x08048dc1 <+207>:   pop    %esi
   0x08048dc2 <+208>:   pop    %ebp

分别来看 phase_6的汇编:
(1)检查输入的值是否满足要求:

   0x08048d11 <+31>:    mov    -0x20(%ebp,%esi,4),%eax
   0x08048d15 <+35>:    sub    $0x1,%eax
   0x08048d18 <+38>:    cmp    $0x5,%eax
   0x08048d1b <+41>:    jbe    0x8048d22 <phase_6+48>//如果eax减为负数时会大于0x5 这时会引爆

在这里首先eax–,如果eax的初值小于等于1或大于5,在eax减1后会大于5,所以这里是对输入的值的大小进行判断

   0x08048d25 <+51>:    cmp    $0x6,%esi
   0x08048d28 <+54>:    jne    0x8048d31 <phase_6+63>// 不足6次
   0x08048d31 <+63>:    mov    %esi,%ebx// ebx = esi
   0x08048d33 <+65>:    mov    -0x20(%ebp,%ebx,4),%eax
   0x08048d37 <+69>:    cmp    %eax,-0x24(%ebp,%esi,4)
   0x08048d3b <+73>:    jne    0x8048d42 <phase_6+80>// 如果num[ebx] 等于 num[esi - 1] 

这里是对相邻两个数之间进行判断,确保相邻两数不等

   0x08048d2a <+56>:    mov    $0x0,%ebx// 如果完成了6次
   0x08048d2f <+61>:    jmp    0x8048d69 <phase_6+119>

如果所有的数都已经进行了判断则跳出第一个大循环,继续向下运行
(2)把对应数据压栈保存

   0x08048d6b <+121>:   mov    -0x20(%ebp,%ebx,4),%ecx// ecx = num[edx]
   0x08048d6f <+125>:   cmp    $0x1,%ecx
   0x08048d72 <+128>:   jle    0x8048d58 <phase_6+102>// ecx <= 1
   0x08048d74 <+130>:   mov    $0x1,%eax
   0x08048d79 <+135>:   mov    $0x804c154,%edx// 
   0x08048d7e <+140>:   jmp    0x8048d4c <phase_6+90>
   0x08048d4c <+90>:    mov    0x8(%edx),%edx

将esi的值保存到edx中,如果ecx>= 1则执行下述操作:

   0x08048d4c <+90>:    mov    0x8(%edx),%edx
   0x08048d4f <+93>:    add    $0x1,%eax// eax ++
   0x08048d52 <+96>:    cmp    %ecx,%eax
   0x08048d54 <+98>:    jne    0x8048d4c <phase_6+90>// 不相等
   0x08048d56 <+100>:   jmp    0x8048d5d <phase_6+107>// 相等则跳转

如果ecx与eax不等则继续循环,相等后就会跳出循环执行:

   0x08048d5d <+107>:   mov    %edx,-0x38(%ebp,%esi,4)// 压栈
   0x08048d61 <+111>:   add    $0x1,%ebx
   0x08048d64 <+114>:   cmp    $0x6,%ebx
   0x08048d67 <+117>:   je     0x8048d80 <phase_6+142>// 相等

即把edx里面对应的值压栈保存到ebp +esi*4 -0x38中,而edx的初值在第102行

   0x08048d58 <+102>:   mov    $0x804c154,%edx// *** ecx == 1
   0x08048d5d <+107>:   mov    %edx,-0x38(%ebp,%esi,4)// 压栈
   0x08048d61 <+111>:   add    $0x1,%ebx
   0x08048d64 <+114>:   cmp    $0x6,%ebx
   0x08048d67 <+117>:   je     0x8048d80 <phase_6+142>// 相等

当该循环刚开始运行时ecx==1执行上诉操作,所以我需要查看0x804c154:
在这里插入图片描述
整理可得:

0x804c154 <node1>:      0x0000010a      0x00000001      0x0804c160
0x804c160 <node2>:      0x00000303      0x00000002      0x0804c16c
0x804c16c <node3>:      0x0000038e      0x00000003      0x0804c178
0x804c154 <node4>:      0x0000036f      0x00000004      0x0804c184
0x804c178 <node5>:      0x00000054      0x00000005      0x0804c190
0x804c190 <node6>:      0x000002cf      0x00000006      0x00000000
                        // 0x00000000      0x38313631                --->esi

可以看出第二列为节点的编号:
即可设节点结构为:

struct node{
	int num_1;
    int num;// 序号
    int num_2
}

(3)建立节点之间的连接

   0x08048d80 <+142>:   mov    -0x38(%ebp),%ebx// num[0]
   0x08048d83 <+145>:   lea    -0x34(%ebp),%eax// num[1]
   0x08048d86 <+148>:   lea    -0x20(%ebp),%esi
   0x08048d89 <+151>:   mov    %ebx,%ecx
   0x08048d8b <+153>:   mov    (%eax),%edx

赋初值操作,esi的设置是为了防止循环到最后链表指向空

   0x08048d8d <+155>:   mov    %edx,0x8(%ecx)// ecx+8是节点存储的第三个数据
   0x08048d90 <+158>:   add    $0x4,%eax// 下一个地址
   0x08048d93 <+161>:   cmp    %esi,%eax
   0x08048d95 <+163>:   je     0x8048d9b <phase_6+169>
   0x08048d97 <+165>:   mov    %edx,%ecx
   0x08048d99 <+167>:   jmp    0x8048d8b <phase_6+153>

在赋初值和循环过程中eax指向的地址一直是ebx后一个的地址,所以在命令mov %edx,0x8(%ecx)中的操作是把前一个节点的0x8处的地址指向下一个节点,所以ecx+0x8应该是指针next,所以当循环结束后链表的结构是:
node1.next->node2.next->node3.next->node4.next->node5.next->node6
链表的第一行应该是节点的值node.num
(4) 排序

   0x08048dac <+186>:   cmp    %eax,(%ebx)
   0x08048dae <+188>:   jle    0x8048db5 <phase_6+195>// node1.num <= node1.num

表明是升序排序

所以根据节点的值升序排序的节点序列为:5 1 6 2 4 3

bomblab 隐藏关卡

  • 思路:
    调出secret_phase的反汇编:
   0x08048e17 <+0>:     push   %ebp
   0x08048e18 <+1>:     mov    %esp,%ebp
   0x08048e1a <+3>:     push   %ebx
   0x08048e1b <+4>:     sub    $0x14,%esp
   0x08048e1e <+7>:     call   0x80491d6 <read_line>
   0x08048e23 <+12>:    movl   $0xa,0x8(%esp)
   0x08048e2b <+20>:    movl   $0x0,0x4(%esp)
   0x08048e33 <+28>:    mov    %eax,(%esp)
   0x08048e36 <+31>:    call   0x8048830 <strtol@plt>// Strtol有三个参数,第一个是要转化的字符串的地址,第二个是结束符标志,0表明是'\0',第三个是转化的数的进制,a说明最后是10进制。
   0x08048e3b <+36>:    mov    %eax,%ebx
   0x08048e3d <+38>:    lea    -0x1(%eax),%eax
   0x08048e40 <+41>:    cmp    $0x3e8,%eax
   0x08048e45 <+46>:    jbe    0x8048e4c <secret_phase+53>// eax-1 <= 1000 
   0x08048e47 <+48>:    call   0x8049145 <explode_bomb>
   0x08048e4c <+53>:    mov    %ebx,0x4(%esp)
   0x08048e50 <+57>:    movl   $0x804c0a0,(%esp)
   0x08048e57 <+64>:    call   0x8048dc4 <fun7>
   0x08048e5c <+69>:    cmp    $0x5,%eax// eax 需要等于0x5
   0x08048e5f <+72>:    je     0x8048e66 <secret_phase+79>
   0x08048e61 <+74>:    call   0x8049145 <explode_bomb>
   0x08048e66 <+79>:    movl   $0x804a15c,(%esp)
   0x08048e6d <+86>:    call   0x8048780 <puts@plt>
   0x08048e72 <+91>:    call   0x804930e <phase_defused>
   0x08048e77 <+96>:    add    $0x14,%esp
   0x08048e7a <+99>:    pop    %ebx
   0x08048e7b <+100>:   pop    %ebp
   0x08048e7c <+101>:   ret

首先需要考虑如何在boomlab中调出隐藏关,因此我查看了phase_defused函数的反汇编:(节选)

   0x08049341 <+51>:    movl   $0x804a42b,0x4(%esp)
   0x08049349 <+59>:    movl   $0x804c8f0,(%esp)
   0x08049350 <+66>:    call   0x80487d0 <__isoc99_sscanf@plt>
   0x08049355 <+71>:    cmp    $0x3,%eax
   0x08049358 <+74>:    jne    0x804938e <phase_defused+128>
   0x0804935a <+76>:    movl   $0x804a434,0x4(%esp)

首先在71行把eax与0x3比较,我查看其他的命令发现没通过一关eax就会加1,而当eax与0x3相等时代表我正在通过第4关,而且讲义上说开启隐藏关需要在第 4 关输入特殊字符,所以我查看了0x804a42b0x804a434
在这里插入图片描述
所以隐藏关的开启是在第四关写入2 4 DrEvil

   0x08048e45 <+46>:    jbe    0x8048e4c <secret_phase+53>// eax-1 <= 1000 
   0x08048e47 <+48>:    call   0x8049145 <explode_bomb>
   0x08048e4c <+53>:    mov    %ebx,0x4(%esp)
   0x08048e50 <+57>:    movl   $c,(%esp)
   0x08048e57 <+64>:    call   0x8048dc4 <fun7>// 参数c 和 ebx
   0x08048e5c <+69>:    cmp    $0x5,%eax// eax 需要等于0x5
   0x08048e5f <+72>:    je     0x8048e66 <secret_phase+79>

这里说明了需要输入一个数num,满足num <= 1001, 而且这个数需要传入func7函数里,返回值需要为5

于是查看func7的反汇编:

   0x08048dc4 <+0>:     push   %ebp
   0x08048dc5 <+1>:     mov    %esp,%ebp
   0x08048dc7 <+3>:     push   %ebx
   0x08048dc8 <+4>:     sub    $0x14,%esp
   0x08048dcb <+7>:     mov    0x8(%ebp),%edx// a
   0x08048dce <+10>:    mov    0xc(%ebp),%ecx// b
   0x08048dd1 <+13>:    test   %edx,%edx
   0x08048dd3 <+15>:    je     0x8048e0c <fun7+72>// edx == 0
   0x08048dd5 <+17>:    mov    (%edx),%ebx// ebx = a
   0x08048dd7 <+19>:    cmp    %ecx,%ebx
   0x08048dd9 <+21>:    jle    0x8048dee <fun7+42>// *a <= b
   0x08048ddb <+23>:    mov    %ecx,0x4(%esp)// b
   0x08048ddf <+27>:    mov    0x4(%edx),%eax
   0x08048de2 <+30>:    mov    %eax,(%esp)// a
   0x08048de5 <+33>:    call   0x8048dc4 <fun7>// 递归调用
   0x08048dea <+38>:    add    %eax,%eax// eax *= 2
   0x08048dec <+40>:    jmp    0x8048e11 <fun7+77>// 跳出
   0x08048dee <+42>:    mov    $0x0,%eax
   0x08048df3 <+47>:    cmp    %ecx,%ebx// *a == b
   0x08048df5 <+49>:    je     0x8048e11 <fun7+77>// 跳出 返回值eax = 0
   0x08048df7 <+51>:    mov    %ecx,0x4(%esp)
   0x08048dfb <+55>:    mov    0x8(%edx),%eax
   0x08048dfe <+58>:    mov    %eax,(%esp)
   0x08048e01 <+61>:    call   0x8048dc4 <fun7>
   0x08048e06 <+66>:    lea    0x1(%eax,%eax,1),%eax//eax = eax*2 + 0x1
   0x08048e0a <+70>:    jmp    0x8048e11 <fun7+77>
   0x08048e0c <+72>:    mov    $0xffffffff,%eax// eax = -1
   0x08048e11 <+77>:    add    $0x14,%esp
   0x08048e14 <+80>:    pop    %ebx
   0x08048e15 <+81>:    pop    %ebp
   0x08048e16 <+82>:    ret

设func7的参数为a,b,则

   0x08048dd1 <+13>:    test   %edx,%edx
   0x08048dd3 <+15>:    je     0x8048e0c <fun7+72>// edx == 0
   0x08048e0c <+72>:    mov    $0xffffffff,%eax// eax = -1
   0x08048e11 <+77>:    add    $0x14,%esp

如果指针a为空则返会-1

   0x08048dd5 <+17>:    mov    (%edx),%ebx// ebx = a
   0x08048dd7 <+19>:    cmp    %ecx,%ebx
   0x08048dd9 <+21>:    jle    0x8048dee <fun7+42>// *a <= b

先判断*a,b的大小关系,如果*a <= b则:

/* *a == b*/
   0x08048dee <+42>:    mov    $0x0,%eax
   0x08048df3 <+47>:    cmp    %ecx,%ebx// *a == b
   0x08048df5 <+49>:    je     0x8048e11 <fun7+77>// 跳出 返回值eax = 0
/* *a < b */
   0x08048df7 <+51>:    mov    %ecx,0x4(%esp)
   0x08048dfb <+55>:    mov    0x8(%edx),%eax
   0x08048dfe <+58>:    mov    %eax,(%esp)// *a +0x8
   0x08048e01 <+61>:    call   0x8048dc4 <fun7>
   0x08048e06 <+66>:    lea    0x1(%eax,%eax,1),%eax//eax = eax*2 + 0x1
   0x08048e0a <+70>:    jmp    0x8048e11 <fun7+77>

如果 *a > b,则:

   0x08048ddb <+23>:    mov    %ecx,0x4(%esp)// b
   0x08048ddf <+27>:    mov    0x4(%edx),%eax
   0x08048de2 <+30>:    mov    %eax,(%esp)// *a + 0x4
   0x08048de5 <+33>:    call   0x8048dc4 <fun7>// 递归调用
   0x08048dea <+38>:    add    %eax,%eax// eax *= 2
   0x08048dec <+40>:    jmp    0x8048e11 <fun7+77>// 跳出

综上,用C语言描述func7函数:

int fun7(int *a, int b)
{
   if(a == NULL)
      return -1;
   else if(*a <= b)
   {
      if(*a == b)
         return 0;
      else
         return (2 * fun7(*a + 8, b) + 1);
   }
   else
       return (2 * fun7(*a + 0x4));
} 

因为返回值为5 ,则有:

5 = 2 * 2 + 1
2 = 2 * 1
1 = 2 * 0 + 1
0: a == b
/*********************/
            0
     +0x4 /   \ +0x8
         /     \
             1 = 2 * '0' + 1
      +0x4 /   \ +0x8
          /     \
      2 = 2 * '1'
    /   \
   /     \
       5 = 2 * '2' + 1     注:''标注表示上一级func7的返回值

而参数a地址为0x804c0a0,所以最初输入的值应该是0x804c0a0先加0x8的对应的地址,然后该地址再加0X4后对应的地址在加0x8,最后的这个地址对应的值即为所求:
在这里插入图片描述
最终结果为 :47

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值