csapp-bomblab

phase_1

(gdb) disas phase_1
Dump of assembler code for function phase_1:
   0x08048b90 <+0>:     sub    $0x1c,%esp;开辟1c栈空间
   0x08048b93 <+3>:     movl   $0x804a1ec,0x4(%esp);用于比较的字符串放到esp+4
   0x08048b9b <+11>:    mov    0x20(%esp),%eax;取参数给eax
   0x08048b9f <+15>:    mov    %eax,(%esp);*esp = eax
   0x08048ba2 <+18>:    call   0x80490ca <strings_not_equal>;比较两字符串是否相等,结果放在eax
   0x08048ba7 <+23>:    test   %eax,%eax
   0x08048ba9 <+25>:    je     0x8048bb0 <phase_1+32>;如果eax=0,则进入phase2;否则爆炸
   0x08048bab <+27>:    call   0x80491d5 <explode_bomb>
   0x08048bb0 <+32>:    add    $0x1c,%esp;回收空间
   0x08048bb3 <+35>:    ret
When a problem comes along, you must zip it!

phase_2

递推公式

(gdb) disas phase_2
Dump of assembler code for function phase_2:
   0x08048bb4 <+0>:     push   %ebx
   0x08048bb5 <+1>:     sub    $0x38,%esp
   0x08048bb8 <+4>:     lea    0x18(%esp),%eax
   0x08048bbc <+8>:     mov    %eax,0x4(%esp);[esp+4]=[esp+18],a[0]地址
   0x08048bc0 <+12>:    mov    0x40(%esp),%eax
   0x08048bc4 <+16>:    mov    %eax,(%esp);[esp+40]=[esp]
   0x08048bc7 <+19>:    call   0x80491fc <read_six_numbers>;输入
   0x08048bcc <+24>:    cmpl   $0x0,0x18(%esp);第一个数是0
   0x08048bd1 <+29>:    jns    0x8048bf5 <phase_2+65>
   0x08048bd3 <+31>:    call   0x80491d5 <explode_bomb>
   0x08048bd8 <+36>:    jmp    0x8048bf5 <phase_2+65>
   0x08048bda <+38>:    mov    %ebx,%eax;loop begin
   0x08048bdc <+40>:    add    0x14(%esp,%ebx,4),%eax;eax+=a[i],a[0]=0
   0x08048be0 <+44>:    cmp    %eax,0x18(%esp,%ebx,4);eax?=a[i+1]
   0x08048be4 <+48>:    je     0x8048beb <phase_2+55>
   0x08048be6 <+50>:    call   0x80491d5 <explode_bomb>;
   0x08048beb <+55>:    add    $0x1,%ebx;ebx++
   0x08048bee <+58>:    cmp    $0x6,%ebx;if ebx<6, loop
   0x08048bf1 <+61>:    jne    0x8048bda <phase_2+38>;loop end
   0x08048bf3 <+63>:    jmp    0x8048bfc <phase_2+72>
   0x08048bf5 <+65>:    mov    $0x1,%ebx;ebx=1
   0x08048bfa <+70>:    jmp    0x8048bda <phase_2+38>
   0x08048bfc <+72>:    add    $0x38,%esp
   0x08048bff <+75>:    pop    %ebx
   0x08048c00 <+76>:    ret

a[1]=0, a[i] = i+a[i-1]

0 1 3 6 10 15

输入函数read_six_numbers在0x80491fc处,内部调用了sscanf:

(gdb) disas 0x80491fc
Dump of assembler code for function read_six_numbers:
   0x080491fc <+0>:     sub    $0x2c,%esp
   0x080491ff <+3>:     mov    0x34(%esp),%eax
   0x08049203 <+7>:     lea    0x14(%eax),%edx
   0x08049206 <+10>:    mov    %edx,0x1c(%esp);
   0x0804920a <+14>:    lea    0x10(%eax),%edx
   0x0804920d <+17>:    mov    %edx,0x18(%esp)
   0x08049211 <+21>:    lea    0xc(%eax),%edx
   0x08049214 <+24>:    mov    %edx,0x14(%esp)
   0x08049218 <+28>:    lea    0x8(%eax),%edx
   0x0804921b <+31>:    mov    %edx,0x10(%esp)
   0x0804921f <+35>:    lea    0x4(%eax),%edx
   0x08049222 <+38>:    mov    %edx,0xc(%esp)
   0x08049226 <+42>:    mov    %eax,0x8(%esp)
   0x0804922a <+46>:    movl   $0x804a387,0x4(%esp);sscanf第二个参数
   0x08049232 <+54>:    mov    0x30(%esp),%eax
   0x08049236 <+58>:    mov    %eax,(%esp)
   0x08049239 <+61>:    call   0x8048860 <__isoc99_sscanf@plt>
   0x0804923e <+66>:    cmp    $0x5,%eax;if i<=5, loop read
   0x08049241 <+69>:    jg     0x8049248 <read_six_numbers+76>
   0x08049243 <+71>:    call   0x80491d5 <explode_bomb>
   0x08049248 <+76>:    add    $0x2c,%esp
   0x0804924b <+79>:    ret

sscanf的函数声明,第二个参数是输入格式:

