赞
踩
查看bomb.c 的源码
lab中自带bomb.c文件
main函数调用各个bomb(炸弹)
main函数中调用phase_1函数的汇编代码
400e32: e8 67 06 00 00 callq 40149e <read_line>
400e37: 48 89 c7 mov %rax,%rdi
400e3a: e8 a1 00 00 00 callq 400ee0 <phase_1>
400e3f: e8 80 07 00 00 callq 4015c4 <phase_defused>
400e44: bf a8 23 40 00 mov $0x4023a8,%edi
400e49: e8 c2 fc ff ff callq 400b10 <puts@plt>
调用read_line函数输入数据,存入rax寄存器中,然后执行 mov %rax,%rdi,将数据复制给rdi寄存器中。
phase_1函数的汇编代码
0000000000400ee0 <phase_1>: ;开辟8字节的内存空间 400ee0: 48 83 ec 08 sub $0x8,%rsp ;将内存地址为0x402400的内容复制给%esi寄存器(第二个参数,第一个参数存放在%edi寄存器中) 400ee4: be 00 24 40 00 mov $0x402400,%esi ;调用strings_not_equal函数进行字符串比较 400ee9: e8 4a 04 00 00 callq 401338 <strings_not_equal> ;判断strings_not_equal函数的返回值(存放在eax寄存器中)是否为0 400eee: 85 c0 test %eax,%eax ;判断标志位ZF的值若为1则进行跳转 400ef0: 74 05 je 400ef7 <phase_1+0x17> ;发生爆炸 400ef2: e8 43 05 00 00 callq 40143a <explode_bomb> ;清除栈内存空间 400ef7: 48 83 c4 08 add $0x8,%rsp 400efb: c3 retq
phase_1函数中调用strings_not_equal函数(进行字符串比较)返回值存放在eax寄存器中,test指令判断eax寄存器是否为0,若为0则ZF为1,否则ZF为0。je指令,若ZF为1,则进行跳转。
使用gdb进行动态调试
下断点到 phase_1函数处,先输入a试试
按n或者ni步入
是将rsi寄存器和rdi寄存器的内容进行比较
而且得知rsi寄存器中的字符串为Border relations with Canada have never been better.
所以第一关输入Border relations with Canada have never been better.就可以通过!
欧耶,通过!!
main函数中调用phase_2函数的汇编代码(与调用phase_1)相同
400e4e: e8 4b 06 00 00 callq 40149e <read_line>
400e53: 48 89 c7 mov %rax,%rdi
400e56: e8 a1 00 00 00 callq 400efc <phase_2>
400e5b: e8 64 07 00 00 callq 4015c4 <phase_defused>
400e60: bf ed 22 40 00 mov $0x4022ed,%edi
400e65: e8 a6 fc ff ff callq 400b10 <puts@plt>
(64位传参,前6个参数存放在rdi,rsi,rdx,rcx,r8,r9)
read_six_numbers函数的汇编代码
000000000040145c <read_six_numbers>: ;开辟0x18(24)个字节的内存空间 40145c: 48 83 ec 18 sub $0x18,%rsp ;将第二个参数(存放在%rsi寄存器中)赋值给第三个参数(存放在%rdx寄存器中) 401460: 48 89 f2 mov %rsi,%rdx ;将%rsi+0x4处的内存单元的地址存放在%rcx寄存器中 401463: 48 8d 4e 04 lea 0x4(%rsi),%rcx ;将%rsi+0x14处的内存单元的地址存放在%rax寄存器中 401467: 48 8d 46 14 lea 0x14(%rsi),%rax ;将%rax寄存器中的数据存放在%rsp+0x8处内存单元 40146b: 48 89 44 24 08 mov %rax,0x8(%rsp) ;将%rsi+0x10处的内存单元的地址存放在%rax寄存器中 401470: 48 8d 46 10 lea 0x10(%rsi),%rax ;将%rax寄存器中的数据存放在%rsp寄存器中 401474: 48 89 04 24 mov %rax,(%rsp) ;将%rsi+0xc处的内存单元地址存放在%r9寄存器中 401478: 4c 8d 4e 0c lea 0xc(%rsi),%r9 ;将%rsi+0x8处的内存单元地址存放在%r8寄存器中 40147c: 4c 8d 46 08 lea 0x8(%rsi),%r8 ;将内存地址为0x4025c3的内存单元中的数据存放在%esi寄存器中 401480: be c3 25 40 00 mov $0x4025c3,%esi ;将%eax寄存器清0 401485: b8 00 00 00 00 mov $0x0,%eax ;调用scanf函数 40148a: e8 61 f7 ff ff callq 400bf0 <__isoc99_sscanf@plt> ;将%eax寄存器中的数据与0x5相比较 40148f: 83 f8 05 cmp $0x5,%eax ;大于则跳转 401492: 7f 05 jg 401499 <read_six_numbers+0x3d> ;发生爆炸 401494: e8 a1 ff ff ff callq 40143a <explode_bomb> 401499: 48 83 c4 18 add $0x18,%rsp 40149d: c3 retq
查看phase_2函数的汇编代码
0000000000400efc <phase_2>: ;保存main函数(调用函数)的信息 400efc: 55 push %rbp 400efd: 53 push %rbx ;开辟0x28(40)个字节的栈内存空间 400efe: 48 83 ec 28 sub $0x28,%rsp ;将%rsp寄存器赋值给%rsi寄存器 400f02: 48 89 e6 mov %rsp,%rsi ;调用read_six_numbers函数,根据函数名可知是输入6个数。 400f05: e8 52 05 00 00 callq 40145c <read_six_numbers> ;将%esp寄存器所指的内存地址中的数据与1相比较 400f0a: 83 3c 24 01 cmpl $0x1,(%rsp) ;若ZF标志位为1,则进行跳转 400f0e: 74 20 je 400f30 <phase_2+0x34> ;发生爆炸 400f10: e8 25 05 00 00 callq 40143a <explode_bomb> ;jmp指令无条件跳转 400f15: eb 19 jmp 400f30 <phase_2+0x34> ;将%rbx寄存器中的地址-0x4的内存内容给%eax寄存器中。%eax = (%rbx - 4) 400f17: 8b 43 fc mov -0x4(%rbx),%eax ;将%eax寄存器的数据乘以2,%eax=%eax+%eax 400f1a: 01 c0 add %eax,%eax ;将%eax寄存器和%rbx寄存器中的数据相比较,若相等则标志位ZF为1,否则为0 400f1c: 39 03 cmp %eax,(%rbx) ;若标志位为1,则进行跳转 400f1e: 74 05 je 400f25 <phase_2+0x29> ;调用explode_bomb函数,发生爆炸 400f20: e8 15 05 00 00 callq 40143a <explode_bomb> ;将%rbx寄存器中的数据+0x4,%rbx=%rbx+0x4 400f25: 48 83 c3 04 add $0x4,%rbx ;将%rbp寄存器和%rbx寄存器中的数据相比较,若相等则标志位ZF为1,否则标志位为0 400f29: 48 39 eb cmp %rbp,%rbx ;若标志位ZF为0则发生跳转,否则不发生跳转 400f2c: 75 e9 jne 400f17 <phase_2+0x1b> ;jmp指令进行无条件跳转 400f2e: eb 0c jmp 400f3c <phase_2+0x40> ;将%rsp寄存器+0x4处的内存单元地址中的数据赋值给%rbx寄存器 400f30: 48 8d 5c 24 04 lea 0x4(%rsp),%rbx ;将%rsp寄存器+0x18处的内存单元地址中的数据赋值给%rbp寄存器 400f35: 48 8d 6c 24 18 lea 0x18(%rsp),%rbp ;jmp指令进行无条件跳转 400f3a: eb db jmp 400f17 <phase_2+0x1b> ;清除栈内存空间 400f3c: 48 83 c4 28 add $0x28,%rsp ;恢复main函数(调用函数)的信息 400f40: 5b pop %rbx 400f41: 5d pop %rbp 400f42: c3 retq
;将%esp寄存器所指的内存地址中的数据与1相比较
400f0a: 83 3c 24 01 cmpl $0x1,(%rsp)
;若ZF标志位为1,则进行跳转
400f0e: 74 20 je 400f30 <phase_2+0x34>
;发生爆炸
400f10: e8 25 05 00 00 callq 40143a <explode_bomb>
由上面的汇编代码得知,第一个元素是1。进行跳转0x400f30
;将%rsp寄存器+0x4处的内存单元地址中的数据赋值给%rbx寄存器
400f30: 48 8d 5c 24 04 lea 0x4(%rsp),%rbx
;将%rsp寄存器+0x18处的内存单元地址中的数据赋值给%rbp寄存器
400f35: 48 8d 6c 24 18 lea 0x18(%rsp),%rbp
;jmp指令进行无条件跳转
400f3a: eb db jmp 400f17 <phase_2+0x1b>
%rsp+0x4的地址赋值给%rbx,%rsp+0x18的地址赋值给%rbp。
进行跳转0x400f17
;将%rbx寄存器中的地址-0x4的内存内容给%eax寄存器中。%eax = (%rbx - 4)
400f17: 8b 43 fc mov -0x4(%rbx),%eax
;将%eax寄存器的数据乘以2,%eax=%eax+%eax
400f1a: 01 c0 add %eax,%eax
;将%eax寄存器和%rbx寄存器中的数据相比较,若相等则标志位ZF为1,否则为0
400f1c: 39 03 cmp %eax,(%rbx)
;若标志位为1,则进行跳转
400f1e: 74 05 je 400f25 <phase_2+0x29>
;调用explode_bomb函数,发生爆炸
400f20: e8 15 05 00 00 callq 40143a <explode_bomb>
400f30: 48 8d 5c 24 04 lea 0x4(%rsp),%rbx
因为这段代码,使得%rbx与%rsp相差0x4
400f17: 8b 43 fc mov -0x4(%rbx),%eax
所以经过这段代码,%eax存放的是%esp所指的内容,也就是1
400f1a: 01 c0 add %eax,%eax
经过代码得,%eax中的数据为2
所以第二个参数是2
;将%rbx寄存器中的数据+0x4,%rbx=%rbx+0x4
400f25: 48 83 c3 04 add $0x4,%rbx
;将%rbp寄存器和%rbx寄存器中的数据相比较,若相等则标志位ZF为1,否则标志位为0
400f29: 48 39 eb cmp %rbp,%rbx
;若标志位ZF为0则发生跳转,否则不发生跳转
400f2c: 75 e9 jne 400f17 <phase_2+0x1b>
这段代码是一个循环
所以得出结果为 1,2,4,8,16,32
查看phase_3函数得汇编代码
0000000000400f43 <phase_3>: ;开辟0x18(24)个字节 400f43: 48 83 ec 18 sub $0x18,%rsp ;将%rsp+0xc的内存地址赋值给%rcx 400f47: 48 8d 4c 24 0c lea 0xc(%rsp),%rcx ;将%rsp+0x8的内存地址赋值给%rdx 400f4c: 48 8d 54 24 08 lea 0x8(%rsp),%rdx ;将内存地址为0x4025cf的内容赋值给%esi 400f51: be cf 25 40 00 mov $0x4025cf,%esi ;将%eax寄存器设置为0 400f56: b8 00 00 00 00 mov $0x0,%eax ;调用__isoc99_sscanf函数 400f5b: e8 90 fc ff ff callq 400bf0 <__isoc99_sscanf@plt> ;函数调用,返回值存放在%eax,将0x1与返回值进行比较 400f60: 83 f8 01 cmp $0x1,%eax ;若返回值大于0x1,则进行跳转到0x400f6a 400f63: 7f 05 jg 400f6a <phase_3+0x27> ;发生爆炸 400f65: e8 d0 04 00 00 callq 40143a <explode_bomb> ;将0x7与%rsp+0x8的内存数据进行比较 400f6a: 83 7c 24 08 07 cmpl $0x7,0x8(%rsp) ;%rsp+0x8的内存数据大于0x7则跳转到0x400fad 400f6f: 77 3c ja 400fad <phase_3+0x6a> ;将%rsp+0x8的内存内容赋值给%eax 400f71: 8b 44 24 08 mov 0x8(%rsp),%eax 400f75: ff 24 c5 70 24 40 00 jmpq *0x402470(,%rax,8) ;将0xcf赋值给%eax 400f7c: b8 cf 00 00 00 mov $0xcf,%eax ;跳转到0x400fbe 400f81: eb 3b jmp 400fbe <phase_3+0x7b> ;将0x2c3赋值给%eax 400f83: b8 c3 02 00 00 mov $0x2c3,%eax ;跳转到0x400fbe 400f88: eb 34 jmp 400fbe <phase_3+0x7b> ;将0x100赋值给%eax 400f8a: b8 00 01 00 00 mov $0x100,%eax ;跳转到0x400fbe 400f8f: eb 2d jmp 400fbe <phase_3+0x7b> ;将0x185赋值给%eax 400f91: b8 85 01 00 00 mov $0x185,%eax ;跳转到0x400fbe 400f96: eb 26 jmp 400fbe <phase_3+0x7b> ;将0xce赋值给%eax 400f98: b8 ce 00 00 00 mov $0xce,%eax ;跳转到0x400fbe 400f9d: eb 1f jmp 400fbe <phase_3+0x7b> ;将0x2aa赋值给%eax 400f9f: b8 aa 02 00 00 mov $0x2aa,%eax ;跳转到0x400fbe 400fa4: eb 18 jmp 400fbe <phase_3+0x7b> ;将0x147赋值给%eax 400fa6: b8 47 01 00 00 mov $0x147,%eax ;无条件跳转到0x400fbe 400fab: eb 11 jmp 400fbe <phase_3+0x7b> ;发生爆炸 400fad: e8 88 04 00 00 callq 40143a <explode_bomb> ;将0x0赋值给%eax 400fb2: b8 00 00 00 00 mov $0x0,%eax ;跳转到0x400fbe 400fb7: eb 05 jmp 400fbe <phase_3+0x7b> ;将0x137赋值给%eax 400fb9: b8 37 01 00 00 mov $0x137,%eax ;%rsp+0xc的内存地址内容与%eax相比较 400fbe: 3b 44 24 0c cmp 0xc(%rsp),%eax ;%eax寄存器中的数据等于%rsp+0xc的内存地址中的数据,跳转到0x400fc9 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 ;返回到调用函数(main函数) 400fcd: c3 retq
这段代码是调用sscanf函数
有"%d %d"可知需要输入两个数值。
400f6a: 83 7c 24 08 07 cmpl $0x7,0x8(%rsp)
;%rsp+0x8的内存数据大于0x7则跳转到0x400fad
400f6f: 77 3c ja 400fad <phase_3+0x6a>
;发生爆炸
400fad: e8 88 04 00 00 callq 40143a <explode_bomb>
由这段代码得第一个数值必须小于7
;将0xcf赋值给%eax
400f7c: b8 cf 00 00 00 mov $0xcf,%eax
;跳转到0x400fbe
400f81: eb 3b jmp 400fbe <phase_3+0x7b>
;%rsp+0xc的内存地址内容与%eax相比较
400fbe: 3b 44 24 0c cmp 0xc(%rsp),%eax
;%eax寄存器中的数据等于%rsp+0xc的内存地址中的数据,跳转到0x400fc9
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
;返回到调用函数(main函数)
400fcd: c3 retq
将%eax赋值为7个不同的值,与0xc(%rsp),即第二个数值相比较,若相同则成功避开炸弹
所以不妨大胆猜想
400f75: ff 24 c5 70 24 40 00 jmpq *0x402470(,%rax,8)
这句代码中表达式*0x402470(,%rax,8)的含义是 switch选择语句
果不其然,书上有例子,唉,还得常翻书 -_ -||
所以随便选择就好,我就选择2吧
;将0x2c3赋值给%eax
400f83: b8 c3 02 00 00 mov $0x2c3,%eax
;跳转到0x400fbe
400f88: eb 34 jmp 400fbe <phase_3+0x7b>
0x2c3转换为十进制,707
000000000040100c <phase_4>: ;开辟0x18(24)个字节 40100c: 48 83 ec 18 sub $0x18,%rsp ;将%rsp+0xc的内存地址赋值给%rcx 401010: 48 8d 4c 24 0c lea 0xc(%rsp),%rcx ;将%rsp+0x8的内存地址赋值给%rdx 401015: 48 8d 54 24 08 lea 0x8(%rsp),%rdx ;将0x4025cf内存地址内容赋值给%esi 40101a: be cf 25 40 00 mov $0x4025cf,%esi ;将0x0赋值给%eax 40101f: b8 00 00 00 00 mov $0x0,%eax ;调用__isoc99_sscanf函数 401024: e8 c7 fb ff ff callq 400bf0 <__isoc99_sscanf@plt> ;将0x2与%eax相比较 401029: 83 f8 02 cmp $0x2,%eax ;若不相等,则进行跳转0x401035 40102c: 75 07 jne 401035 <phase_4+0x29> ;将0xe与%rsp+0x8的内存地址数据相比较 40102e: 83 7c 24 08 0e cmpl $0xe,0x8(%rsp) ;%rsp+0x8的内存地址数据小于等于(<=)0xe,则进行跳转到0x40103a 401033: 76 05 jbe 40103a <phase_4+0x2e> ;发生爆炸 401035: e8 00 04 00 00 callq 40143a <explode_bomb> ;将0xe赋值给%edx 40103a: ba 0e 00 00 00 mov $0xe,%edx ;将0x0赋值给%esi 40103f: be 00 00 00 00 mov $0x0,%esi ;将%rsp+0x8的内存地址内容的数据赋值给%edi 401044: 8b 7c 24 08 mov 0x8(%rsp),%edi ;调用func4函数 401048: e8 81 ff ff ff callq 400fce <func4> ;将%eax寄存器中的数据与0相比较 40104d: 85 c0 test %eax,%eax ;若%eax寄存器中的数据与0不相等则进行跳转0x401058 40104f: 75 07 jne 401058 <phase_4+0x4c> ;将0x0与%rsp+0xc的内存地址数据相比较 401051: 83 7c 24 0c 00 cmpl $0x0,0xc(%rsp) ;若0x0与%rsp+0xc的内存地址数据相等则进行跳转到0x40105d 401056: 74 05 je 40105d <phase_4+0x51> ;发生爆炸 401058: e8 dd 03 00 00 callq 40143a <explode_bomb> ;清除栈内存空间 40105d: 48 83 c4 18 add $0x18,%rsp ;pop %rip,返回到调用函数(main函数) 401061: c3 retq
;将0xe与%rsp+0x8的内存地址数据相比较
40102e: 83 7c 24 08 0e cmpl $0xe,0x8(%rsp)
;%rsp+0x8的内存地址数据小于等于(<=)0xe,则进行跳转到0x40103a
401033: 76 05 jbe 40103a <phase_4+0x2e>
;发生爆炸
401035: e8 00 04 00 00 callq 40143a <explode_bomb>
由上边的代码得知,0x8(%rsp),第一个输入的数据得<=0x8(14)
;将0x0与%rsp+0xc的内存地址数据相比较
401051: 83 7c 24 0c 00 cmpl $0x0,0xc(%rsp)
;若0x0与%rsp+0xc的内存地址数据相等则进行跳转到0x40105d
401056: 74 05 je 40105d <phase_4+0x51>
;发生爆炸
401058: e8 dd 03 00 00 callq 40143a <explode_bomb>
由上述代码得,0xc(%rsp),第二个输入的数据为0
;将0xe与%rsp+0x8的内存地址数据相比较
40102e: 83 7c 24 08 0e cmpl $0xe,0x8(%rsp)
;%rsp+0x8的内存地址数据小于等于(<=)0xe,则进行跳转到0x40103a
401033: 76 05 jbe 40103a <phase_4+0x2e>
;发生爆炸
401035: e8 00 04 00 00 callq 40143a <explode_bomb>
由上述代码得第一个输入得数据<=14
接下来分析func4函数
func4函数的汇编代码
0000000000400fce <func4>: ;开辟0x8(8)个字节大小的栈内存空间 400fce: 48 83 ec 08 sub $0x8,%rsp ;将%edx赋值给%eax 400fd2: 89 d0 mov %edx,%eax ;将%eax-%esi 400fd4: 29 f0 sub %esi,%eax ;将%eax赋值给%ecx 400fd6: 89 c1 mov %eax,%ecx ;将%ecx中的数据逻辑右移31位 400fd8: c1 e9 1f shr $0x1f,%ecx ;%eax=%eax+%ecx 400fdb: 01 c8 add %ecx,%eax ;将%eax算术右移1位 400fdd: d1 f8 sar %eax ;将(%rsi*1+%rax)的内存地址赋值给%ecx 400fdf: 8d 0c 30 lea (%rax,%rsi,1),%ecx ;将%edi与%ecx相比较 400fe2: 39 f9 cmp %edi,%ecx ;小于等于进行跳转0x400ff2 400fe4: 7e 0c jle 400ff2 <func4+0x24> ;将%rcx-0x1的内存地址赋值给%edx 400fe6: 8d 51 ff lea -0x1(%rcx),%edx ;调用func4函数 400fe9: e8 e0 ff ff ff callq 400fce <func4> ;%eax=%eax+%eax 400fee: 01 c0 add %eax,%eax ;无条件跳转到0x401007 400ff0: eb 15 jmp 401007 <func4+0x39> ;将0x0赋值给%eax 400ff2: b8 00 00 00 00 mov $0x0,%eax ;%edi与%ecx相比较 400ff7: 39 f9 cmp %edi,%ecx ;小于等于进行跳转0x401007 400ff9: 7d 0c jge 401007 <func4+0x39> ;将%rcx+0x1赋值给%esi 400ffb: 8d 71 01 lea 0x1(%rcx),%esi ;调用func4函数 400ffe: e8 cb ff ff ff callq 400fce <func4> ;将(%rax*1+%rax)+0x1的地址赋值给%eax 401003: 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax ;清除栈内存空间 401007: 48 83 c4 08 add $0x8,%rsp ;pop %rip 返回到调用函数(main函数) 40100b: c3 retq
唉,作弊一下,借助一下IDA。
经分析 v3=(14-0)/2+0 = 7;
v3== a1 时return 0
经分析第一个参数可以为0/1/3/7
我们选择(a1)第一个数据为7
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。