任务目标
通过反汇编可执行程序,来反推出程序执行内容
找到六个正确的字符串来解除自己的炸弹
操作指南
wget <http://csapp.cs.cmu.edu/3e/bomb.tar>
共有6个 phase,难度逐级提升
objdump-用于反汇编二进制对象文件
gdb-用于运行时单步调试与查看运行时内存与寄存器信息
前置知识
寄存器:存储最常用的数据
常用汇编指令
b w l q 字节1 2 4 8
//传送语句
leaq S,D //加载有效地址D←&S
mov S,D //S传向D(源-目的)
movq (%rdi),%rax //从内存中读值到寄存器
movq %rsi,(%rdi) //从寄存器写到内存 括号括起来表示--寻内存的地址
//控制语句
cmp a,b //比较 计算b-a cmpb,cmpw,cmpl,cmpq
test b,a //测试 a&b
test a,a //检查a是正数 负数 还是0
jmp //跳转
je //相等时跳
jne //不等时跳
jg //大于时
jl //小于时
jbe //<=时
//过程语句
call //调用
ret //从调用返回
//栈相关
pushq S //入栈
popq D //出栈
//算数 逻辑
//二元操作
add S,D //D←D+S
sub S,D //D←D-S
imul S,D //D←D*S 乘
xor S,D //D←D^S 异或
and S,D //D←D&S 与
//移位操作
sar k,D //算数右移 D>>k
sal D //D默认左移一位
shr k,D //逻辑右移
shr $0x1f,%ecx //ecx >> 31
//核心
//phase_4 递归
//phase_5 for循环
and $0xf,%edx; //得到当前字符的后四位
movzbl 0x4024b0(%rdx),%edx; //edx = *(rdx + 0x4024b0); 0x4024b0处存了个字符串,每次获取第%rdx个字符,%rdx从输入所获得的字符的后四位
(gdb) x/s 0x4024b0 //数组选择前16位,"maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?"
//输入rdx--每个字符&0xf--将其作为maduiersnfotvbyl的下标选择字符
//phase_6 链表 结构体
struct {
int value;
int order;
node* next;
} node;
//输入正确的order--使node的value从大到小排列
//6个node由大到小排序 对node排序(345612)✅ VS ❌将6个值从大到小排序 对值排序
node1: 0x14c 5
node2: 0x0a8 6
node3: 0x39c 1
node4: 0x2b3 2
node5: 0x1dd 3
node6: 0x1bb 4
node3 > node4 > node5 > node6 > node1 > node2
常用操作符含义
gdb命令
内存如何存储数据?
内存模型——-堆+栈
实例
int add_a_and_b(int a, int b) {
return a + b;
}
int main() {
return add_a_and_b(2, 3);
}
tmux常用命令+vim语法高亮
参考www.ruanyifeng.com/blog/2019/1…
//tmux常用命令
tmux //启动tmux
ctrl + d 或 exit //退出tmux
ctrl + b % //划分左右两窗口
ctrl + b " //划分上下两窗口
ctrl + b <箭头> //移动光标到上下左右窗格
ctrl + b x //关闭当前窗格
//vim语法高亮
:syntax on
vimrc配置 ... //配置完可以一直使用
//用到的gdb命令
gdb bomb //开始调试
x/s 0x4025cf //查看这个地址的字符串
0x4025cf: "%d %d"
print (char *) 0x4025cf//同上
jmpq *0x402470(,%rax,8) //间接跳转 是switch特征 dst=0x402470 + 8 * rax
x/8g 0x402470 //检查以0x402470为起始地址的8个内存地址里的内容
x/8a 0x402470
b explode_bomb //打断点
b phase_1
set args ./solution.txt //设置参数
run //运行
continue // 继续运行
info registers //查看寄存器内容
题目解法
bomb.c — 找到main 函数 — 看注释
objdump命令将炸弹文件反汇编出来:
objdump -d bomb > bomb.s
main 函数
【1】phase 1
考察 字符串
0000000000400ee0 <phase_1>:
400ee0: 48 83 ec 08 subq $8, %rsp #栈指针减8
400ee4: be 00 24 40 00 movl $4203520, %esi # imm = 0x402400 #第二个参数传0x402400
400ee9: e8 4a 04 00 00 callq 0x401338 <strings_not_equal> #调用函数 <strings_not_equal>
400eee: 85 c0 testl %eax, %eax #验证函数 <strings_not_equal>返回值
400ef0: 74 05 je 0x400ef7 <phase_1+0x17> # 如果返回值为0,跳转0x400ef7
400ef2: e8 43 05 00 00 callq 0x40143a <explode_bomb> # 如果返回值不为0,爆炸
400ef7: 48 83 c4 08 addq $8, %rsp
400efb: c3 retq
phase_1(rdi){
esi = 0x402400;
strings_not_equal(rdi,rsi);
if(eax === 0) {
retq
}
callq explode_bomb;
}
gdb -q bomb # -q 安静模式
layout split
b phase_1
b explode_bomb
“Border relations with Canada have never been better.”
【1】phase 2
考察 数组和循环
0000000000400efc <phase_2>:
400efc: 55 pushq %rbp #栈帧相关:被调用者保存
400efd: 53 pushq %rbx #栈帧相关:被调用者保存
400efe: 48 83 ec 28 subq $40, %rsp # 栈指针减40
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) #比较rsp内存地址是否是1
400f0e: 74 20 je 0x400f30 <phase_2+0x34> #是1则跳转0x400f30
400f10: e8 25 05 00 00 callq 0x40143a <explode_bomb> #否则爆炸
400f15: eb 19 jmp 0x400f30 <phase_2+0x34> 跳转0x400f30
400f17: 8b 43 fc movl -4(%rbx), %eax #%rax = rbx内存地址减去4
400f1a: 01 c0 addl %eax, %eax # rax+=rax
400f1c: 39 03 cmpl %eax, (%rbx) #比较rbx内存地址是否是 rax
400f1e: 74 05 je 0x400f25 <phase_2+0x29> #是 跳转0x400f25
400f20: e8 15 05 00 00 callq 0x40143a <explode_bomb> #否 爆炸
400f25: 48 83 c3 04 addq $4, %rbx #rbx+= 4
400f29: 48 39 eb cmpq %rbp, %rbx #比较rbx是否等于rbp
400f2c: 75 e9 jne 0x400f17 <phase_2+0x1b> #不等于 跳转0x400f17
400f2e: eb 0c jmp 0x400f3c <phase_2+0x40> #跳转0x400f3c
400f30: 48 8d 5c 24 04 leaq 4(%rsp), %rbx #栈指针+4后赋值给 rbx
400f35: 48 8d 6c 24 18 leaq 24(%rsp), %rbp #栈指针+24后赋值给 rbp
400f3a: eb db jmp 0x400f17 <phase_2+0x1b> # 跳转0x400f17
400f3c: 48 83 c4 28 addq $40, %rsp
400f40: 5b popq %rbx
400f41: 5d popq %rbp
400f42: c3 retq
<read_six_numbers>
000000000040145c <read_six_numbers>:
40145c: 48 83 ec 18 **subq $24, %rsp #设置6个数字**
401460: 48 89 f2 movq %rsi, %rdx
401463: 48 8d 4e 04 leaq 4(%rsi), %rcx
401467: 48 8d 46 14 leaq 20(%rsi), %rax
40146b: 48 89 44 24 08 movq %rax, 8(%rsp)
401470: 48 8d 46 10 leaq 16(%rsi), %rax
401474: 48 89 04 24 movq %rax, (%rsp)
401478: 4c 8d 4e 0c leaq 12(%rsi), %r9
40147c: 4c 8d 46 08 leaq 8(%rsi), %r8
401480: be c3 25 40 00 movl $4203971, %esi # imm = 0x4025C3
401485: b8 00 00 00 00 movl $0, %eax
40148a: e8 61 f7 ff ff callq 0x400bf0 **<__isoc99_sscanf@plt>**
40148f: 83 f8 05 cmpl $5, %eax
401492: 7f 05 jg 0x401499 <read_six_numbers+0x3d>
401494: e8 a1 ff ff ff callq 0x40143a <explode_bomb>
401499: 48 83 c4 18 **addq $24, %rsp**
40149d: c3 retq
- 可读性调整
phase_2(rdi) {
rsi = rsp - 40;
callq <read_six_numbers>;
if(*rsp == 1){ #注意是*rsp
go to 0x400f30;
}
callq <explode_bomb>;
400f17:
rax = *(rbx - 4);
rax += rax;
if(*rbx == rax){
goto 0x400f25;
}
callq <explode_bomb>;
400f25:
rbx += 4;
if(rbx != rbp){
goto 0x400f17; #循环
} else {
goto 0x400f3c; #循环结束
}
400f30:
rbx = rsp + 4;
rbp = rsp + 24;
goto 0x400f17;
400f3c:
popq
retq
}
- C 风格
phase_2(a) {
rsi = rsp - 40;
read_six_numbers;
if(*rsp !== 1) bomb; # 说明 *rsp = 1
rbx = rsp + 4; # 初始值
rbp = rsp + 24; # 6个
do {
rax += *(rbx - 4);
if(*rbx != rax) bomb; # 说明 *rbx = 2 *(rbx-4);
rbx += 4;
}
while(rbx != rbp)
ret
}
- C 伪代码
phase_2(char *a) {
int b;
read_six_numbers(a, b);
if(b[0] !== 1) bomb(); # 说明 第一个元素 = 1
for(i = 1; i < 6; i++){
b[i-1] += b[i-1]; # 说明 数组中后一个元素是前一个元素的2倍
if(b[i] != b[i-1]) bomb();
}
return
}
- 答案
1 2 4 8 16 32
【1】phase 3
考察 switch-case
0000000000400f43 <phase_3>:
400f43: 48 83 ec 18 subq $24, %rsp # 6个变量
400f47: 48 8d 4c 24 0c leaq 12(%rsp), %rcx #栈指针+12后赋值给 rcx
400f4c: 48 8d 54 24 08 leaq 8(%rsp), %rdx #栈指针+8后赋值给 rdx
400f51: be cf 25 40 00 movl 0x4025CF, %esi #gdb: x/s 0x4025CF => rsi = '%d %d'
400f56: b8 00 00 00 00 movl $0, %eax #rax = 0
400f5b: e8 90 fc ff ff callq 0x400bf0 <__isoc99_sscanf@plt>
400f60: 83 f8 01 cmpl $1, %eax
400f63: 7f 05 jg 0x400f6a <phase_3+0x27>
400f65: e8 d0 04 00 00 callq 0x40143a <explode_bomb>
400f6a: 83 7c 24 08 07 cmpl $7, 8(%rsp)
400f6f: 77 3c ja 0x400fad <phase_3+0x6a>
400f71: 8b 44 24 08 movl 8(%rsp), %eax
**400f75: ff 24 c5 70 24 40 00 jmpq *4203632(,%rax,8)** #跳转表 *(0x402470+rax*8)
400f7c: b8 cf 00 00 00 movl $207, %eax
400f81: eb 3b jmp 0x400fbe <phase_3+0x7b>
400f83: b8 c3 02 00 00 movl $707, %eax # imm = 0x2C3
400f88: eb 34 jmp 0x400fbe <phase_3+0x7b>
400f8a: b8 00 01 00 00 movl $256, %eax # imm = 0x100
400f8f: eb 2d jmp 0x400fbe <phase_3+0x7b>
400f91: b8 85 01 00 00 movl $389, %eax # imm = 0x185
400f96: eb 26 jmp 0x400fbe <phase_3+0x7b>
400f98: b8 ce 00 00 00 movl $206, %eax
400f9d: eb 1f jmp 0x400fbe <phase_3+0x7b>
400f9f: b8 aa 02 00 00 movl $682, %eax # imm = 0x2AA
400fa4: eb 18 jmp 0x400fbe <phase_3+0x7b>
400fa6: b8 47 01 00 00 movl $327, %eax # imm = 0x147
400fab: eb 11 jmp 0x400fbe <phase_3+0x7b>
400fad: e8 88 04 00 00 callq 0x40143a <explode_bomb>
400fb2: b8 00 00 00 00 movl $0, %eax
400fb7: eb 05 jmp 0x400fbe <phase_3+0x7b>
400fb9: b8 37 01 00 00 movl $311, %eax # imm = 0x137
400fbe: 3b 44 24 0c cmpl 12(%rsp), %eax
400fc2: 74 05 je 0x400fc9 <phase_3+0x86>
400fc4: e8 71 04 00 00 callq 0x40143a <explode_bomb>
400fc9: 48 83 c4 18 addq $24, %rsp
400fcd: c3 retq
- 可读性调整
phase_3(a){
rsi = '%d %d';
rax = 0;
sccanf();
if(rax <= 1) bomb();
if(*(rsp + 8) > 7) bomb();
goto *(0x402470+rax*8)
400f7c: #0
eax == $207; goto 400fbe;
400f83: #2
eax == $707; goto 400fbe;
400f8a: #3
eax == $256; goto 400fbe;
400f91: #4
eax == $389; goto 400fbe;
400f98: #5
eax == $206; goto 400fbe;
400f9f: #6
eax == $682; goto 400fbe;
400fa6: #7
eax == $327; goto 400fbe;
%eax = 0; goto 400fbe;
400fb9: #1
eax = $311;
400fbe:
if(rax != *(rsp + 12)) bomb();
retq;
}
- C 风格
phase_3(char* a){
if(sccanf(a, '%d %d', &x, &y) <= 1) bomb(); # 将输入的字符串解析为两个数字x,y
if(x > 7) bomb(); # x <= 7
switch(x){ #映射
case 0: y = 207; break;
case 1: y = 311; break;
case 2: y = 707; break;
case 3: y = 256; break;
case 4: y = 389; break;
case 5: y = 206; break;
case 6: y = 682; break;
case 7: y = 327; break;
}
}
-
答案
8组 0 207/1 311/…
【0】phase 4
考察 递归
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 # imm = 0x4025CF
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
0000000000400fce <func4>:
400fce: 48 83 ec 08 subq $8, %rsp
400fd2: 89 d0 movl %edx, %eax
400fd4: 29 f0 subl %esi, %eax
400fd6: 89 c1 movl %eax, %ecx
400fd8: c1 e9 1f shrl $31, %ecx
400fdb: 01 c8 addl %ecx, %eax
400fdd: d1 f8 sarl %eax
400fdf: 8d 0c 30 leal (%rax,%rsi), %ecx
400fe2: 39 f9 cmpl %edi, %ecx
400fe4: 7e 0c jle 0x400ff2 <func4+0x24>
400fe6: 8d 51 ff leal -1(%rcx), %edx
400fe9: e8 e0 ff ff ff **callq 0x400fce <func4> # 递归**
400fee: 01 c0 addl %eax, %eax
400ff0: eb 15 jmp 0x401007 <func4+0x39>
400ff2: b8 00 00 00 00 movl $0, %eax
400ff7: 39 f9 cmpl %edi, %ecx
400ff9: 7d 0c jge 0x401007 <func4+0x39>
400ffb: 8d 71 01 leal 1(%rcx), %esi
400ffe: e8 cb ff ff ff **callq 0x400fce <func4> # 递归**
401003: 8d 44 00 01 leal 1(%rax,%rax), %eax
401007: 48 83 c4 08 addq $8, %rsp
40100b: c3 retq
- 可读性调整
phase_4(rdi){
rcx = rsp + 12; #参数4
rdx = rsp + 8; #参数3
rsi = 0x4025CF; #参数2
rax = 0;
**sccanf(rdi, '%d %d', rdx, rcx);**
if(rax != 2) bomb();
if(*(rsp + 8) <= 14) goto 0x40103a;
bomb();
0x40103a:
rdx = 14; #参数3
rsi = 0; #参数2
rdi = *(rsp + 8); #参数1
**func4(rdi, rsi, rdx);**
if(rax ! = 0) bomb();
if(*(rsp + 12) != 0) bomb();
return
}
func4(a, b, c){
rax = c - b;
rax = (rax + rax >>31) >> 1;
rcx = rax + rsi;
if(rcx <= a) goto 0x400ff2;
c = rcx - 1;
**func4(); #递归**
rax += rax;
goto 0x401007;
0x400ff2:
rax = 0;
if(rcx >= a) goto 0x401007;
b = rcx + 1;
**func4(); #递归
rax = rax + rax +1;**
0x401007:
return
}
- C风格
phase_4(char *input){
rax = sccanf(input, '%d %d', &x, &y)
if(rax != 2 || x > 14) bomb();
ret = func4(x, 0, 14);
if(ret != 0 || y != 0) bomb(); => func4(x, 0, 14) = 0, y = 0
}
func4(a, b=0, c=14){
int x = c - b; # 14
x = (x + x >>31) / 2;
int y = x + b; #7
if(y <= a) {
if(y >= a) return 0;
return 2 * func4(a, y+1, c) + 1;
}
return 2 * func4(a, b, y-1)
}
- 答案 7 0/……
【0】phase 5
考察 for循环/数组/字符串
0000000000401062 <phase_5>:
401062: 53 pushq %rbx
401063: 48 83 ec 20 subq $32, %rsp
401067: 48 89 fb movq %rdi, %rbx
40106a: 64 48 8b 04 25 28 00 00 00 **movq %fs:40, %rax #金丝雀**
401073: 48 89 44 24 18 movq %rax, 24(%rsp)
401078: 31 c0 xorl %eax, %eax
40107a: e8 9c 02 00 00 callq 0x40131b <string_length>
40107f: 83 f8 06 cmpl $6, %eax
401082: 74 4e je 0x4010d2 <phase_5+0x70>
401084: e8 b1 03 00 00 callq 0x40143a <explode_bomb>
401089: eb 47 jmp 0x4010d2 <phase_5+0x70>
40108b: 0f b6 0c 03 movzbl (%rbx,%rax), %ecx
40108f: 88 0c 24 movb %cl, (%rsp)
401092: 48 8b 14 24 movq (%rsp), %rdx
401096: 83 e2 0f andl $15, %edx
401099: 0f b6 92 b0 24 40 00 movzbl 4203696(%rdx), %edx
4010a0: 88 54 04 10 **movb %dl, 16(%rsp,%rax)**
4010a4: 48 83 c0 01 addq $1, %rax
4010a8: 48 83 f8 06 cmpq $6, %rax
4010ac: 75 dd jne 0x40108b <phase_5+0x29>
4010ae: c6 44 24 16 00 movb $0, 22(%rsp)
4010b3: be 5e 24 40 00 movl $4203614, %esi # imm = 0x40245E
4010b8: 48 8d 7c 24 10 leaq 16(%rsp), %rdi
4010bd: e8 76 02 00 00 callq 0x401338 <strings_not_equal>
4010c2: 85 c0 testl %eax, %eax
4010c4: 74 13 je 0x4010d9 <phase_5+0x77>
4010c6: e8 6f 03 00 00 callq 0x40143a <explode_bomb>
4010cb: 0f 1f 44 00 00 nopl (%rax,%rax)
4010d0: eb 07 jmp 0x4010d9 <phase_5+0x77>
4010d2: b8 00 00 00 00 movl $0, %eax
4010d7: eb b2 jmp 0x40108b <phase_5+0x29>
4010d9: 48 8b 44 24 18 movq 24(%rsp), %rax
4010de: 64 48 33 04 25 28 00 00 00 xorq %fs:40, %rax
4010e7: 74 05 je 0x4010ee <phase_5+0x8c>
4010e9: e8 42 fa ff ff callq 0x400b30 <__stack_chk_fail@plt>
4010ee: 48 83 c4 20 addq $32, %rsp
4010f2: 5b popq %rbx
4010f3: c3 retq
- 可读性调整
phase_5(rdi){
rbx = rdi;
**rax = fs:40;**
*(rsp + 24) = rax;
rax = rax ^ rax;
string_length(rdi);
if(rax != 6) bomb();
goto 0x4010d2;
0x40108b:
rcx = rbx + rax; #将输入的字符串保存至rcx中
*rsp = cl; # 字符串的某一位保存至栈顶
rdx = *rsp;
**rdx &= 0xf; #与0xf做与运算
rdx = *(rdx + 0x4024b0);** **#取0x4024b0数组edx位置的值
# x/s 0x4024b0
# "maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?"**
*(rsp + rax + 16) = dl;
rax += 1; #自增
if(rax != 6) goto 0x40108b; #循环
*(rsp + 22) = 0;
**rsi = 0x40245E;
# x/s 0x40245e
# 参数二 "flyers"**
rdi = *(rsp + 16); # 参数一 上面循环压栈的字符
strings_not_equal(rdi, rsi);
if(rax == 0) bomb();
nopl(%rax,%rax);
goto 0x4010d9;
0x4010d2:
rax = 0;
goto 0x40108b;
0x4010d9:
rax = *(rsp + 24);
rax ^= fs:40;
**if(rax == 0) return**
callq __stack_chk_fail@plt;
}
- C风格
phase_5(char *input){
char str[7];
**const char g_str[16] = "maduiersnfotvbyl";
if(string_length(input) != 6) bomb();** # 长度必须为6
for(int i = 0; i < 6; i++){
**str[i] = g_str[input[i] & 0xf]**
}
**if(strings_not_equal(str,"flyers") != 0) bomb()
# f l y e r s
# 9 15 14 5 6 7 input[i] & 0xf**
}
- 答案
查ascii表 c.biancheng.net/c/ascii/,可以找到六个&0xf分别为 9 15 14 5 6 7的字符:
【0】phase 6
考察 嵌套循环 / 结构体(异构数组)/ 链表
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 # imm = 0x6032D0
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 # imm = 0x6032D0
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_6(rdi){
r13 = rsp;
rsi = rsp;
callq read_six_numbers(rdi, rsi);
r14 = rsp;
r12 = 0;
401114:
rbp = r13;
rax = *r13;
40111b:
rax -= 1;
if(rax > 5) bomb();
401128:
r12 += 1;
if(r12 == 6) goto 0x401153; #外循环
rbx = r12;
401135:
rax = rbx;
rax = *(rsp + 4 * rax);
if(*rbp != rax) goto 0x401145;
bomb();
401145:
rbx += 1;
if(rbx <= 5) goto 0x401135; #内循环
r13 += 4;
goto 0x401114;
---------------------------------------------------
401153:
rsi = *(rsp + 24);
rax = r14;
rcx = 7;
401160:
rdx = rcx;
rdx -= *rax;
*rax = rdx;
rax += 4;
if(rax != rsi) goto 0x401160; #循环
rsi = 0;
goto 0x401197;
------------------------------------------------------
401176:
rdx = *(rdx + 8);
rax += 1;
if(rax != rcx) goto 0x401176; #循环
goto 0x401188;
401183:
rdx = 0x6032D0;
401188:
*(rsp + 2rsi + 32) = rdx;
rsi += 4;
if(rsi == 24) goto 0x4011ab; #外循环
401197:
rcx = *(rsp + rsi);
if(rcx <= 1) goto 0x401183;
rax = 1;
rdx = 0x6032D0;
goto 0x401176;
-----------------------------------------------------------------
4011ab:
rbx = *(rsp + 32);
rax = *(rsp + 40);
rsi = *(rsp + 80);
rcx = rbx;
4011bd:
rdx = *rax;
*(rcx + 8) = rdx;
rax += 8;
if(rax == rsi) goto 0x4011d2;
rcx = rdx;
goto 0x4011bd;
-----------------------------------------------------------------
4011d2:
*(rdx + 8) = 0;
rbp = 5;
4011df:
rax = *(rbp + 8);
rax = *(rax);
if(*(rbx) >= rax) goto 0x4011ee;
bomb();
4011ee:
rbx = *(rbx + 8);
rbp -= 1;
if(rbp != 0) goto 4011df;
}
- C风格
phase_6(rdi, rsi){
r13 = rsp;
rsi = rsp;
callq read_six_numbers(rdi, rsi);
r14 = rsp;
for(r12 = 0; r12 != 6; r12++) {
rbp = r13;
rax = *r13; #数组
rax -= 1;
if(rax > 5) bomb(); # rax-1<=5 rax<=6
for(rbx = r12 + 1; rbx <= 5; rbx++){
rax = rbx;
rax = *(rsp + 4 * rax);
if(*rbp == rax) bomb(); #元素不重复
}
r13 += 4;
}
---------------------------------------------------------------
401153:
rsi = *(rsp + 24);
rcx = 7;
for(rax = 14; rax != rsi; rax += 4){
rdx = rcx; # 修改数组
rdx -= *rax; # rdx = 7 - *rax
*rax = rdx; # *rax = 7 - *rax
}
----------------------------------------------------------------
401176:
for(rsi = 0; rsi != 24; rsi +=4){
rcx = *(rsp + rsi);
rdx = 0x6032D0; // 链表head
if(rcx > 1) {
for(rax = 1; rax != rcx; rax++){
rdx = *(rdx + 8);
}
}
*(rsp + 2rsi + 32) = rdx;
}
-----------------------------------------------------------------
4011ab:
rbx = *(rsp + 32);
rcx = rbx;
for(rax = *(rsp + 40); rax != *(rsp + 80); rax += 8){
rdx = *rax;
*(rcx + 8) = rdx; # *(rax + 8) = *rax;
rcx = rdx;
}
-----------------------------------------------------------------
4011d2:
*(rdx + 8) = 0; # ListNode* ptr = node_array[0];
for(rbp = 5; rbp != 0; rbp -= 1;){
rax = *(rbp + 8);
rax = *(rax);
if(*(rbx) < rax) bomb(); # ptr->val < ptr->next->val
rbx = *(rbx + 8); # ptr = ptr->next;
}
}
typedef struct {
int val;
ListNode* next;
} ListNode;
phase_6(char* input){
int array[6]; #r13
read_six_numbers(input, array[6]);
# 输入数组的一些限定条件
for(int i = 0; i != 6; i++){
int num = array[i];
num -= 1;
**if(num > 5) bomb(); #num小于等于 5, i小于等于6**
for(int j = i+1; j <= 5; j++){
num = j;
**if(arr[i] == arr[j]) boumb(); #元素不重复**
}
}
# 修改数组元素的值
for(int i = 0; i != 6; i++){
array[i] = 7 - array[i] **#重排**
}
#
for(int i = 0; i != 6; i++){
int num = array[i];
**rdx = 0x6032D0;
# ListNode* node = 0x6032d0;
#(gdb) x/24w 0x6032d0 结构体 应该是链表结构**
if(num > 1){
for(int j = 1; j!= num; j++){
rdx = *(rdx + 8);
}
}
***(rsp + 2rsi + 32) = rdx; # node_array[i] = node;**
}
#
for(int i = 0; i != 5; i++){
**node_array[i]->next = node_array[i+1]; #链表**
}
ListNode* ptr = node_array[0];
for (int i = 5; i > 0; i--) {
**if (ptr->val < ptr->next->val) # 降序**
explode_bomb();
ptr = ptr->next;
}
}
-
答案
// (gdb) x/24w 0x6032d0 结构体 应该是链表结构**
// node1 node2 node3 node4 node5 node6**
// 0x6032d0 0x6032e0 0x6032f0 0x603300 0x603310 0x603320
// 332 168 924 691 477 443
// 递减node排序 -- 3,4,5,6,1,2
// 7 - array[i]
// 递增 -- 4,3,2,1,6,5
参考博客
blog.csdn.net/qq_38537503…解题思路 转换成C 第四五题
zhuanlan.zhihu.com/p/104130161 注释
zhuanlan.zhihu.com/p/458872003
earthaa.github.io/2020/01/12/… 注释写的好
wdxtub.com/csapp/thick… CMU的学生 另一种解题思路
blog.csdn.net/zhangjs0322… gdb调试的 layout
www.coonote.com/gdb-note/gd… gdb 命令大全
www.ruanyifeng.com/blog/2018/0… x86-64汇编语言入门
最好的搭配:每一题的栈帧+转换代码
八. 总结
- 寄存器的eflags 每个寄存器都有条件码位(ZF SF...)
- 数组 循环 结构体的表示
- 栈帧结构
- gdb调试打断点 + info register很酷
- tmux + vim很酷