int sscanf( const char *buffer, const char *format [, argument ] ... );

查看:

(gdb) x/s 0x804a387
0x804a387:      "%d %d %d %d %d %d"

phase_3

switch分支跳转

(gdb) disas phase_3
Dump of assembler code for function phase_3:
   0x08048c01 <+0>:     sub    $0x3c,%esp
   0x08048c04 <+3>:     lea    0x2c(%esp),%eax;输入3:int
   0x08048c08 <+7>:     mov    %eax,0x10(%esp)
   0x08048c0c <+11>:    lea    0x27(%esp),%eax;输入2:char
   0x08048c10 <+15>:    mov    %eax,0xc(%esp)
   0x08048c14 <+19>:    lea    0x28(%esp),%eax;输入1:int
   0x08048c18 <+23>:    mov    %eax,0x8(%esp)
   0x08048c1c <+27>:    movl   $0x804a242,0x4(%esp);格式符
   0x08048c24 <+35>:    mov    0x40(%esp),%eax
   0x08048c28 <+39>:    mov    %eax,(%esp)
   0x08048c2b <+42>:    call   0x8048860 <__isoc99_sscanf@plt>
   0x08048c30 <+47>:    cmp    $0x2,%eax;参数多余2个
   0x08048c33 <+50>:    jg     0x8048c3a <phase_3+57>
   0x08048c35 <+52>:    call   0x80491d5 <explode_bomb>
   0x08048c3a <+57>:    cmpl   $0x7,0x28(%esp);if >7,bomb
   0x08048c3f <+62>:    ja     0x8048d41 <phase_3+320>
   0x08048c45 <+68>:    mov    0x28(%esp),%eax
   0x08048c49 <+72>:    jmp    *0x804a254(,%eax,4);switch(输入1) case
   0x08048c50 <+79>:    mov    $0x7a,%eax
   0x08048c55 <+84>:    cmpl   $0x2cd,0x2c(%esp);case 0: char=0x7a,int=0x2cd
   0x08048c5d <+92>:    je     0x8048d4b <phase_3+330>
   0x08048c63 <+98>:    call   0x80491d5 <explode_bomb>
   0x08048c68 <+103>:   mov    $0x7a,%eax
   0x08048c6d <+108>:   jmp    0x8048d4b <phase_3+330>
   0x08048c72 <+113>:   mov    $0x6b,%eax
   0x08048c77 <+118>:   cmpl   $0x238,0x2c(%esp)
   0x08048c7f <+126>:   je     0x8048d4b <phase_3+330>
   0x08048c85 <+132>:   call   0x80491d5 <explode_bomb>
   0x08048c8a <+137>:   mov    $0x6b,%eax
   0x08048c8f <+142>:   jmp    0x8048d4b <phase_3+330>
   0x08048c94 <+147>:   mov    $0x74,%eax
   0x08048c99 <+152>:   cmpl   $0x1a2,0x2c(%esp);0x1a2
   0x08048ca1 <+160>:   je     0x8048d4b <phase_3+330>
   0x08048ca7 <+166>:   call   0x80491d5 <explode_bomb>
   0x08048cac <+171>:   mov    $0x74,%eax
   0x08048cb1 <+176>:   jmp    0x8048d4b <phase_3+330>
   0x08048cb6 <+181>:   mov    $0x68,%eax
   0x08048cbb <+186>:   cmpl   $0x32d,0x2c(%esp);0x32d
   0x08048cc3 <+194>:   je     0x8048d4b <phase_3+330>
   0x08048cc9 <+200>:   call   0x80491d5 <explode_bomb>
   0x08048cce <+205>:   mov    $0x68,%eax
   0x08048cd3 <+210>:   jmp    0x8048d4b <phase_3+330>
   0x08048cd5 <+212>:   mov    $0x76,%eax
   0x08048cda <+217>:   cmpl   $0x249,0x2c(%esp)
   0x08048ce2 <+225>:   je     0x8048d4b <phase_3+330>
   0x08048ce4 <+227>:   call   0x80491d5 <explode_bomb>
   0x08048ce9 <+232>:   mov    $0x76,%eax
   0x08048cee <+237>:   jmp    0x8048d4b <phase_3+330>
   0x08048cf0 <+239>:   mov    $0x63,%eax
   0x08048cf5 <+244>:   cmpl   $0x99,0x2c(%esp)
   0x08048cfd <+252>:   je     0x8048d4b <phase_3+330>
   0x08048cff <+254>:   call   0x80491d5 <explode_bomb>
   0x08048d04 <+259>:   mov    $0x63,%eax
   0x08048d09 <+264>:   jmp    0x8048d4b <phase_3+330>
   0x08048d0b <+266>:   mov    $0x6c,%eax
   0x08048d10 <+271>:   cmpl   $0x377,0x2c(%esp)
   0x08048d18 <+279>:   je     0x8048d4b <phase_3+330>
   0x08048d1a <+281>:   call   0x80491d5 <explode_bomb>
   0x08048d1f <+286>:   mov    $0x6c,%eax
   0x08048d24 <+291>:   jmp    0x8048d4b <phase_3+330>
   0x08048d26 <+293>:   mov    $0x65,%eax
   0x08048d2b <+298>:   cmpl   $0x3e3,0x2c(%esp)
   0x08048d33 <+306>:   je     0x8048d4b <phase_3+330>
   0x08048d35 <+308>:   call   0x80491d5 <explode_bomb>
   0x08048d3a <+313>:   mov    $0x65,%eax
   0x08048d3f <+318>:   jmp    0x8048d4b <phase_3+330>
   0x08048d41 <+320>:   call   0x80491d5 <explode_bomb>
   0x08048d46 <+325>:   mov    $0x62,%eax
   0x08048d4b <+330>:   cmp    0x27(%esp),%al;输入2:char ?= eax[8:0]
   0x08048d4f <+334>:   je     0x8048d56 <phase_3+341>
   0x08048d51 <+336>:   call   0x80491d5 <explode_bomb>
   0x08048d56 <+341>:   add    $0x3c,%esp
   0x08048d59 <+344>:   ret

