CSAPP bomb lab3
Phase_3
0000000000400f43 <phase_3>:
// arg1=input (input是一个字符串)
400f43: 48 83 ec 18 sub $0x18,%rsp
400f47: 48 8d 4c 24 0c lea 0xc(%rsp),%rcx
400f4c: 48 8d 54 24 08 lea 0x8(%rsp),%rdx
400f51: be cf 25 40 00 mov $0x4025cf,%esi
400f56: b8 00 00 00 00 mov $0x0,%eax
400f5b: e8 90 fc ff ff callq 400bf0 <__isoc99_sscanf@plt>
400f60: 83 f8 01 cmp $0x1,%eax
400f63: 7f 05 jg 400f6a <phase_3+0x27>
400f65: e8 d0 04 00 00 callq 40143a <explode_bomb>
400f6a: 83 7c 24 08 07 cmpl $0x7,0x8(%rsp)
400f6f: 77 3c ja 400fad <phase_3+0x6a>
400f71: 8b 44 24 08 mov 0x8(%rsp),%eax
400f75: ff 24 c5 70 24 40 00 jmpq *0x402470(,%rax,8)
400f7c: b8 cf 00 00 00 mov $0xcf,%eax
400f81: eb 3b jmp 400fbe <phase_3+0x7b>
400f83: b8 c3 02 00 00 mov $0x2c3,%eax
400f88: eb 34 jmp 400fbe <phase_3+0x7b>
400f8a: b8 00 01 00 00 mov $0x100,%eax
400f8f: eb 2d jmp 400fbe <phase_3+0x7b>
400f91: b8 85 01 00 00 mov $0x185,%eax
400f96: eb 26 jmp 400fbe <phase_3+0x7b>
400f98: b8 ce 00 00 00 mov $0xce,%eax
400f9d: eb 1f jmp 400fbe <phase_3+0x7b>
400f9f: b8 aa 02 00 00 mov $0x2aa,%eax
400fa4: eb 18 jmp 400fbe <phase_3+0x7b>
400fa6: b8 47 01 00 00 mov $0x147,%eax
400fab: eb 11 jmp 400fbe <phase_3+0x7b>
400fad: e8 88 04 00 00 callq 40143a <explode_bomb>
400fb2: b8 00 00 00 00 mov $0x0,%eax
400fb7: eb 05 jmp 400fbe <phase_3+0x7b>
400fb9: b8 37 01 00 00 mov $0x137,%eax
400fbe: 3b 44 24 0c cmp 0xc(%rsp),%eax
400fc2: 74 05 je 400fc9 <phase_3+0x86>
400fc4: e8 71 04 00 00 callq 40143a <explode_bomb>
400fc9: 48 83 c4 18 add $0x18,%rsp
400fcd: c3 retq
在phase_3中同样调用了sscanf,第二个参数rsi在调用前赋予了0x4025cf
gdb中用 x/1s 0x4025cf查到是:“%d %d”,说明这个是输入两个int整数。然后写入第三、四参数,即rdx,rcx,
rcx=rsp+0xc,rdx=rsp+0x8,
rdx和rcx其实是一个数组,令:rdx<=>&a[0],rcx<=>&a[1]
同样的套路,在调用Phase_3之前先要求按"%d %d"来将数据流写入到char *input,
然后调用sscanf(char *input,"%d %d",&a[0],&a[1])。
若sscanf的返回值<=1,直接爆炸(说明先确保按正确的格式输入)。跳出sscanf后,if (a[0]<0 或 a[0]>7),也直接爆炸。(保证0 =< a[0] <=7)
后面有一个重要的命令:jmpq *0x402470(,%rax,8),由于rax=a[0],所以表明跳转到地址(0x402470+a[0]*8)中存放的地址(代码)。gdb下输入 x/8gx 0x402470得到:
这摆明是以rdx为索引的跳转表啊!
图中所写入的8个地址都在phase_3代码段中可查,switch的索引a[0]可以取0,1,2,3,4,5,6,7以及default,转成代码为:
void phase_3(char *input)
{
int a[2];
if ( sscanf(input,"%d %d",&a[0],&a[1]) != 2)
bomb();
switch (a[0]){
case 0: goto 0x400f7c; break;
case 1: goto 0x400fb9; break;
case 2: goto 0x400f83; break;
case 3: goto 0x400f8a; break;
case 4: goto 0x400f91; break;
case 5: goto 0x400f98; break;
case 6: goto 0x400f9f; break;
case 7: goto 0x400fa6; break;
default: bomb();
}
}
以a[0]=0为例,真实的代码存放在0x402470对应的实际代码地址为400f7c:
400f7c: b8 cf 00 00 00 mov $0xcf,%eax
// eax=0xcf
400fbe: 3b 44 24 0c cmp 0xc(%rsp),%eax
400fc2: 74 05 je 400fc9 <phase_3+0x86>
// if (eax==a[1])->成功! --> 所以a[1]=0xcf =
400fc4: e8 71 04 00 00 callq 40143a <explode_bomb>
400fc9: 48 83 c4 18 add $0x18,%rsp
// 同样的,可以令a[0]取另外7个数,也有对应的a[1]使得关卡通过。
因而,其中一个答案为:"0 207"