Windows逆向安全(一)之基础知识(九)

汇编比较三种循环

众所周知,在C语言可以使用可以使用三种循环,分别是:while、do…while和for

本文从汇编的角度出发,观察这三种循环的差异

范例代码

先贴出三种循环的代码,分别用这三种循环计算

0+1+2+3+4+5+6+7+8+9(从0一直加到9)

#include "stdafx.h"
int loop1(){
        int i=0,j=0;
        for(i=0;i<10;i++){
                j=j+i;
        }
        return j;
}

int loop2(){
        int i=0,j=0;
        while(i<10){
                j=j+i;
                i=i+1;
        }
        return j;
}
int loop3(){
        int i=0,j=0;
        do {
                j=j+i;
                i=i+1;
        } while(i<10);
        return j;
}

int main(int argc, char* argv[])
{
        int result=0;
        result=loop1();
        printf("%d\n",result);
        result=loop2();
        printf("%d\n",result);
        result=loop3();
        printf("%d\n",result);
        return 0;
}

运行结果

在这里插入图片描述

显然,这三种循环都能正确地计算出结果,接下来挨个分析这三种循环的汇编代码

for循环

省去汇编代码中保护现场、提升堆栈、初始化堆栈、恢复现场和返回的代码,直接看代码的对应汇编

9:        int i=0,j=0;
0040D748   mov         dword ptr [ebp-4],0
0040D74F   mov         dword ptr [ebp-8],0
10:       for(i=0;i<10;i++){
0040D756   mov         dword ptr [ebp-4],0
0040D75D   jmp         loop1+38h (0040d768)
0040D75F   mov         eax,dword ptr [ebp-4]
0040D762   add         eax,1
0040D765   mov         dword ptr [ebp-4],eax
0040D768   cmp         dword ptr [ebp-4],0Ah
0040D76C   jge         loop1+49h (0040d779)
11:           j=j+i;
0040D76E   mov         ecx,dword ptr [ebp-8]
0040D771   add         ecx,dword ptr [ebp-4]
0040D774   mov         dword ptr [ebp-8],ecx
12:       }
0040D777   jmp         loop1+2Fh (0040d75f)
13:       return j;
0040D779   mov         eax,dword ptr [ebp-8]
14:   }

头两行汇编对应将i和j初始化为0,没什么好说的

9:        int i=0,j=0;
0040D748   mov         dword ptr [ebp-4],0
0040D74F   mov         dword ptr [ebp-8],0

在这里插入图片描述
接下来看循环语句部分:

第一行为:

0040D756   mov         dword ptr [ebp-4],0

对应for(i=0;i<10;i++)中的i=0

接下来是一个绝对跳转指令:

0040D75D   jmp         loop1+38h (0040d768)

跳转的地址为:0040d768

0040D768   cmp         dword ptr [ebp-4],0Ah
0040D76C   jge         loop1+49h (0040d779)

这里就是比较 i 和0Ah(十六进制的10),也就是对应for(i=0;i<10;i++)中的i<10

jge指令:jump greater equal,当大于等于时跳转(有符号)

所以这里就是判断i是否大于10,如果大于10就跳转到0040d779

接下来看0040d779对应的代码:

13:       return j;
0040D779   mov         eax,dword ptr [ebp-8]

这里就是返回的语句了,已经在循环的外部了,即上面的跳转其实就是退出循环的语句

如果前面的i<10,则继续向下看汇编语句:

11:           j=j+i;
0040D76E   mov         ecx,dword ptr [ebp-8]
0040D771   add         ecx,dword ptr [ebp-4]
0040D774   mov         dword ptr [ebp-8],ecx

先将j赋值给ecx,然后用ecx加上i,最后将ecx赋值给j,即j=j+i,也就是我们循环里要执行的内容

执行完上面的j=j+1后,下一行指令是一个绝对跳转:

12:       }
0040D777   jmp         loop1+2Fh (0040d75f)

跳转的地址为0040d75f,继续观察:

0040D75F   mov         eax,dword ptr [ebp-4]
0040D762   add         eax,1
0040D765   mov         dword ptr [ebp-4],eax
0040D768   cmp         dword ptr [ebp-4],0Ah

先将i的值赋给eax,然后eax加一后把eax赋给i,对应for(i=0;i<10;i++)中的i++

然后就回到了之前的步骤,比较i是否大于等于10,是则退出循环,否则继续循环执行

for循环总结

通过前面的分析大致可以知道for循环的执行流程为:

在这里插入图片描述

while循环

省去汇编代码中保护现场、提升堆栈、初始化堆栈、恢复现场和返回的代码,直接看代码的对应汇编

17:       int i=0,j=0;
0040D7A8   mov         dword ptr [ebp-4],0
0040D7AF   mov         dword ptr [ebp-8],0
18:       while(i<10){
0040D7B6   cmp         dword ptr [ebp-4],0Ah
0040D7BA   jge         loop2+40h (0040d7d0)
19:           j=j+i;
0040D7BC   mov         eax,dword ptr [ebp-8]
0040D7BF   add         eax,dword ptr [ebp-4]
0040D7C2   mov         dword ptr [ebp-8],eax
20:           i=i+1;
0040D7C5   mov         ecx,dword ptr [ebp-4]
0040D7C8   add         ecx,1
0040D7CB   mov         dword ptr [ebp-4],ecx
21:       }
0040D7CE   jmp         loop2+26h (0040d7b6)
22:       return j;
0040D7D0   mov         eax,dword ptr [ebp-8]
23:   }