看一下输入格式:

(gdb) x/s 0x804a242
0x804a242:      "%d %c %d"

第一个数x1<=7

cmpl   $0x7,0x28(%esp)

switch跳转:

jmp    *0x804a254(,%eax,4);switch(输入1) case

看一下case分支:

(gdb) p/x *0x804a254
$1 = 0x8048c50
对应语句:
   0x08048c50 <+79>:    mov    $0x7a,%eax
   0x08048c55 <+84>:    cmpl   $0x2cd,0x2c(%esp);case 0: char=0x7a,int=0x2cd
   0x08048c5d <+92>:    je     0x8048d4b <phase_3+330>
   0x08048c63 <+98>:    call   0x80491d5 <explode_bomb>
   
   0x08048d4b <+330>:   cmp    0x27(%esp),%al;输入2:char ?= eax[8:0]
(gdb) p/x *(0x804a254+1*4)
$2 = 0x8048c72

   0x08048c72 <+113>:   mov    $0x6b,%eax
   0x08048c77 <+118>:   cmpl   $0x238,0x2c(%esp);case 1:char=0x6b,int=0x238
   0x08048c7f <+126>:   je     0x8048d4b <phase_3+330>
   0x08048c85 <+132>:   call   0x80491d5 <explode_bomb>
(gdb) p/x *(0x804a254+2*4)
$3 = 0x8048c94
(gdb) p/x *(0x804a254+3*4)
$4 = 0x8048cb6
(gdb) p/x *(0x804a254+4*4)
$5 = 0x8048cd5
(gdb) p/x *(0x804a254+5*4)
$6 = 0x8048cf0
(gdb) p/x *(0x804a254+6*4)
$7 = 0x8048d0b
(gdb) p/x *(0x804a254+7*4)
$8 = 0x8048d26

一种答案:

第一个输入x1:0
 switch case(0):

第二、三个输入x2、x3:
x2=char		=0x7a	=(ascii)z

x3=int		=0x2cd	=(int)717

phase_4

递归函数

(gdb) disas phase_4
Dump of assembler code for function phase_4:
   0x08048da4 <+0>:     sub    $0x2c,%esp
   0x08048da7 <+3>:     lea    0x18(%esp),%eax;输入x2
   0x08048dab <+7>:     mov    %eax,0xc(%esp)
   0x08048daf <+11>:    lea    0x1c(%esp),%eax;输入x1
   0x08048db3 <+15>:    mov    %eax,0x8(%esp)
   0x08048db7 <+19>:    movl   $0x804a393,0x4(%esp)
   0x08048dbf <+27>:    mov    0x30(%esp),%eax
   0x08048dc3 <+31>:    mov    %eax,(%esp)
   0x08048dc6 <+34>:    call   0x8048860 <__isoc99_sscanf@plt>
   0x08048dcb <+39>:    cmp    $0x2,%eax;2个输入
   0x08048dce <+42>:    jne    0x8048ddc <phase_4+56>
   0x08048dd0 <+44>:    mov    0x18(%esp),%eax
   0x08048dd4 <+48>:    sub    $0x2,%eax
   0x08048dd7 <+51>:    cmp    $0x2,%eax;x2=4
   0x08048dda <+54>:    jbe    0x8048de1 <phase_4+61>
   0x08048ddc <+56>:    call   0x80491d5 <explode_bomb>
   0x08048de1 <+61>:    mov    0x18(%esp),%eax
   0x08048de5 <+65>:    mov    %eax,0x4(%esp)
   0x08048de9 <+69>:    movl   $0x8,(%esp)
   0x08048df0 <+76>:    call   0x8048d5a <func4>;funv4(8,4)
   0x08048df5 <+81>:    cmp    0x1c(%esp),%eax;x1=func4(8,4)=216
   0x08048df9 <+85>:    je     0x8048e00 <phase_4+92>
   0x08048dfb <+87>:    call   0x80491d5 <explode_bomb>
   0x08048e00 <+92>:    add    $0x2c,%esp
   0x08048e03 <+95>:    ret

输入:

(gdb) x/s 0x804a393
0x804a393:      "%d %d"

调用func4:

