大神论坛

找回密码
快速注册
查看: 491 | 回复: 0

[语言编程类] 大神论坛 逆向脱壳分析基础学习笔记十五 汇编比较三种循环

主题

帖子

5

积分

初入江湖

UID
20
积分
5
精华
威望
10 点
违规
大神币
68 枚
注册时间
2021-03-14 10:40
发表于 2021-03-14 18:33
本帖最后由 kay2kay 于 2021-03-14 18:33 编辑

本文为本人的滴水逆向破解脱壳学习笔记之一,为本人对以往所学的回顾和总结,可能会有谬误之处,欢迎大家指出。
陆续将不断有笔记放出,希望能对想要入门的萌新有所帮助,一起进步


所有笔记链接:

大神论坛 逆向脱壳分析基础学习笔记一 进制篇
大神论坛 逆向脱壳分析基础学习笔记二 数据宽度和逻辑运算
大神论坛 逆向脱壳分析基础学习笔记三 通用寄存器和内存读写
大神论坛 逆向脱壳分析基础学习笔记四 堆栈篇
大神论坛 逆向脱壳分析基础学习笔记五 标志寄存器 
大神论坛 逆向脱壳分析基础学习笔记六 汇编跳转和比较指令
大神论坛 逆向脱壳分析基础学习笔记七 堆栈图(重点)(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记八 反汇编分析C语言
大神论坛 逆向脱壳分析基础学习笔记九 C语言内联汇编和调用协定
大神论坛 逆向脱壳分析基础学习笔记十 汇编寻找C程序入口(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记十一 汇编C语言基本类型
大神论坛 逆向脱壳分析基础学习笔记十二 汇编 全局和局部 变量(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记十三 汇编C语言类型转换(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记十四 汇编嵌套if else(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记十五 汇编比较三种循环(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记十六 汇编一维数组(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记十七 汇编二维数组 位移 乘法(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记十八 汇编 结构体和内存对齐(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记十九 汇编switch比较if else(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记二十 汇编 指针(一)(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记二十一 汇编 指针(二)(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记二十二 汇编 指针(三)(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记二十三 汇编 指针(四)(需登录才能访问)
大神论坛 逆向脱壳分析基础学习笔记二十四 汇编 指针(五) 系列完结(需登录才能访问)

更多逆向脱壳资源,请访问  大神论坛

汇编比较三种循环

众所周知,在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;
}


运行结果

image-20210303185910081

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


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
变量对应地址
iebp-4
jebp-8

接下来看循环语句部分:

第一行为:

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循环的执行流程为:

image-20210303205219083

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对应的地址

变量对应地址
iebp-4
jebp-8

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

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循环的执行流程为:

image-20210303203923715

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对应的地址

变量对应地址
iebp-4
jebp-8

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

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循环的执行流程为:

image-20210303204001738

三种循环总结

首先汇总三种循环的流程图:

for循环:

image-20210303205219083

while循环:

image-20210303203923715

do while循环:

image-20210303204001738


比较

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

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,满足条件则跳回去继续执行循环内的代码

版权声明:本文由 lyl610abc 原创,欢迎分享本文,转载请保留出处

返回顶部