头两行初始化i和j,和前面一样,不属于循环的内容,这里给出i和j对应的地址

在这里插入图片描述

下面正式来看循环的内容:

18:       while(i<10){
0040D7B6   cmp         dword ptr [ebp-4],0Ah
0040D7BA   jge         loop2+40h (0040d7d0)

比较 i 和 10

jge:jump greater equal,大于等于就跳转(有符号)

综上两句就是用来判断 i<10 对应while(i<10)中的 判断条件 i<10

如果i>=10,则跳转到0040d7d0,退出循环

22:       return j;
0040D7D0   mov         eax,dword ptr [ebp-8]

这里就是返回的语句了,已经在循环的外部了

如果i<10,也就是没有跳转,接着看下面的语句:

19:           j=j+i;
0040D7BC   mov         eax,dword ptr [ebp-8]
0040D7BF   add         eax,dword ptr [ebp-4]
0040D7C2   mov         dword ptr [ebp-8],eax
20:           i=i+1;
0040D7C5   mov         ecx,dword ptr [ebp-4]
0040D7C8   add         ecx,1
0040D7CB   mov         dword ptr [ebp-4],ecx
21:       }

就是执行我们while里面所写的代码(执行循环内的代码)

接着看下面的语句,是一个无条件跳转,跳转到前面的0040d7b6

0040D7CE   jmp         loop2+26h (0040d7b6)

来看看0040d7b6,就是最开始的判断语句,如果i<10则继续执行,否则跳出循环

0040D7B6   cmp         dword ptr [ebp-4],0Ah
0040D7BA   jge         loop2+40h (0040d7d0)

while循环总结

通过前面的分析大致可以知道while循环的执行流程为

在这里插入图片描述

do while循环

省去汇编代码中保护现场、提升堆栈、初始化堆栈、恢复现场和返回的代码,直接看代码的对应汇编

25:       int i=0,j=0;
0040D888   mov         dword ptr [ebp-4],0
0040D88F   mov         dword ptr [ebp-8],0
26:       do {
27:           j=j+i;
0040D896   mov         eax,dword ptr [ebp-8]
0040D899   add         eax,dword ptr [ebp-4]
0040D89C   mov         dword ptr [ebp-8],eax
28:           i=i+1;
0040D89F   mov         ecx,dword ptr [ebp-4]
0040D8A2   add         ecx,1
0040D8A5   mov         dword ptr [ebp-4],ecx
29:       } while(i<10);
0040D8A8   cmp         dword ptr [ebp-4],0Ah
0040D8AC   jl          loop3+26h (0040d896)
30:       return j;
0040D8AE   mov         eax,dword ptr [ebp-8]
31:   }

头两行初始化i和j,和前面一样,不属于循环的内容,这里给出i和j对应的地址

在这里插入图片描述
下面正式来看循环的内容:

26:       do {
27:           j=j+i;
0040D896   mov         eax,dword ptr [ebp-8]
0040D899   add         eax,dword ptr [ebp-4]
0040D89C   mov         dword ptr [ebp-8],eax
28:           i=i+1;
0040D89F   mov         ecx,dword ptr [ebp-4]
0040D8A2   add         ecx,1
0040D8A5   mov         dword ptr [ebp-4],ecx

直接执行我们do while里面所写的代码(执行循环内的代码)

接着看下面的代码:

29:       } while(i<10);
0040D8A8   cmp         dword ptr [ebp-4],0Ah
0040D8AC   jl          loop3+26h (0040d896)

先是比较 i 和 10

然后 jl :jump less (有符号数),当i<10的时候才跳转

跳转地址为0040d896,也就是前面的代码

26:       do {
27:           j=j+i;
0040D896   mov         eax,dword ptr [ebp-8]

如果没有跳转则执行下面的代码

30:       return j;
0040D8AE   mov         eax,dword ptr [ebp-8]

注意到这里已经是退出循环的状态了,返回j

do while循环总结

过前面的分析大致可以知道do while循环的执行流程为:

在这里插入图片描述

比较

在这里插入图片描述在这里插入图片描述

在这里插入图片描述

从流程图就不难看出,三种循环的复杂程度:

for循环>while循环>do while循环

因此执行效率则是:

do while循环>while循环>for循环

  • for循环是先判断条件是否不满足i<10,也就是是否满足i>=10,不满足条件则跳出循环并返回;满足条件则执行循环内的代码,执行完循环内代码后无条件跳转到计数增加i=i+1再回到判断条件
  • while循环也是先判断条件是否不满足i<10,也就是是否满足i>=10,不满足条件则跳出循环并返回;满足条件则执行循环内的代码,执行完循环内代码后无条件跳转到判断条件处
  • do while循环则是先执行循环内的语句,然后再判断条件,判断条件是否满足i<10,满足条件则跳回去继续执行循环内的代码
posted @ 2023-04-19 08:13  私ははいしゃ敗者です  阅读(6)  评论(0编辑  收藏  举报  来源