(gdb) disas func4
Dump of assembler code for function func4:
   0x08048d5a <+0>:     push   %edi
   0x08048d5b <+1>:     push   %esi
   0x08048d5c <+2>:     push   %ebx
   0x08048d5d <+3>:     sub    $0x10,%esp
   0x08048d60 <+6>:     mov    0x20(%esp),%ebx;x
   0x08048d64 <+10>:    mov    0x24(%esp),%esi;y
   0x08048d68 <+14>:    test   %ebx,%ebx
   0x08048d6a <+16>:    jle    0x8048d98 <func4+62>;x==0,return 0
   0x08048d6c <+18>:    mov    %esi,%eax;
   0x08048d6e <+20>:    cmp    $0x1,%ebx
   0x08048d71 <+23>:    je     0x8048d9d <func4+67>;x==1,return y
   0x08048d73 <+25>:    mov    %esi,0x4(%esp)
   0x08048d77 <+29>:    lea    -0x1(%ebx),%eax;x-1
   0x08048d7a <+32>:    mov    %eax,(%esp)
   0x08048d7d <+35>:    call   0x8048d5a <func4>;func4(x-1,y)
   0x08048d82 <+40>:    lea    (%eax,%esi,1),%edi;func(x-1,y)+y
   0x08048d85 <+43>:    mov    %esi,0x4(%esp)
   0x08048d89 <+47>:    sub    $0x2,%ebx;x-2
   0x08048d8c <+50>:    mov    %ebx,(%esp)
   0x08048d8f <+53>:    call   0x8048d5a <func4>;func4(x-2,y)
   0x08048d94 <+58>:    add    %edi,%eax;return func4(x-1,y)+y+func4(x-2,y)
   0x08048d96 <+60>:    jmp    0x8048d9d <func4+67>
   0x08048d98 <+62>:    mov    $0x0,%eax
   0x08048d9d <+67>:    add    $0x10,%esp
   0x08048da0 <+70>:    pop    %ebx
   0x08048da1 <+71>:    pop    %esi
   0x08048da2 <+72>:    pop    %edi
   0x08048da3 <+73>:    ret

相当于如下的c函数:

#include<stdio.h>
int func4(int x,int y){
    if(x==0)	return 0;
    if(x==1)	return y;
    return func4(x-1,y)+y+func4(x-2,y);
}

int main(){
    int a=func4(8,4);
    printf("%d\n",a);
    return 0;
}

输入x1、x2:

x2=4
x1=func4(8,x2)=func4(8,4)=216

phase_5

从输入char中截取,作为偏移量去寻址,拼凑出结果string

(gdb) disas phase_5
Dump of assembler code for function phase_5:
   0x08048e04 <+0>:     push   %ebx
   0x08048e05 <+1>:     sub    $0x28,%esp
   0x08048e08 <+4>:     mov    0x30(%esp),%ebx
   0x08048e0c <+8>:     mov    %gs:0x14,%eax
   0x08048e12 <+14>:    mov    %eax,0x1c(%esp)
   0x08048e16 <+18>:    xor    %eax,%eax
   0x08048e18 <+20>:    mov    %ebx,(%esp)
   0x08048e1b <+23>:    call   0x80490ab <string_length>
   0x08048e20 <+28>:    cmp    $0x6,%eax
   0x08048e23 <+31>:    je     0x8048e6a <phase_5+102>
   0x08048e25 <+33>:    call   0x80491d5 <explode_bomb>
   0x08048e2a <+38>:    jmp    0x8048e6a <phase_5+102>
   0x08048e2c <+40>:    movzbl (%ebx,%eax,1),%edx;loop begin
   0x08048e30 <+44>:    and    $0xf,%edx;low 4 bit
   0x08048e33 <+47>:    movzbl 0x804a274(%edx),%edx;从0x804a274处取
   0x08048e3a <+54>:    mov    %dl,0x15(%esp,%eax,1);esp+15+eax=edx[3:0]
   0x08048e3e <+58>:    add    $0x1,%eax;eax++
   0x08048e41 <+61>:    cmp    $0x6,%eax
   0x08048e44 <+64>:    jne    0x8048e2c <phase_5+40>;loop end
   0x08048e46 <+66>:    movb   $0x0,0x1b(%esp)
   0x08048e4b <+71>:    movl   $0x804a24b,0x4(%esp);puzzle text
   0x08048e53 <+79>:    lea    0x15(%esp),%eax
   0x08048e57 <+83>:    mov    %eax,(%esp)
   0x08048e5a <+86>:    call   0x80490ca <strings_not_equal>
   0x08048e5f <+91>:    test   %eax,%eax
   0x08048e61 <+93>:    je     0x8048e72 <phase_5+110>
   0x08048e63 <+95>:    call   0x80491d5 <explode_bomb>
   0x08048e68 <+100>:   jmp    0x8048e72 <phase_5+110>
   0x08048e6a <+102>:   mov    $0x0,%eax
   0x08048e6f <+107>:   nop
   0x08048e70 <+108>:   jmp    0x8048e2c <phase_5+40>
   0x08048e72 <+110>:   mov    0x1c(%esp),%eax
   0x08048e76 <+114>:   xor    %gs:0x14,%eax
   0x08048e7d <+121>:   lea    0x0(%esi),%esi
   0x08048e80 <+124>:   je     0x8048e87 <phase_5+131>
   0x08048e82 <+126>:   call   0x80487c0 <__stack_chk_fail@plt>
   0x08048e87 <+131>:   add    $0x28,%esp
   0x08048e8a <+134>:   pop    %ebx
   0x08048e8b <+135>:   ret

