CSAPP-lab2-phase_6


汇编代码

   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


文章作者: 0x00dream
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 0x00dream !
  目录