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