汇编代码
0x00000000004010f4 <+0>: push r14
0x00000000004010f6 <+2>: push r13
0x00000000004010f8 <+4>: push r12
0x00000000004010fa <+6>: push rbp
0x00000000004010fb <+7>: push rbx
0x00000000004010fc <+8>: sub rsp,0x50
0x0000000000401100 <+12>: mov r13,rsp ; r13=rsp
0x0000000000401103 <+15>: mov rsi,rsp ; rsi=rsp
0x0000000000401106 <+18>: call 0x40145c <read_six_numbers>
0x000000000040110b <+23>: mov r14,rsp ; r14=rsp
0x000000000040110e <+26>: mov r12d,0x0 ; i=0
;for(i=0; i<6 ; i++)
; Part-1 循环下来,保证六个数都<=6 loop1
0x0000000000401114 <+32>: mov rbp,r13 ; rbp=r13=rsp
0x0000000000401117 <+35>: mov eax,DWORD PTR [r13+0x0] ; eax = rsp
0x000000000040111b <+39>: sub eax,0x1 ; eax-1
0x000000000040111e <+42>: cmp eax,0x5
0x0000000000401121 <+45>: jbe 0x401128 <phase_6+52> ; eax-1 <= 5 ==> eax <= 6
0x0000000000401123 <+47>: call 0x40143a <explode_bomb>
; Part-2 实现数组中每个数都各不相同
0x0000000000401128 <+52>: add r12d,0x1 ; j=i+1
0x000000000040112c <+56>: cmp r12d,0x6 ; 要循环六个数,j < 6
0x0000000000401130 <+60>: je 0x401153 <phase_6+95>
0x0000000000401132 <+62>: mov ebx,r12d ; ebx=j
; for(j=i+1;j <= 5; j++) loop2
;循环下来后,保证六个数都各不相同
0x0000000000401135 <+65>: movsxd rax,ebx ; rax=ebx=j
0x0000000000401138 <+68>: mov eax,DWORD PTR [rsp+rax*4] ; eax=arr[j]
0x000000000040113b <+71>: cmp DWORD PTR [rbp+0x0],eax ; arr[i] 和 arr[j]进行比较
0x000000000040113e <+74>: jne 0x401145 <phase_6+81>
0x0000000000401140 <+76>: call 0x40143a <explode_bomb>
; if arr[i+1] != arr[i]
0x0000000000401145 <+81>: add ebx,0x1 ; j++
0x0000000000401148 <+84>: cmp ebx,0x5 ; 判断j是否越界
0x000000000040114b <+87>: jle 0x401135 <phase_6+65>
0x000000000040114d <+89>: add r13,0x4 ; r13+4
0x0000000000401151 <+93>: jmp 0x401114 <phase_6+32>
; Part-3 实现arr[m] = 7-arr[m]
0x0000000000401153 <+95>: lea rsi,[rsp+0x18] ; &rsi=&arr[6](arr的尾后地址)
0x0000000000401158 <+100>: mov rax,r14 ; rax=r14=rsp ==> m=0
0x000000000040115b <+103>: mov ecx,0x7 ; ecx=7
; for(m=0;m<6;m++) loop3
0x0000000000401160 <+108>: mov edx,ecx ; edx=ecx=7
0x0000000000401162 <+110>: sub edx,DWORD PTR [rax] ; edx=7-arr[m]
0x0000000000401164 <+112>: mov DWORD PTR [rax],edx ; arr[m] = edx= 7-arr[m]
0x0000000000401166 <+114>: add rax,0x4 ; m++
0x000000000040116a <+118>: cmp rax,rsi ; m < 6
0x000000000040116d <+121>: jne 0x401160 <phase_6+108>
; Part-4 把node进行从小到大排序,依次放入栈中
0x000000000040116f <+123>: mov esi,0x0 ; esi=0 ==> k=0
0x0000000000401174 <+128>: jmp 0x401197 <phase_6+163>
; if(arr[k] > count)
0x0000000000401176 <+130>: mov rdx,QWORD PTR [rdx+0x8] ; edx = node[k]->next
0x000000000040117a <+134>: add eax,0x1 ; count++ eax==>count
0x000000000040117d <+137>: cmp eax,ecx ; 判断count是否等于arr[k]
0x000000000040117f <+139>: jne 0x401176 <phase_6+130>
0x0000000000401181 <+141>: jmp 0x401188 <phase_6+148> ; 当前node入栈
; if(arr[k] <= 1)
0x0000000000401183 <+143>: mov edx,0x6032d0 ; edx=0x6032d0 ==> node1
; if(arr[k] <= count)
0x0000000000401188 <+148>: mov QWORD PTR [rsp+rsi*2+0x20],rdx ; 把当前edx中存储的node压入栈中
0x000000000040118d <+153>: add rsi,0x4 ; k++
0x0000000000401191 <+157>: cmp rsi,0x18 ; k < 6
0x0000000000401195 <+161>: je 0x4011ab <phase_6+183>
; if(k <= 5)
0x0000000000401197 <+163>: mov ecx,DWORD PTR [rsp+rsi*1] ; ecx=arr[k]
0x000000000040119a <+166>: cmp ecx,0x1
0x000000000040119d <+169>: jle 0x401183 <phase_6+143>
; if(arr[k] > 1)
0x000000000040119f <+171>: mov eax,0x1 ; count=1 eax==>count
0x00000000004011a4 <+176>: mov edx,0x6032d0 ; edx = node1
0x00000000004011a9 <+181>: jmp 0x401176 <phase_6+130>
; Part-5 将入栈后的node按入栈顺序链接起来
; if(k > 5) 跳出Part-4
0x00000000004011ab <+183>: mov rbx,QWORD PTR [rsp+0x20] ; rbx = nod1 将入栈后的node按顺序依次记为nod1....nod6
0x00000000004011b0 <+188>: lea rax,[rsp+0x28] ; rax = nod2
0x00000000004011b5 <+193>: lea rsi,[rsp+0x50] ; rsi = nod6后面的位置,即栈帧边界
0x00000000004011ba <+198>: mov rcx,rbx ; rcx = rbx = nod1
; if(n < 6)
0x00000000004011bd <+201>: mov rdx,QWORD PTR [rax] ; rdx = rax = nod2
0x00000000004011c0 <+204>: mov QWORD PTR [rcx+0x8],rdx ; nod1->next = nod2
0x00000000004011c4 <+208>: add rax,0x8 ; rax = rax->next = nod3
0x00000000004011c8 <+212>: cmp rax,rsi ; 判断是否越界
0x00000000004011cb <+215>: je 0x4011d2 <phase_6+222>
; if(n < 6)
0x00000000004011cd <+217>: mov rcx,rdx ; rcx = rdx = nod2
0x00000000004011d0 <+220>: jmp 0x4011bd <phase_6+201>
; Part-6 判断入栈的nod序列的weight是否是从大到小排序的,如果不是(例如 nod1.weight < nod2.weight),则炸弹爆炸
; if(n >= 6)
0x00000000004011d2 <+222>: mov QWORD PTR [rdx+0x8],0x0 ; nod6->next = 0
0x00000000004011da <+230>: mov ebp,0x5 ; ebp = 5 ==> con=5
; if(con > 0) loop
0x00000000004011df <+235>: mov rax,QWORD PTR [rbx+0x8] ;rax = nod1->next = nod2
0x00000000004011e3 <+239>: mov eax,DWORD PTR [rax] ; eax = nod2.weight
0x00000000004011e5 <+241>: cmp DWORD PTR [rbx],eax
=> 0x00000000004011e7 <+243>: jge 0x4011ee <phase_6+250> ; if(nod1.weight >= nod2.weight)
0x00000000004011e9 <+245>: call 0x40143a <explode_bomb>
; if(nod1.weight >= nod2.weight)
0x00000000004011ee <+250>: mov rbx,QWORD PTR [rbx+0x8] ; rbx = rbx->next
0x00000000004011f2 <+254>: sub ebp,0x1 ;ebp-- ==> con--
0x00000000004011f5 <+257>: jne 0x4011df <phase_6+235>
; 程序结束
0x00000000004011f7 <+259>: add rsp,0x50
0x00000000004011fb <+263>: pop rbx
0x00000000004011fc <+264>: pop rbp
0x00000000004011fd <+265>: pop r12
0x00000000004011ff <+267>: pop r13
0x0000000000401201 <+269>: pop r14
0x0000000000401203 <+271>: ret
Part-1
输入六个数字,都必须满足arr[i] - 1 <= 5
for(i = 0; i < 6; i++){
if (arr[i]-1 > 5)
bomb();
}
Part-2
六个数字必须各不相同
for(i = 0; i < 6; i++){
for(j = 1; j < 6; j++){
if(arr[j] == arr[i])
bomb();
}
}
所以我们输入 1 2 3 4 5 6
Part-3
实现arr[m] = 7-arr[m]
for(m = 0; m < 6; m++){
arr[m] = 7-arr[m];
}
输入的数变为6 5 4 3 2 1
Part-4
令人费解的地方
0x0000000000401188 <+148>: mov QWORD PTR [rsp+rsi*2+0x20],rdx
首先在内存中有链表node1……node6 一一对应 1 2 3 4 5 6
struct node{
int weight; //表示权重
int value; //表示的是这个node是第几个node
node * next;
}node;
node * node1,node2,node3,node4,node5,node6;
node1.value = 1;
node1->next = node2;
node2.value = 2;
node2->next = node3;
......
node6.value = 6;
对Part-4反编译可以是下面这样的伪代码:
node * nod = node1;
for(k = 0; k < 6; k++){
for(count = 1; ; count++){
if(arr[k] <= count){
push(nod);
break;
}
else{
nod = nod->next;
}
}
}
可以得到它的逻辑是,根据arr[k]的值,让序列为这个值的node入栈,例如arr[0] = 6,则循环遍历到node6让其入栈,根据Part-3我们的数组值变为了6 5 4 3 2 1,所以我们入栈的node序列为node6 node5 node4 node3 node2 node1
查看内存得知,node1-node6的weight 权重分别为:332,168,924,691,477,443
Part-5
将入栈后的node按入栈顺序链接起来
for(n = 0; n < 5; n++){
nod[n]->next = nod[n+1];
}
Part-6
判断入栈的nod序列的weight是否是从大到小排序的,如果不是(例如 nod1.weight < nod2.weight),则炸弹爆炸
for(i = 0,con = 5; con > 0; i++,con--){
if(nod[i].weight < nod[i+1].weight)
bomb();
}
结论
所以输入的数字顺序应该按照node.weight的从大到小来输入,因为Part-4中我们知道它会把我们输入的数字按从大到小的顺序来将链表压入栈中,所以weight最大的位置应该放6,第二大的位置放5,即weight大小的位置与value大小一一对应。
weight:332,168,924,691,477,443 对应的value分别是 1 2 3 4 5 6
被7减过后的value顺序应该是: 3 , 4 ,5 , 6 , 1 , 2
又因为它还要用7减去我们输入的数,我们我们输入的数应该是用7减之前的。
所以最终应该输入的value:4 3 2 1 6 5