输入要求:长度6的字符串

   0x08048e1b <+23>:    call   0x80490ab <string_length>
   0x08048e20 <+28>:    cmp    $0x6,%eax

核心代码解读:以输入字符的低4位作offset,从0x804a274处逐个取字符,放到esp+15。要求最终esp+15处的结果==0x804a24b的字符串

   0x08048e2c <+40>:    movzbl (%ebx,%eax,1),%edx;loop begin
   0x08048e30 <+44>:    and    $0xf,%edx;low 4 bit
   0x08048e33 <+47>:    movzbl 0x804a274(%edx),%edx;从0x804a274处取
   0x08048e3a <+54>:    mov    %dl,0x15(%esp,%eax,1);esp+15+eax=edx[3:0]
   0x08048e3e <+58>:    add    $0x1,%eax;eax++
   0x08048e41 <+61>:    cmp    $0x6,%eax
   0x08048e44 <+64>:    jne    0x8048e2c <phase_5+40>;loop end
   0x08048e46 <+66>:    movb   $0x0,0x1b(%esp)
   0x08048e4b <+71>:    movl   $0x804a24b,0x4(%esp);puzzle text
   0x08048e53 <+79>:    lea    0x15(%esp),%eax
   0x08048e57 <+83>:    mov    %eax,(%esp)
   0x08048e5a <+86>:    call   0x80490ca <strings_not_equal>

查看内存:从maduiersnfotvbyl中依次选6个char,拼凑出devils。每次用的offset作为输入char的低4位

(gdb) x/s 0x804a274
0x804a274 <array.3142>: "maduiersnfotvbyl"

(gdb) x/s 0x804a24b
0x804a24b:      "devils"

offset = 2,5,12,4,15,7
bit[3:0]=2,5,c,4,f,7
hex = 0x62,0x65,0x6c,0x64,0x6f,0x67
ascii = b, e,l,d,o,g

beldog

phase_6

链表排序

(gdb) disas phase_6
Dump of assembler code for function phase_6:
   0x08048e8c <+0>:     push   %esi
   0x08048e8d <+1>:     push   %ebx
   0x08048e8e <+2>:     sub    $0x44,%esp
   0x08048e91 <+5>:     lea    0x10(%esp),%eax;x2
   0x08048e95 <+9>:     mov    %eax,0x4(%esp)
   0x08048e99 <+13>:    mov    0x50(%esp),%eax;x1
   0x08048e9d <+17>:    mov    %eax,(%esp)
   0x08048ea0 <+20>:    call   0x80491fc <read_six_numbers>
   0x08048ea5 <+25>:    mov    $0x0,%esi
						;//外层循环<30-87>:输入的数字<=6
   0x08048eaa <+30>:    mov    0x10(%esp,%esi,4),%eax
   0x08048eae <+34>:    sub    $0x1,%eax
   0x08048eb1 <+37>:    cmp    $0x5,%eax
   0x08048eb4 <+40>:    jbe    0x8048ebb <phase_6+47>;输入<=6
   0x08048eb6 <+42>:    call   0x80491d5 <explode_bomb>
   0x08048ebb <+47>:    add    $0x1,%esi
   0x08048ebe <+50>:    cmp    $0x6,%esi
   0x08048ec1 <+53>:    jne    0x8048eca <phase_6+62>
   0x08048ec3 <+55>:    mov    $0x0,%ebx
   0x08048ec8 <+60>:    jmp    0x8048f03 <phase_6+119>;esi=6时跳出循环
   0x08048eca <+62>:    mov    %esi,%ebx;ebx=1
						;//内层循环<64-85>: 输入的6个数字不能相同,即只能输入1,2,3,4,5,6
   0x08048ecc <+64>:    mov    0x10(%esp,%ebx,4),%eax
   0x08048ed0 <+68>:    cmp    %eax,0xc(%esp,%esi,4); a[ebx]!=a[esi+1]
   0x08048ed4 <+72>:    jne    0x8048edb <phase_6+79>
   0x08048ed6 <+74>:    call   0x80491d5 <explode_bomb>
   0x08048edb <+79>:    add    $0x1,%ebx;ebx++
   0x08048ede <+82>:    cmp    $0x5,%ebx
   0x08048ee1 <+85>:    jle    0x8048ecc <phase_6+64>;ebx<=5, 内层循环
   0x08048ee3 <+87>:    jmp    0x8048eaa <phase_6+30>
						;//排序
   0x08048ee5 <+89>:    mov    0x8(%edx),%edx
   0x08048ee8 <+92>:    add    $0x1,%eax
   0x08048eeb <+95>:    cmp    %ecx,%eax
   0x08048eed <+97>:    jne    0x8048ee5 <phase_6+89>
   0x08048eef <+99>:    nop
   0x08048ef0 <+100>:   jmp    0x8048ef7 <phase_6+107>
   0x08048ef2 <+102>:   mov    $0x804c13c,%edx;//list node
   0x08048ef7 <+107>:   mov    %edx,0x28(%esp,%esi,4)
   0x08048efb <+111>:   add    $0x1,%ebx
   0x08048efe <+114>:   cmp    $0x6,%ebx
   0x08048f01 <+117>:   je     0x8048f1a <phase_6+142>
   0x08048f03 <+119>:   mov    %ebx,%esi
   0x08048f05 <+121>:   mov    0x10(%esp,%ebx,4),%ecx
   0x08048f09 <+125>:   cmp    $0x1,%ecx
   0x08048f0c <+128>:   jle    0x8048ef2 <phase_6+102>
   0x08048f0e <+130>:   mov    $0x1,%eax
   0x08048f13 <+135>:   mov    $0x804c13c,%edx;//list node
   0x08048f18 <+140>:   jmp    0x8048ee5 <phase_6+89>
   0x08048f1a <+142>:   mov    0x28(%esp),%ebx
   0x08048f1e <+146>:   lea    0x2c(%esp),%eax
   0x08048f22 <+150>:   lea    0x40(%esp),%esi
   0x08048f26 <+154>:   mov    %ebx,%ecx
   0x08048f28 <+156>:   mov    (%eax),%edx
   0x08048f2a <+158>:   mov    %edx,0x8(%ecx)
   0x08048f2d <+161>:   add    $0x4,%eax
   0x08048f30 <+164>:   cmp    %esi,%eax
   0x08048f32 <+166>:   je     0x8048f38 <phase_6+172>
   0x08048f34 <+168>:   mov    %edx,%ecx
   0x08048f36 <+170>:   jmp    0x8048f28 <phase_6+156>
   0x08048f38 <+172>:   movl   $0x0,0x8(%edx)
   0x08048f3f <+179>:   mov    $0x5,%esi
						;//升序链表,前一个node<=后一个node
   0x08048f44 <+184>:   mov    0x8(%ebx),%eax	;node.next, 下一个node的地址
   0x08048f47 <+187>:   mov    (%eax),%eax		;node.next.value,下一个node的值
   0x08048f49 <+189>:   cmp    %eax,(%ebx)
   0x08048f4b <+191>:   jle    0x8048f52 <phase_6+198>;node.value <= node.next.value
   0x08048f4d <+193>:   call   0x80491d5 <explode_bomb>
   0x08048f52 <+198>:   mov    0x8(%ebx),%ebx	;node = node.next,遍历链表
   0x08048f55 <+201>:   sub    $0x1,%esi
   0x08048f58 <+204>:   jne    0x8048f44 <phase_6+184>

   0x08048f5a <+206>:   add    $0x44,%esp
   0x08048f5d <+209>:   pop    %ebx
   0x08048f5e <+210>:   pop    %esi
   0x08048f5f <+211>:   ret

