1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
00000000004010f4 <phase_6>:
4010f4: 41 56 push %r14
4010f6: 41 55 push %r13
4010f8: 41 54 push %r12
4010fa: 55 push %rbp
4010fb: 53 push %rbx
4010fc: 48 83 ec 50 sub $0x50,%rsp //入栈,栈指针减少80
401100: 49 89 e5 mov %rsp,%r13 //r13=rsp
401103: 48 89 e6 mov %rsp,%rsi //rsi=rsp
401106: e8 51 03 00 00 call 40145c <read_six_numbers> //读取6个数字
40110b: 49 89 e6 mov %rsp,%r14 //r14=rsp
40110e: 41 bc 00 00 00 00 mov $0x0,%r12d //r12d=0
401114: 4c 89 ed mov %r13,%rbp //rbp=r13 rsp rsp+4
401117: 41 8b 45 00 mov 0x0(%r13),%eax //eax=*(r13)
40111b: 83 e8 01 sub $0x1,%eax //eax=eax-1
40111e: 83 f8 05 cmp $0x5,%eax //eax与5比较
401121: 76 05 jbe 401128 <phase_6+0x34> //若eax<=5,跳转到0x401128
401123: e8 12 03 00 00 call 40143a <explode_bomb> //否则,爆炸
401128: 41 83 c4 01 add $0x1,%r12d //r12d=r12d+1=1 2
40112c: 41 83 fc 06 cmp $0x6,%r12d //r12d与6比较
401130: 74 21 je 401153 <phase_6+0x5f> //若r12d=6,则跳转到0x401153
401132: 44 89 e3 mov %r12d,%ebx //ebx=r12d=1 2
401135: 48 63 c3 movslq %ebx,%rax //rax=ebx 1 2
401138: 8b 04 84 mov (%rsp,%rax,4),%eax //eax=*(rsp+rax*4)
40113b: 39 45 00 cmp %eax,0x0(%rbp)
40113e: 75 05 jne 401145 <phase_6+0x51> //若*(rbp)!=*(rsp+rax*4),跳转到0x401145
401140: e8 f5 02 00 00 call 40143a <explode_bomb> //否则,爆炸
401145: 83 c3 01 add $0x1,%ebx //ebx++ 2
401148: 83 fb 05 cmp $0x5,%ebx
40114b: 7e e8 jle 401135 <phase_6+0x41> //若ebx<=5,跳转到0x401135
40114d: 49 83 c5 04 add $0x4,%r13 //r13+=4
401151: eb c1 jmp 401114 <phase_6+0x20> //跳转到0x401114
#这段代码的目的就是让所有参数要小于等于6,并且不得重复
401153: 48 8d 74 24 18 lea 0x18(%rsp),%rsi //rsi=rsp+24
401158: 4c 89 f0 mov %r14,%rax //rax=r14 rsp
40115b: b9 07 00 00 00 mov $0x7,%ecx //ecx=7
401160: 89 ca mov %ecx,%edx //edx=ecx=7
401162: 2b 10 sub (%rax),%edx //edx=edx-*(rax) 7-*(rsp)
401164: 89 10 mov %edx,(%rax) //*(rax)=edx *(rsp)=7-*(rsp)
401166: 48 83 c0 04 add $0x4,%rax //rax=rax+4 rsp+4
40116a: 48 39 f0 cmp %rsi,%rax //rax与rsi比较
40116d: 75 f1 jne 401160 <phase_6+0x6c> //若rax!=rsi,则跳转到0x401160 六次循环
#这段代码就是处理参数
#相当于for(int i=0;i<6;i++){
#input[i]=7-input[i];
#}
40116f: be 00 00 00 00 mov $0x0,%esi //esi=0
401174: eb 21 jmp 401197 <phase_6+0xa3> //跳转到0x401197
401176: 48 8b 52 08 mov 0x8(%rdx),%rdx //rdx=*(rdx+8) *(0x6032d0+8)
40117a: 83 c0 01 add $0x1,%eax //eax++ 2
40117d: 39 c8 cmp %ecx,%eax //比较ecx和eax的大小 *(rsp)与2大小
40117f: 75 f5 jne 401176 <phase_6+0x82> //若ecx!=eax,则跳转到0x401176
401181: eb 05 jmp 401188 <phase_6+0x94> //跳转到0x401188
401183: ba d0 32 60 00 mov $0x6032d0,%edx //edx=0x6032d0
401188: 48 89 54 74 20 mov %rdx,0x20(%rsp,%rsi,2) //*(rsp+rsi*2+32)=rdx
40118d: 48 83 c6 04 add $0x4,%rsi //rsi=rsi+4 4
401191: 48 83 fe 18 cmp $0x18,%rsi //rsi与24比较
401195: 74 14 je 4011ab <phase_6+0xb7> //若rsi=24,跳转到0x4011ab
401197: 8b 0c 34 mov (%rsp,%rsi,1),%ecx //ecx=*(rsp+rsi) 指针偏移,依次获取6个数 *(rsp) *(rsp+4)
40119a: 83 f9 01 cmp $0x1,%ecx //比较ecx与1的大小
40119d: 7e e4 jle 401183 <phase_6+0x8f> //若ecx<=1,跳转到0x401183 即当处理后的*(rsp)=1时
40119f: b8 01 00 00 00 mov $0x1,%eax //eax=1
4011a4: ba d0 32 60 00 mov $0x6032d0,%edx //edx=0x6032d0
4011a9: eb cb jmp 401176 <phase_6+0x82> //跳转到0x401176
#这段代码不太好着手,根据我们输入的1 2 3 4 5 6带入运行,经过之前的处理后编程了6 5 4 3 2 1,
#这段代码的关键在于0x6032d0这个地址代表的含义,
#在处理第一个参数6时,发现在不断嵌套使用地址,优点像链表,利用gdb查看,这个地址的值发现:
#(gdb) x/24w 0x6032d0
#0x6032d0 <node1>: 0x0000014c 0x00000001 0x006032e0 0x00000000
#0x6032e0 <node2>: 0x000000a8 0x00000002 0x006032f0 0x00000000
#0x6032f0 <node3>: 0x0000039c 0x00000003 0x00603300 0x00000000
#0x603300 <node4>: 0x000002b3 0x00000004 0x00603310 0x00000000
#0x603310 <node5>: 0x000001dd 0x00000005 0x00603320 0x00000000
#0x603320 <node6>: 0x000001bb 0x00000006 0x00000000 0x00000000
#在这里,我的输入是1 2 3 4 5 6
#我们看到打印出来的结果,每个node里第2个四字节的部分和我们的输入吻合;
#而第三个四字节的部分则是下一个node的起始地址,最后一个四字节的部分则为0,
#考虑到内存对齐,我们大概能推测出,这应该是一个链表,而我们的输入的数字与在第二个四字节的地方的数据有关,
#第一个四字节的内容表示的是什么待确定
# 这个结构体有点类似链表:
# struct {
# int sth; // 某四字节内容
# int input; // 与我们的输入有关
# node* next; // 下一个node地址
# } node;
#这么看下来这段代码就是将处理后参数所对应node的起始地址存储到首地址为rsp+0x20,尾地址为rsp+0x50的地方
#(gdb) x/12w $rsp+0x20
#0x7fffffffd8c0: 0x00603320 0x00000000 0x00603310 0x00000000
#0x7fffffffd8d0: 0x00603300 0x00000000 0x006032f0 0x00000000
#0x7fffffffd8e0: 0x006032e0 0x00000000 0x006032d0 0x00000000
4011ab: 48 8b 5c 24 20 mov 0x20(%rsp),%rbx //rbx=*(rsp+0x20) 0x00603320
4011b0: 48 8d 44 24 28 lea 0x28(%rsp),%rax //rax=(rsp+0x28)
4011b5: 48 8d 74 24 50 lea 0x50(%rsp),%rsi //rsi=(rsp+0x50)
4011ba: 48 89 d9 mov %rbx,%rcx //rcx=rbx=*(rsp+0x20) 0x00603320
4011bd: 48 8b 10 mov (%rax),%rdx //rdx=*(rax)=*(rsp+0x28) 0x00603310
4011c0: 48 89 51 08 mov %rdx,0x8(%rcx) //*(rcx+8)=rdx *(*(rsp+0x20)+8)=*(rsp+0x28) //*0x00603328=0x00603310 *0x00603318=0x603300
4011c4: 48 83 c0 08 add $0x8,%rax //rax+=8 (rsp+0x30)
4011c8: 48 39 f0 cmp %rsi,%rax
4011cb: 74 05 je 4011d2 <phase_6+0xde> //若rax=rsi,跳转到0x4011d2
4011cd: 48 89 d1 mov %rdx,%rcx //rcx=rdx *(rsp+0x28)
4011d0: eb eb jmp 4011bd <phase_6+0xc9> //跳转到0x4011bd
#这段代码可以简化为一个for循环,这个循环用来将链表的结点重新调整至第一个参数的结点为头节点,
#后面的参数依次链接在这个头结点后的链表:
#for(int i=0;i<6;i++){
#node[i]->next=node[i+1];
#}
#结果如下
#(gdb) x/24w 0x6032d0
#0x6032d0 <node1>: 0x0000014c 0x00000001 0x006032e0 0x00000000
#0x6032e0 <node2>: 0x000000a8 0x00000002 0x006032d0 0x00000000
#0x6032f0 <node3>: 0x0000039c 0x00000003 0x006032e0 0x00000000
#0x603300 <node4>: 0x000002b3 0x00000004 0x006032f0 0x00000000
#0x603310 <node5>: 0x000001dd 0x00000005 0x00603300 0x00000000
#0x603320 <node6>: 0x000001bb 0x00000006 0x00603310 0x00000000
4011d2: 48 c7 42 08 00 00 00 movq $0x0,0x8(%rdx) ///*(rdx+8)=0
4011d9: 00
4011da: bd 05 00 00 00 mov $0x5,%ebp //ebp=5
4011df: 48 8b 43 08 mov 0x8(%rbx),%rax //rax=*(rbx+8)=头结点的下一个结点rbx=*(rsp+0x20)
4011e3: 8b 00 mov (%rax),%eax //eax=*(rax) 下一结点的sth内容
4011e5: 39 03 cmp %eax,(%rbx) //当前结点的sth与下一结点的sth内容比较
4011e7: 7d 05 jge 4011ee <phase_6+0xfa> //若*(rbx)>=eax,则跳转到0x4011ee
4011e9: e8 4c 02 00 00 call 40143a <explode_bomb> //否则,爆炸
4011ee: 48 8b 5b 08 mov 0x8(%rbx),%rbx //rbx=*(rbx+8) 指向下一个结点
4011f2: 83 ed 01 sub $0x1,%ebp //ebp--
4011f5: 75 e8 jne 4011df <phase_6+0xeb> //若不等于0,则跳转到0x4011df
4011f7: 48 83 c4 50 add $0x50,%rsp //出栈,栈指针增加80
#这段代码主要是比较每个结点和下一个结点的sth值(结点的首四字节内容),当前结点的sth要大于等于下一结点的sth,
#所以我们需要将sth的值排序从大到小排序,排序后所结点对应序号的序列就是我们要输入的参数值和对应顺序,
#即4 3 2 1 6 5 注意参数被处理过,不要写成3 4 5 6 1 2
4011fb: 5b pop %rbx
4011fc: 5d pop %rbp
4011fd: 41 5c pop %r12
4011ff: 41 5d pop %r13
401201: 41 5e pop %r14
401203: c3 ret
|