今天看了《加密與解密》循環語句部分,接下來將從do-while循環,while循環,for循環三個方面去學習循環的彙編。
0x01 do-while循環
do-while循環的流程是:先執行語句塊,在進行表達式判斷,當表達式爲真時,在繼續執行語句塊。接下來先看一段C語言代碼:
#include "stdafx.h"
int main(int argc, char* argv[])
{
int nCount=0;
do{
printf("%d\r\n",nCount);
nCount++;
}
while(nCount<argc); argc爲整型,用來統計程序運行時發送給main函數的命令行參數的個數,在VS中默認值爲1。
return 0;
}
切到反彙編模式:
可以看到,先執行了輸出語句和nCount的自增,然後比較nCount和argc的大小,若小於則循環,否則將線性向下執行。
下面是我寫的彙編代碼:
#include "stdafx.h"
int main(int argc, char* argv[])
{
//int nCount=0;
char *str="%d\r\n";
_asm{
mov eax,0
circle: push eax
push str
call printf //調用printf函數
add esp,8 //平衡棧
inc eax //nCount自增,
cmp eax,dword ptr [ebp+8]
jl circle //if (nCount<argc),跳轉到circle循環執行
xor eax,eax //設置返回值爲0
}
}
成功運行!
在IDA Pro裏面識別do—while循環
0x02 while循環
while循環的流程是:先進行表達式判斷,在執行語句塊,當表達式爲真時,會繼續執行語句塊,示例如下
#include<stdio.h>
void main()
{
char *str="%d\n";
_asm{
mov eax,1 //i=1
mov ebx,0 //sum=0
circle: cmp eax,100
jg end
add ebx,1 //sum++
inc eax,1 //i++
jmp circle
end:
push ebx
push str
call printf
add esp,8
}
}
切入到反彙編:
可以看到,先比較i與100的大小,若i<=100,則執行語句塊,否則就直接輸出sum。
下面是我寫的彙編代碼:
#include<stdio.h>
void main()
{
char *str="%d\n";
_asm{
mov eax,1 //i=1
mov ebx,0 //sum=0
circle: cmp eax,100
jg end
add ebx,1 //sum++
inc eax,1 //i++
jmp circle
end:
push ebx
push str
call printf
add esp,8
}
}
在IDA Pro裏面識別while循環
循環的特點是會向低地址跳轉。while循環和do-while循環區別:
1.while循環使用的是jmp循環,while循環使用的是jxx彙編指令需要取反
2.while循環比do循環多一次if判斷,因此性能上while循環不如do循環高,在Release版本中,編譯器會把while循環優化成等價的do循環。
0x03 for循環
for語句由賦初值,循環條件,循環步長三條語句組成,示例如下:
#include "stdafx.h"
int main(int argc, char* argv[])
{
for(int nCount=0; nCount<argc;nCount++)
{
printf("%d\r\n",nCount);
}
return 0;
}
切入到反彙編:
在這裏可以看到,對nCount賦值以後,就跳到判斷的位置,如果判斷結果爲真,就跳上去執行語句塊
接下來是我寫的彙編代碼:
#include "stdafx.h"
int main(int argc, char* argv[])
{
char *str="%d\r\n";
_asm{
mov eax,0
jmp judge
circle: add eax,1
judge: cmp eax,dword ptr[ebp+8]
jge circle
push eax
push str
call printf
add esp,8
xor eax,eax
}
}
在IDA Pro裏面識別for循環
關於循環語句的學習就先到這裏。
eax加1,可以有如下兩種表示:
inc eax
add eax,1
複製代碼
雖然功能一樣,可還是有以下區別:
(1) 機器碼長度不同,inc短,add長。(這不是關鍵)
(2)INC不改變標誌位CF,而ADD則改變CF。(這點很關鍵。)
例如:
number dw 0FFFFH,1234H,0,0,0
表示的80位數1234FFFFH,希望給它加2。
MOV SI,OFFSET NUMBER
MOV CX,4 ;4個高位的字單元
ADD WORD PTR [SI],2 ;最低位加2
L1:
INC SI
ADC WORD PTR [SI],0 ;把產生的進位加到高位
LOOP L1
若把INC SI換成ADD SI,1就會出錯。原因是 ADD WORD PTR [SI],2產生了CF,若用ADD SI,1就會把CF清0,從而後面的ADC就不能把前面的進位加上。
dec eax
sub eax,1
複製代碼
eax減1,dec和sub的區別也和加1類似。