查看node:

(gdb) p/x *(0x804c13c)@18
$1 = {0x233, 0x1, 0x804c148, 
0x149, 0x2, 0x804c154, 
0x29a, 0x3, 0x804c160, 
0x7c, 0x4, 0x804c16c,
0x1c6, 0x5,0x804c178, 
0x1f7, 0x6, 0x0}
 
(gdb) x/24xw 0x804c13c
0x804c13c <node1>:      0x00000233      0x00000001      0x0804c148      0x00000149
0x804c14c <node2+4>:    0x00000002      0x0804c154      0x0000029a      0x00000003
0x804c15c <node3+8>:    0x0804c160      0x0000007c      0x00000004      0x0804c16c
0x804c16c <node5>:      0x000001c6      0x00000005      0x0804c178      0x000001f7
0x804c17c <node6+4>:    0x00000006      0x00000000      0x00000004      0x00000000
0x804c18c:      0x00000000      0x00000000      0x00000000      0x00000000

相当于结构体:

struct node{
    int value;
    int index;
    struct node* next;
};

打印链表 : 打印节点的数据,序号和下一个节点的地址

(gdb) p/x *(0x804c13c)@3
$6 = {0x233, 0x1, 0x804c148}
(gdb) p/x *(0x804c148)@3
$7 = {0x149, 0x2, 0x804c154}
(gdb) p/x *(0x804c154)@3
$8 = {0x29a, 0x3, 0x804c160}
(gdb) p/x *(0x804c160)@3
$9 = {0x7c, 0x4, 0x804c16c}
(gdb) p/x *(0x804c16c)@3
$10 = {0x1c6, 0x5, 0x804c178}
(gdb) p/x *(0x804c178)@3
$11 = {0x1f7, 0x6, 0x0}

升序链表:

4 2 5 6 1 3

secret_phase

隐藏关卡入口

从<phase_defused>找到隐藏关卡入口:

