一、实验目的
- 通过objdump命令对bomb文件进行反汇编从而得到汇编代码
- 进一步将C语言代码与汇编代码进行联系理解,从而更深刻地理解汇编代码和其中的各种操作
- 通过GDB对汇编代码进行调试和分析,包括逐步运行汇编代码、断点设置、查看寄存器和内存内容等操作,从而进一步的熟悉操作。
二、实验内容与实验步骤
先使用objdump -d bomb > bomb_assembly.S将bomb文件进行反汇编,并将反汇编代码保存到bomb_assembly.S文件中,再进行调试。
1.phase1
0000000000400ee0 <phase_1>:
400ee0: 48 83 ec 08 subq $8, %rsp
400ee4: be 00 24 40 00 movl $4203520, %esi
400ee9: e8 4a 04 00 00 callq 0x401338 <strings_not_equal>
400eee: 85 c0 testl %eax, %eax
400ef0: 74 05 je 0x400ef7 <phase_1+0x17>
400ef2: e8 43 05 00 00 callq 0x40143a <explode_bomb>
400ef7: 48 83 c4 08 addq $8, %rsp
400efb: c3 retq
(1)使用gdb运行程序然后设置断点。
(2)查看寄存器%rsi中保存的内容,在mov指令前其中为输入的字符串,得到phase1答案为:Border relations with Canada have never been better.
2.phase2
对汇编代码进行分析:
0000000000400efc <phase_2>:
400efc: 55 pushq %rbp
400efd: 53 pushq %rbx
400efe: 48 83 ec 28 subq $40, %rsp
400f02: 48 89 e6 movq %rsp, %rsi
400f05: e8 52 05 00 00 callq 0x40145c <read_six_numbers>
400f0a: 83 3c 24 01 cmpl $1, (%rsp)
400f0e: 74 20 je 0x400f30 <phase_2+0x34>
400f10: e8 25 05 00 00 callq 0x40143a <explode_bomb>
400f15: eb 19 jmp 0x400f30 <phase_2+0x34>
400f17: 8b 43 fc movl -4(%rbx), %eax
400f1a: 01 c0 addl %eax, %eax
400f1c: 39 03 cmpl %eax, (%rbx)
400f1e: 74 05 je 0x400f25 <phase_2+0x29>
400f20: e8 15 05 00 00 callq 0x40143a <explode_bomb>
400f25: 48 83 c3 04 addq $4, %rbx
400f29: 48 39 eb cmpq %rbp, %rbx
400f2c: 75 e9 jne 0x400f17 <phase_2+0x1b>
400f2e: eb 0c jmp 0x400f3c <phase_2+0x40>
400f30: 48 8d 5c 24 04 leaq 4(%rsp), %rbx
400f35: 48 8d 6c 24 18 leaq 24(%rsp), %rbp
400f3a: eb db jmp 0x400f17 <phase_2+0x1b>
400f3c: 48 83 c4 28 addq $40, %rsp
400f40: 5b popq %rbx
400f41: 5d popq %rbp
400f42: c3 retq
从代码中可以看出第二个炸弹由 6 个数字组成,
且分别保存在%rsp, %rsp+4, %rsp+8, …, %rsp+20 中
根据 0x0000000000400f0a <+14>: cmpl $0x1,(%rsp) 得出第一个数字为 1
根据 0x0000000000400f17 <+27>: mov -0x4(%rbx), %eax
0x0000000000400f1a <+30>:add %eax, %eax
0x0000000000400f1c <+32>:cmp %eax,(%rbx) 得出后一个数是前一个数的两倍
答案为:1 2 4 8 16 32
3.phase3
先分析汇编代码
0000000000400f43 <phase_3>:
400f43: 48 83 ec 18 sub $0x18,%rsp//分配栈内存
400f47: 48 8d 4c 24 0c lea 0xc(%rsp),%rcx//对%rcx进行取址
400f4c: 48 8d 54 24 08 lea 0x8(%rsp),%rdx//对%rdx进行取址
400f51: be cf 25 40 00 mov $0x4025cf,%esi//将内存地址赋给%esi
400f56: b8 00 00 00 00 mov $0x0,%eax//将%eax清空
400f5b: e8 90 fc ff ff callq 400bf0 <__isoc99_sscanf@plt>//调用
400f60: 83 f8 01 cmp $0x1,%eax//将函数返回值与1进行比较
400f63: 7f 05 jg 400f6a <phase_3+0x27>//若大于则跳转 至400f6a
400f65: e8 d0 04 00 00 callq 40143a <explode_bomb>//否则炸弹爆炸
在mov指令执行前,%esi和%eax中存储的是输入的字符串,而在mov后%esi中存储为“%d %d”,所以输入为两个整数
继续分析代码
400f6a: 83 7c 24 08 07 cmpl $0x7,0x8(%rsp)//将第一个数与7进行比较
400f6f: 77 3c ja 400fad <phase_3+0x6a>//若超过则跳转 至400fad,炸弹爆炸
400f71: 8b 44 24 08 mov 0x8(%rsp),%eax//将第一个数赋值给%eax
400f75: ff 24 c5 70 24 40 00 jmpq *0x402470(,%rax,8)//进入switch语句 的跳转表,跳转至jt[%rax],内存地址0x402470存储跳转表
由此部分可知本关的代码为switch语句,输入的第一个整数的范围是0~7,跳转表为
400f7c为case 0,400fb9为case 1,400f83为case 2,400f8a为case 3,400f91为case 4,400f98为case 5,400f9f为case 6,400fa6为case 7
400f7c: b8 cf 00 00 00 mov $0xcf,%eax//赋值%eax为207
400f81: eb 3b jmp 400fbe <phase_3+0x7b>//跳转至 400fbe
400f83: b8 c3 02 00 00 mov $0x2c3,%eax//赋值为707
400f88: eb 34 jmp 400fbe <phase_3+0x7b>//跳转至比较
400f8a: b8 00 01 00 00 mov $0x100,%eax//赋值为256
400f8f: eb 2d jmp 400fbe <phase_3+0x7b>//跳转至比较
400f91: b8 85 01 00 00 mov $0x185,%eax//赋值为389
400f96: eb 26 jmp 400fbe <phase_3+0x7b>//跳转
400f98: b8 ce 00 00 00 mov $0xce,%eax//赋值为206
400f9d: eb 1f jmp 400fbe <phase_3+0x7b>//跳转
400f9f: b8 aa 02 00 00 mov $0x2aa,%eax//赋值为682
400fa4: eb 18 jmp 400fbe <phase_3+0x7b>//跳转
400fa6: b8 47 01 00 00 mov $0x147,%eax//赋值为327
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//赋值%eax为0
400fb7: eb 05 jmp 400fbe <phase_3+0x7b>//跳转至比较
400fb9: b8 37 01 00 00 mov $0x137,%eax//赋值%eax为311
400fbe: 3b 44 24 0c cmp 0xc(%rsp),%eax//第二个数与%eax进行比较
400fc2: 74 05 je 400fc9 <phase_3+0x86>//相等则跳转至 400fc9,释放栈内存,返回
400fc4: e8 71 04 00 00 callq 40143a <explode_bomb>//否则炸弹爆炸
400fc9: 48 83 c4 18 add $0x18,%rsp//释放栈内存
400fcd: c3 retq
该部分为switch内部语句,对于每一个case,其内容为如下形式
switch (x)
{
case 0:
if (n != n1) //explode
break;
case 1: //结构同上
}
通过查看跳转表得出对应的整数组合:0 207,1 311,2 707,3 256,4 389,5 206,6 682,7 327为八个答案
4.phase4
000000000040100c <phase_4>:
40100c: 48 83 ec 18 subq $24, %rsp
401010: 48 8d 4c 24 0c leaq 12(%rsp), %rcx
401015: 48 8d 54 24 08 leaq 8(%rsp), %rdx
40101a: be cf 25 40 00 movl $4203983, %esi
40101f: b8 00 00 00 00 movl $0, %eax
401024: e8 c7 fb ff ff callq 0x400bf0 <__isoc99_sscanf@plt>
401029: 83 f8 02 cmpl $2, %eax
40102c: 75 07 jne 0x401035 <phase_4+0x29>
40102e: 83 7c 24 08 0e cmpl $14, 8(%rsp)
401033: 76 05 jbe 0x40103a <phase_4+0x2e>
401035: e8 00 04 00 00 callq 0x40143a <explode_bomb>
40103a: ba 0e 00 00 00 movl $14, %edx
40103f: be 00 00 00 00 movl $0, %esi
401044: 8b 7c 24 08 movl 8(%rsp), %edi
401048: e8 81 ff ff ff callq 0x400fce <func4>
40104d: 85 c0 testl %eax, %eax
40104f: 75 07 jne 0x401058 <phase_4+0x4c>
401051: 83 7c 24 0c 00 cmpl $0, 12(%rsp)
401056: 74 05 je 0x40105d <phase_4+0x51>
401058: e8 dd 03 00 00 callq 0x40143a <explode_bomb>
40105d: 48 83 c4 18 addq $24, %rsp
401061: c3 retq
设 fun4 的两个参数分别为 x,y
根据 fun4 之后的反汇编代码,很容易看出只有当 fun4()返回值为 0 且 y = 0,才能解除炸弹。逐步调试,直到第 10 行,比较%edi 和 %ecx 的值。
(gdb) print/d $ecx
$17 = 7
查看%ecx 寄存器的值,并把这个值作为 x。
答案为:7 0
5.phase5
分析代码
0000000000401062 <phase_5>:
401062: 53 push %rbx//入栈
401063: 48 83 ec 20 sub $0x20,%rsp//分配栈内存
401067: 48 89 fb mov %rdi,%rbx//用%rdi赋值给%rbx,内容为 输入的字符串
40106a: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax//用%fs:0x28给%rax赋值
401071: 00 00
401073: 48 89 44 24 18 mov %rax,0x18(%rsp)//将%rax的内容存入栈
401078: 31 c0 xor %eax,%eax//%rax的低四字节进行异或清零
40107a: e8 9c 02 00 00 callq 40131b <string_length>//调用函数 string_length
40107f: 83 f8 06 cmp $0x6,%eax//将返回值和6进行比较
401082: 74 4e je 4010d2 <phase_5+0x70>//若相等则跳转 至4010d2
401084: e8 b1 03 00 00 callq 40143a <explode_bomb>//否则炸弹爆炸
此处%rdi中存储的字符串长度为6
分析跳转后的代码
4010d2: b8 00 00 00 00 mov $0x0,%eax//将%eax赋值为0
4010d7: eb b2 jmp 40108b <phase_5+0x29>//跳转至 40108b
40108b: 0f b6 0c 03 movzbl (%rbx,%rax,1),%ecx//将%rbx+%rax的 第四字节赋值给%ecx,并清零其高四字节
//此时%ecx当中存储的是输入的字符串的第%rax+1个字符,即string[%rax]
此时%ecx中存储的是输入字符串的第%rax+1个字符,即string[%rax],但x/s命令不可访问
继续分析
40108f: 88 0c 24 mov %cl,(%rsp)//将%cl的地址放入栈顶
401092: 48 8b 14 24 mov (%rsp),%rdx//将栈顶的内容赋值给%rdx, 即%cl
401096: 83 e2 0f and $0xf,%edx//将0xf与%edx的内容进行与操 作,即保留其低4位,清空高位
401099: 0f b6 92 b0 24 40 00 movzbl 0x4024b0(%rdx),%edx//对%edx进行赋值 为0x4024b0+%rdx,并清空高4字节
0x4024b0内容为一个字符串: “maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?”,所以此时%edx中存储的是0x4024b0的字符串的第%rdx个字符,所以认为这段代码应该是将%ecx中字符的ASCII码的低s四位存入%rdx
继续分析
4010a0: 88 54 04 10 mov %dl,0x10(%rsp,%rax,1)//将%dl的值存 入栈中%rsp+16+%rax的位置
4010a4: 48 83 c0 01 add $0x1,%rax//++%rax
4010a8: 48 83 f8 06 cmp $0x6,%rax//将%rax与6进行比较
4010ac: 75 dd jne 40108b <phase_5+0x29>//若不相等则跳 转至40108b,循环操作
将存有字符的%edx的最低一字节放入栈中对应位置,当%rax小于6时进行循环操作,所以%rax=0-5会进行六次操作,得到六个字符存入栈中连续的位置,%rsp+16~%rsp+21,生成了一个含有六个字符的字符串,这六个字符串分别与输入字符串的低4位ASCII码在0x4024b0的字符串对应下标字符对应
继续分析
4010ae: c6 44 24 16 00 movb $0x0,0x16(%rsp)//将%rsp+22最低字节 赋值位0
4010b3: be 5e 24 40 00 mov $0x40245e,%esi//将%esi赋值为 0x40245e的内容
4010b8: 48 8d 7c 24 10 lea 0x10(%rsp),%rdi//%rdi取址为%rsp+16
4010bd: e8 76 02 00 00 callq 401338 <strings_not_equal>//调用函 数strings_not_equal,字符串相同时返回0,不同时返回1
4010c2: 85 c0 test %eax,%eax//测试返回值
4010c4: 74 13 je 4010d9 <phase_5+0x77>//返回为0则跳 转至4010d9
4010c6: e8 6f 03 00 00 callq 40143a <explode_bomb>//否则炸弹爆炸
4010d9: 48 8b 44 24 18 mov 0x18(%rsp),%rax//将%rsp+24地址赋值 给%rax
4010de: 64 48 33 04 25 28 00 xor %fs:0x28,%rax//将%fs:0x28与%rax进行 异或
4010e5: 00 00
4010e7: 74 05 je 4010ee <phase_5+0x8c>//若相等则跳转 至4010ee
4010e9: e8 42 fa ff ff callq 400b30 <__stack_chk_fail@plt>//否 则调用函数__stack_chk_fail@plt
4010ee: 48 83 c4 20 add $0x20,%rsp//释放栈内存
4010f2: 5b pop %rbx//%rbx出栈
4010f3: c3 retq
这段代码将0x40245e的内容赋值给%esi,查看该内存位置的内容,发现其为一个长度为六的字符串: “flyers”,之后将%rdi取址%rsp+16,即在上一步骤中获得的字符串的首地址,然后调用函数strings_not_equal,该函数对两个字符串进行比较,相等时返回0,否则返回1,当返回1时炸弹引爆,返回0时经过进一步操作完成本关。
综上可知本关的输入是长度为六的字符串,该字符串每个字符的ASCII码的低四位在0x4024b0的字符串中对应确定一个字符,组成新的长度为6的字符串,该字符串与0x40245e的字符串相同。
在“flyers”中每个字符分别位于“maduiersnfotvbylSo you think you can stop the bomb with ctrlc, do you?”第9,15,14,5,6,7位,四位二进制表示为1001,1111,1110,0101,0110,0111,对应可取字符i,o,n,e,f,g
所以答案为:ionefg
6.phase6
00000000004010f4 <phase_6>:
4010f4: 41 56 pushq %r14
4010f6: 41 55 pushq %r13
4010f8: 41 54 pushq %r12
4010fa: 55 pushq %rbp
4010fb: 53 pushq %rbx
4010fc: 48 83 ec 50 subq $80, %rsp
401100: 49 89 e5 movq %rsp, %r13
401103: 48 89 e6 movq %rsp, %rsi
401106: e8 51 03 00 00 callq 0x40145c <read_six_numbers>
40110b: 49 89 e6 movq %rsp, %r14
40110e: 41 bc 00 00 00 00 movl $0, %r12d
401114: 4c 89 ed movq %r13, %rbp
401117: 41 8b 45 00 movl (%r13), %eax
40111b: 83 e8 01 subl $1, %eax
40111e: 83 f8 05 cmpl $5, %eax
401121: 76 05 jbe 0x401128 <phase_6+0x34>
401123: e8 12 03 00 00 callq 0x40143a <explode_bomb>
401128: 41 83 c4 01 addl $1, %r12d
40112c: 41 83 fc 06 cmpl $6, %r12d
401130: 74 21 je 0x401153 <phase_6+0x5f>
401132: 44 89 e3 movl %r12d, %ebx
401135: 48 63 c3 movslq %ebx, %rax
401138: 8b 04 84 movl (%rsp,%rax,4), %eax
40113b: 39 45 00 cmpl %eax, (%rbp)
40113e: 75 05 jne 0x401145 <phase_6+0x51>
401140: e8 f5 02 00 00 callq 0x40143a <explode_bomb>
401145: 83 c3 01 addl $1, %ebx
401148: 83 fb 05 cmpl $5, %ebx
40114b: 7e e8 jle 0x401135 <phase_6+0x41>
40114d: 49 83 c5 04 addq $4, %r13
401151: eb c1 jmp 0x401114 <phase_6+0x20>
401153: 48 8d 74 24 18 leaq 24(%rsp), %rsi
401158: 4c 89 f0 movq %r14, %rax
40115b: b9 07 00 00 00 movl $7, %ecx
401160: 89 ca movl %ecx, %edx
401162: 2b 10 subl (%rax), %edx
401164: 89 10 movl %edx, (%rax)
401166: 48 83 c0 04 addq $4, %rax
40116a: 48 39 f0 cmpq %rsi, %rax
40116d: 75 f1 jne 0x401160 <phase_6+0x6c>
40116f: be 00 00 00 00 movl $0, %esi
401174: eb 21 jmp 0x401197 <phase_6+0xa3>
401176: 48 8b 52 08 movq 8(%rdx), %rdx
40117a: 83 c0 01 addl $1, %eax
40117d: 39 c8 cmpl %ecx, %eax
40117f: 75 f5 jne 0x401176 <phase_6+0x82>
401181: eb 05 jmp 0x401188 <phase_6+0x94>
401183: ba d0 32 60 00 movl $6304464, %edx
401188: 48 89 54 74 20 movq %rdx, 32(%rsp,%rsi,2)
40118d: 48 83 c6 04 addq $4, %rsi
401191: 48 83 fe 18 cmpq $24, %rsi
401195: 74 14 je 0x4011ab <phase_6+0xb7>
401197: 8b 0c 34 movl (%rsp,%rsi), %ecx
40119a: 83 f9 01 cmpl $1, %ecx
40119d: 7e e4 jle 0x401183 <phase_6+0x8f>
40119f: b8 01 00 00 00 movl $1, %eax
4011a4: ba d0 32 60 00 movl $6304464, %edx
4011a9: eb cb jmp 0x401176 <phase_6+0x82>
4011ab: 48 8b 5c 24 20 movq 32(%rsp), %rbx
4011b0: 48 8d 44 24 28 leaq 40(%rsp), %rax
4011b5: 48 8d 74 24 50 leaq 80(%rsp), %rsi
4011ba: 48 89 d9 movq %rbx, %rcx
4011bd: 48 8b 10 movq (%rax), %rdx
4011c0: 48 89 51 08 movq %rdx, 8(%rcx)
4011c4: 48 83 c0 08 addq $8, %rax
4011c8: 48 39 f0 cmpq %rsi, %rax
4011cb: 74 05 je 0x4011d2 <phase_6+0xde>
4011cd: 48 89 d1 movq %rdx, %rcx
4011d0: eb eb jmp 0x4011bd <phase_6+0xc9>
4011d2: 48 c7 42 08 00 00 00 00 movq $0, 8(%rdx)
4011da: bd 05 00 00 00 movl $5, %ebp
4011df: 48 8b 43 08 movq 8(%rbx), %rax
4011e3: 8b 00 movl (%rax), %eax
4011e5: 39 03 cmpl %eax, (%rbx)
4011e7: 7d 05 jge 0x4011ee <phase_6+0xfa>
4011e9: e8 4c 02 00 00 callq 0x40143a <explode_bomb>
4011ee: 48 8b 5b 08 movq 8(%rbx), %rbx
4011f2: 83 ed 01 subl $1, %ebp
4011f5: 75 e8 jne 0x4011df <phase_6+0xeb>
4011f7: 48 83 c4 50 addq $80, %rsp
4011fb: 5b popq %rbx
4011fc: 5d popq %rbp
4011fd: 41 5c popq %r12
4011ff: 41 5d popq %r13
401201: 41 5e popq %r14
401203: c3 retq
结合phase_2可知,本关输入也为六个数字,且第一个输入的数字要小于等于6
401128-401151部分通过循环操作,确定输入的六个数字互不相同,且都小于等于6,所以这六个整数取址范围为1~6
401153-40116d部分将输入的每个数在栈中替换为7-该数,即%rsp到%rsp+20中的n1, n2, n3, n4, n5, n6, n7变为了7-n1, 7-n2, 7-n3, 7-n4, 7-n5, 7-n6, 7-n7,处理完后跳出该循环
40116f-40117f部分中有一个内存部分0x6032d0,查看后发现其内部为一个链表,node1 = 332,node2 =
168,node3 = 924,node4 = 691,node5 = 477,node6 = 443,操作中通过栈中的六个数字作
为序列对链表元素进行入栈操作,存储在%rsp+32~%rsp+32+40的栈内存中
4011ab-4011cb该部分将入栈后的链表元素按照入栈的顺序进行重新的链表连接
4011d2-401203部分将栈内存中的链表节点内容进行比较,当前一个节点的内容小于等于后一个节点的值时炸弹引爆,所以节点的内容按照降序排列,即节点入栈的顺序需要按照其内容的值从大到小进行入栈,已知924 > 691 > 477 > 443 > 332 > 168,所以节点入栈的顺序为3,4,5,6,1,2,每个下标对应了7-n,所以输入的六个数字为4 3 2 1 6 5
所以答案为:4 3 2 1 6 5