今天看了《加密与解密》循环语句部分,接下来将从do-while循环,while循环,for循环三个方面去学习循环的汇编。
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
}
}
while循环的流程是:先进行表达式判断,在执行语句块,当表达式为真时,会继续执行语句块,示例如下
#include
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循环。
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类似。