(gdb) disas phase_defused
Dump of assembler code for function phase_defused:
   0x08049346 <+0>:     sub    $0x8c,%esp
   0x0804934c <+6>:     mov    %gs:0x14,%eax
   0x08049352 <+12>:    mov    %eax,0x7c(%esp)
   0x08049356 <+16>:    xor    %eax,%eax
   0x08049358 <+18>:    cmpl   $0x6,0x804c3c8;6个关卡
   0x0804935f <+25>:    jne    0x80493d3 <phase_defused+141>
   0x08049361 <+27>:    lea    0x2c(%esp),%eax
   0x08049365 <+31>:    mov    %eax,0x10(%esp)
   0x08049369 <+35>:    lea    0x28(%esp),%eax
   0x0804936d <+39>:    mov    %eax,0xc(%esp)
   0x08049371 <+43>:    lea    0x24(%esp),%eax
   0x08049375 <+47>:    mov    %eax,0x8(%esp)
   0x08049379 <+51>:    movl   $0x804a3ed,0x4(%esp);0x804a3ed="%d %d %s"
   0x08049381 <+59>:    movl   $0x804c4d0,(%esp)
   0x08049388 <+66>:    call   0x8048860 <__isoc99_sscanf@plt>
   0x0804938d <+71>:    cmp    $0x3,%eax;3个参数,才会继续
   0x08049390 <+74>:    jne    0x80493c7 <phase_defused+129>
   0x08049392 <+76>:    movl   $0x804a3f6,0x4(%esp);0x804a3f6="DrEvil"
   0x0804939a <+84>:    lea    0x2c(%esp),%eax
   0x0804939e <+88>:    mov    %eax,(%esp)
   0x080493a1 <+91>:    call   0x80490ca <strings_not_equal>
   0x080493a6 <+96>:    test   %eax,%eax;字符串不符合要求,就无法开启隐藏关卡
   0x080493a8 <+98>:    jne    0x80493c7 <phase_defused+129>
   0x080493aa <+100>:   movl   $0x804a2bc,(%esp);0x804a2bc="Curses, you've found the secret phase!"
   0x080493b1 <+107>:   call   0x80487f0 <puts@plt>
   0x080493b6 <+112>:   movl   $0x804a2e4,(%esp);0x804a2e4="But finding it and solving it are quite different..."
   0x080493bd <+119>:   call   0x80487f0 <puts@plt>
   0x080493c2 <+124>:   call   0x8048fb1 <secret_phase>;进入隐藏关卡
   0x080493c7 <+129>:   movl   $0x804a31c,(%esp);0x804a31c="Congratulations! You've defused the bomb!"
   0x080493ce <+136>:   call   0x80487f0 <puts@plt>
   0x080493d3 <+141>:   mov    0x7c(%esp),%eax
   0x080493d7 <+145>:   xor    %gs:0x14,%eax
   0x080493de <+152>:   je     0x80493e5 <phase_defused+159>
   0x080493e0 <+154>:   call   0x80487c0 <__stack_chk_fail@plt>
   0x080493e5 <+159>:   add    $0x8c,%esp
   0x080493eb <+165>:   ret

解答

递归函数

(gdb) disas secret_phase
Dump of assembler code for function secret_phase:
   0x08048fb1 <+0>:     push   %ebx
   0x08048fb2 <+1>:     sub    $0x18,%esp
   0x08048fb5 <+4>:     call   0x804924c <read_line>;读入一行,作为<strtol@plt>第1个参数
   0x08048fba <+9>:     movl   $0xa,0x8(%esp); x3=a
   0x08048fc2 <+17>:    movl   $0x0,0x4(%esp); x2=0
   0x08048fca <+25>:    mov    %eax,(%esp);    x1=read_line
   0x08048fcd <+28>:    call   0x80488d0 <strtol@plt>;y=strtol(x1,0,a),x1为10进制数
   0x08048fd2 <+33>:    mov    %eax,%ebx
   0x08048fd4 <+35>:    lea    -0x1(%eax),%eax
   0x08048fd7 <+38>:    cmp    $0x3e8,%; if strtol()-1<= (decimal)1000 , x1<=1001
   0x08048fdc <+43>:    jbe    0x8048fe3 <secret_phase+50>
   0x08048fde <+45>:    call   0x80491d5 <explode_bomb>
   0x08048fe3 <+50>:    mov    %ebx,0x4(%esp)
   0x08048fe7 <+54>:    movl   $0x804c088,(%esp);*pointer=0x24=(decimal)36
   0x08048fee <+61>:    call   0x8048f60 <fun7>;z=fun7(pointer,y)
   0x08048ff3 <+66>:    cmp    $0x7,%eax        ;z=7
   0x08048ff6 <+69>:    je     0x8048ffd <secret_phase+76>
   0x08048ff8 <+71>:    call   0x80491d5 <explode_bomb>
   0x08048ffd <+76>:    movl   $0x804a21c,(%esp);0x804a21c="Wow! You've defused the secret stage!"
   0x08049004 <+83>:    call   0x80487f0 <puts@plt>
   0x08049009 <+88>:    call   0x8049346 <phase_defused>
   0x0804900e <+93>:    add    $0x18,%esp
   0x08049011 <+96>:    pop    %ebx
   0x08049012 <+97>:    ret

输入一个十进制数,先调用strtol,后调用fun7

(gdb) disas strtol
;//将我们输入的数字当作字符串处理,然后转为十进制。简单地说就是输入什么十进制数参数就是那个十进制数本身
Dump of assembler code for function strtol:
   0xf7e09400 <+0>:     endbr32
   0xf7e09404 <+4>:     call   0xf7f1429d
   0xf7e09409 <+9>:     add    $0x1b1bf7,%eax
   0xf7e0940e <+14>:    sub    $0x18,%esp
   0xf7e09411 <+17>:    mov    -0x16c(%eax),%eax
   0xf7e09417 <+23>:    pushl  %gs:(%eax)
   0xf7e0941a <+26>:    push   $0x0
   0xf7e0941c <+28>:    pushl  0x2c(%esp)
   0xf7e09420 <+32>:    pushl  0x2c(%esp)
   0xf7e09424 <+36>:    pushl  0x2c(%esp)
   0xf7e09428 <+40>:    call   0xf7e095c0
   0xf7e0942d <+45>:    add    $0x2c,%esp
   0xf7e09430 <+48>:    ret

fun7()的参数:

(gdb) p/x *0x804c088
$13 = 0x24
(gdb) disas fun7
Dump of assembler code for function fun7:
   0x08048f60 <+0>:     push   %ebx
   0x08048f61 <+1>:     sub    $0x18,%esp
   0x08048f64 <+4>:     mov    0x20(%esp),%edx;x1
   0x08048f68 <+8>:     mov    0x24(%esp),%ecx;x2
   0x08048f6c <+12>:    test   %edx,%edx;if x1=0, return 0xffffffff
   0x08048f6e <+14>:    je     0x8048fa7 <fun7+71>
   0x08048f70 <+16>:    mov    (%edx),%ebx;ebx=*x1
   0x08048f72 <+18>:    cmp    %ecx,%ebx;if x2<=*x1
   0x08048f74 <+20>:    jle    0x8048f89 <fun7+41>
   0x08048f76 <+22>:    mov    %ecx,0x4(%esp)
   0x08048f7a <+26>:    mov    0x4(%edx),%eax
   0x08048f7d <+29>:    mov    %eax,(%esp)
   0x08048f80 <+32>:    call   0x8048f60 <fun7>;y=fun7(M[x1+4],x2)
   0x08048f85 <+37>:    add    %eax,%eax;2*y
   0x08048f87 <+39>:    jmp    0x8048fac <fun7+76>;if x2>x1, return 2*fun7(M[x1+4],x2)
   0x08048f89 <+41>:    mov    $0x0,%eax
   0x08048f8e <+46>:    cmp    %ecx,%ebx;if x2==*x1, return 0
   0x08048f90 <+48>:    je     0x8048fac <fun7+76>
   0x08048f92 <+50>:    mov    %ecx,0x4(%esp)
   0x08048f96 <+54>:    mov    0x8(%edx),%eax
   0x08048f99 <+57>:    mov    %eax,(%esp)
   0x08048f9c <+60>:    call   0x8048f60 <fun7>;z=fun7(M[x1+8],x2)
   0x08048fa1 <+65>:    lea    0x1(%eax,%eax,1),%eax;2*z+1
   0x08048fa5 <+69>:    jmp    0x8048fac <fun7+76>;if x2<x1, return 2*fun7(M[x1+8],x2)+1
   0x08048fa7 <+71>:    mov    $0xffffffff,%eax
   0x08048fac <+76>:    add    $0x18,%esp
   0x08048faf <+79>:    pop    %ebx
   0x08048fb0 <+80>:    ret

相当于二叉树搜索:

#include<stdio.h>

struct node{
    int value;
    struct node *right;
    struct node *left;
};

int fun7(struct node *root, int key){
    if (root == NULL)		return 0xffffffff;
    if (root->value == key)	return 0;
    if (root->value < key)
        return 2 * fun7(root->right, key);//fun7( *(root+4),key )
    else
        return 2 * fun7(root->left, key) + 1;//fun7( *(root+8),key )
}

int main(){
    int x=1001;
    struct node *n;
    n->value=36;

    printf("%d\n",fun7(n,x));
    return 0;
}
fun7(A,B) = 7

递归base=0,那么有:
A*2+1=7-->A=3 即有*A>B
A*2+1=3-->A=1*A>B
A*2+1=1-->A=0*A>B 

递归三次,此时,要有A=fun(A,B)=0,即A=B,所以输入x=*A->value

查看每次递归的变量值:

(gdb) p/x *0x804c088		;{36,left,0x804c0a0}
$1 = 0x24
(gdb) p/x *(0x804c088+8)	;{value,0x804c088,0x804c0a0}
$2 = 0x804c0a0
(gdb) p/x *(0x804c0a0+8)	;{value,0x804c0a0,0x804c0d0}
$3 = 0x804c0d0
(gdb) p/x *(0x804c0d0+8)	;{value,0x804c0d0,0x804c130}
$4 = 0x804c130
(gdb) p/x *(0x804c130)		;{1001,0x804c0d0,NULL}
$6 = 0x3e9
输入x = 0x3e9 = 1001

结果截图

所有输入:

When a problem comes along, you must zip it!
0 1 3 6 10 15
0 z 717
216 4
beldog
4 2 5 6 1 3

//for secret_phase
When a problem comes along, you must zip it!
0 1 3 6 10 15
0 z 717
216 4 DrEvil
beldog
4 2 5 6 1 3
1001
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值