C&汇编基础-循环语句
9unk Lv5

do…while 循环

  1. 源码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    void Function()
    {
    int i=0;
    do
    {
    printf("%d\n",i);
    i++;
    }while(i<=100);
    }
  2. 反汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
00401020   push        ebp
00401021 mov ebp,esp
00401023 sub esp,44h
00401026 push ebx
00401027 push esi
00401028 push edi
00401029 lea edi,[ebp-44h]
0040102C mov ecx,11h
00401031 mov eax,0CCCCCCCCh
00401036 rep stos dword ptr [edi]


00401038 mov dword ptr [ebp-4],0 //int i=0

0040103F mov eax,dword ptr [ebp-4]
00401042 push eax
00401043 push offset string "%d\n" (0041f10c)
00401048 call printf (0040b770)
0040104D add esp,8 //printf("%d\n",i);

00401050 mov ecx,dword ptr [ebp-4]
00401053 add ecx,1
00401056 mov dword ptr [ebp-4],ecx //i++

00401059 cmp dword ptr [ebp-4],64h
0040105D jle Function+1Fh (0040103f) //while(i<=100);

0040105F pop edi
00401060 pop esi
00401061 pop ebx
00401062 add esp,44h
00401065 cmp ebp,esp
00401067 call __chkesp (00401100)
0040106C mov esp,ebp
0040106E pop ebp
0040106F ret

do…while语句的表现形式

  1. JCC 指令会跳到循环语句的起始地址

  2. JCC 指令所在的地址,就是循环语句块的结束地址

  3. JCC 条件判断与源码相同

while 循环

  1. 源码
1
2
3
4
5
6
7
8
9
void Function1()
{
int i = 0;
while(i<=100)
{
printf("%d\n",i);
i++;
}
}
  1. 反汇编
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
00401070   push        ebp
00401071 mov ebp,esp
00401073 sub esp,44h
00401076 push ebx
00401077 push esi
00401078 push edi
00401079 lea edi,[ebp-44h]
0040107C mov ecx,11h
00401081 mov eax,0CCCCCCCCh
00401086 rep stos dword ptr [edi]

00401088 mov dword ptr [ebp-4],0
0040108F cmp dword ptr [ebp-4],64h
00401093 jg Function1+41h (004010b1)
00401095 mov eax,dword ptr [ebp-4]

00401098 push eax
00401099 push offset string "%d\n" (0041f10c)
0040109E call printf (0040b770)
004010A3 add esp,8

004010A6 mov ecx,dword ptr [ebp-4]
004010A9 add ecx,1
004010AC mov dword ptr [ebp-4],ecx
004010AF jmp Function1+1Fh (0040108f)

004010B1 pop edi
004010B2 pop esi
004010B3 pop ebx
004010B4 add esp,44h
004010B7 cmp ebp,esp
004010B9 call __chkesp (00401100)
004010BE mov esp,ebp
004010C0 pop ebp
004010C1 ret

while语句的表现形式

  1. JCC 会跳出循环,条件判读跳转的地址的上面一个是 jmp 指令

  2. 程序块运行结束后会使用 jmp 指令跳转到循环的起始地址。程序块的结尾是 jmp 指令的地址

  3. JCC 条件判断与源码相反

for 循环

  1. 源码
1
2
3
4
5
6
7
void Function2()
{
for(int i=0;i<=100;i++)
{
printf("%d\n",i);
}
}
  1. 反汇编
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
0040B7F0   push        ebp
0040B7F1 mov ebp,esp
0040B7F3 sub esp,44h
0040B7F6 push ebx
0040B7F7 push esi
0040B7F8 push edi
0040B7F9 lea edi,[ebp-44h]
0040B7FC mov ecx,11h
0040B801 mov eax,0CCCCCCCCh
0040B806 rep stos dword ptr [edi]

0040B808 mov dword ptr [ebp-4],0
0040B80F jmp Function2+2Ah (0040b81a) //int i=0;

0040B811 mov eax,dword ptr [ebp-4]
0040B814 add eax,1
0040B817 mov dword ptr [ebp-4],eax //i++

0040B81A cmp dword ptr [ebp-4],64h
0040B81E jg Function2+43h (0040b833) //i<=100;

0040B820 mov ecx,dword ptr [ebp-4]
0040B823 push ecx
0040B824 push offset string "%d\n" (0041f10c)
0040B829 call printf (0040b770)
0040B82E add esp,8
0040B831 jmp Function2+21h (0040b811) //printf("%d\n",i);

0040B833 pop edi
0040B834 pop esi
0040B835 pop ebx
0040B836 add esp,44h
0040B839 cmp ebp,esp
0040B83B call __chkesp (00401100)
0040B840 mov esp,ebp
0040B842 pop ebp
0040B843 ret

for 语句执行流程

  1. 执行参数1

  2. 执行参数2

  3. 执行循环语句

  4. 执行参数3

for 语句表现形式

  1. 第一个 jmp 指令前为赋初始值部分

  2. 第一个 jmp 指令所跳转的地址是循环条件的判断部分的起始地址

  3. JCC 判断条件成立时跳转到循环体外

  4. JCC 条件跳转地址上面有一个 jmp,jmp 地址为表达式3的起始位置

  5. JCC 条件判断与源码相反

练习

正向代码

  1. 将两个变量的值交换
1
2
3
4
5
6
7
8
9
10
11
void change(int x,int y)
{
int i;
i=x;
x=y;
y=i;


printf("%d,%d",x,y);

}
  1. 将一个数组中的数倒序输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void back()
{
int arr[10]={0,1,2,3,4,5,6,7,8,9};
int i,n,m,a;
int j=9;

for(i=0;i<=4;i++)
{
n=arr[i];
a=arr[j];
arr[i]=a;
arr[j]=n;
j=j-1;
}

for(m=0;m<=9;m++)
{
printf("%d ",arr[m]);
}
}
  1. 找出数组里最大的值,并返回
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int big()
{
int arr[10]={1,10,6,12,9,0,2,4,5,24};

int i;
int a=0;

for(i=0;i<=9;i++)
{
if(a<arr[i])
{
a=arr[i];
}
}
return a;
}
  1. 将数组中所有的值相加并返回
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int sum()
{
int arr[10]={1,3,6,7,9,0,2,4,5,8};
int i;
int sum=0;

for(i=0;i<=9;i++)
{
sum=sum+arr[i];
}

return sum;

}
  1. 打印一个数组中的所有的值
1
2
3
4
5
6
7
8
9
10
11
void print()
{
int arr[10]={1,3,6,7,9,0,2,4,5,8};

int i;

for(i=0;i<=9;i++)
{
printf("%d ",arr[i]);
}
}
  1. 将两个等长数组相同位置的值相加,存储到另外一个等长数组中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int plus()
{
int arr1[10]={1,2,3,4,5,6,7,8,9,10};
int arr2[10]={1,2,3,4,5,4,3,2,8,3};
int arr3[10];

int i,j;

for(i=0;i<=9;i++)
{
arr3[i]=arr1[i]+arr2[i];
}

for(j=0;j<=9;j++)
{
printf("%d ",arr3[j]);
}
return 0;

}
  1. 如果参数 x 是素数返回1,否则返回 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int prime(int x)
{
int i,j;
if(x<2)
{
j=0;
}
else
{
for(i = 2;i < x;i++)
{
if(x%i == 0)
{
j=0;
}
else
{
j=1;
}
}

}
return j;
}
  1. 俩俩比较数组的值,将最大的一个存储到数组的最后一个位置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void paixu()
{
int arr[10]={1,3,6,7,9,0,2,4,5,8};
int i,j,a,b;
int n=0;

for(j=0;j<=9;j++)
{
for(i=0;i<=9;i++)
{
a=arr[i];
b=arr[i+1];

if(a>b&&i+1<=9)
{
arr[i]=b;
arr[i+1]=a;
}
}
}

for(n=0;n<=9;n++)
{
printf("%d ",arr[n]);
}
}
  1. 判断数组是否是对称的,如果是返回 1,不是返回 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int duic()
{
int j,i;
int arr[10]={1,2,3,4,5,6,7,8,9,0};
j=sizeof(arr[10]);
if(j%2==0)
{
i=1;
}
else
{
i=0;
}
return i;
}
  1. 冒泡排序

冒泡排序原理:

  • 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
  • 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
  • 针对所有的元素重复以上的步骤,除了最后一个。
  • 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void Bubble()
{
int arr[]={1,3,6,7,9,0,2,4,5,8};
int i,j,a,b;
int n=0;
int size=0;

size=sizeof(arr)/sizeof(*arr)-1;

for(j=0;j<=size;j++)
{
for(i=0;i<=size;i++)
{
a=arr[i];
b=arr[i+1];

if(a>b&&i+1<=size)
{
arr[i]=b;
arr[i+1]=a;
}
}
}

for(n=0;n<=size;n++)
{
printf("%d ",arr[n]);
}
}

数组+for循环(例1)

反汇编

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
00401190   push        ebp
00401191 mov ebp,esp
00401193 sub esp,80h
00401199 push ebx
0040119A push esi
0040119B push edi
0040119C lea edi,[ebp-80h]
0040119F mov ecx,20h
004011A4 mov eax,0CCCCCCCCh
004011A9 rep stos dword ptr [edi]
004011AB mov dword ptr [ebp-14h],1
004011B2 mov dword ptr [ebp-10h],2
004011B9 mov dword ptr [ebp-0Ch],3
004011C0 mov dword ptr [ebp-8],4
004011C7 mov dword ptr [ebp-4],5
004011CE mov dword ptr [ebp-28h],4
004011D5 mov dword ptr [ebp-24h],3
004011DC mov dword ptr [ebp-20h],2
004011E3 mov dword ptr [ebp-1Ch],8
004011EA mov dword ptr [ebp-18h],3
004011F1 mov dword ptr [ebp-40h],0
004011F8 jmp plus+73h (00401203)
004011FA mov eax,dword ptr [ebp-40h]
004011FD add eax,1
00401200 mov dword ptr [ebp-40h],eax
00401203 cmp dword ptr [ebp-40h],9
00401207 jg plus+90h (00401220)
00401209 mov ecx,dword ptr [ebp-40h]
0040120C mov edx,dword ptr [ebp+ecx*4-14h]
00401210 mov eax,dword ptr [ebp-40h]
00401213 add edx,dword ptr [ebp+eax*4-28h]
00401217 mov ecx,dword ptr [ebp-40h]
0040121A mov dword ptr [ebp+ecx*4-3Ch],edx
0040121E jmp plus+6Ah (004011fa)
00401220 pop edi
00401221 pop esi
00401222 pop ebx
00401223 mov esp,ebp
00401225 pop ebp
00401226 ret

还原步骤

  1. 截取程序代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
004011AB   mov         dword ptr [ebp-14h],1
004011B2 mov dword ptr [ebp-10h],2
004011B9 mov dword ptr [ebp-0Ch],3
004011C0 mov dword ptr [ebp-8],4
004011C7 mov dword ptr [ebp-4],5
004011CE mov dword ptr [ebp-28h],4
004011D5 mov dword ptr [ebp-24h],3
004011DC mov dword ptr [ebp-20h],2
004011E3 mov dword ptr [ebp-1Ch],8
004011EA mov dword ptr [ebp-18h],3

004011F1 mov dword ptr [ebp-40h],0
004011F8 jmp plus+73h (00401203)
004011FA mov eax,dword ptr [ebp-40h]
004011FD add eax,1
00401200 mov dword ptr [ebp-40h],eax
00401203 cmp dword ptr [ebp-40h],9
00401207 jg plus+90h (00401220)
00401209 mov ecx,dword ptr [ebp-40h]
0040120C mov edx,dword ptr [ebp+ecx*4-14h]
00401210 mov eax,dword ptr [ebp-40h]
00401213 add edx,dword ptr [ebp+eax*4-28h]
00401217 mov ecx,dword ptr [ebp-40h]
0040121A mov dword ptr [ebp+ecx*4-3Ch],edx
0040121E jmp plus+6Ah (004011fa)

  1. 分析参数

  1. 变量分析

[ebp-40h]:i

  1. 数组分析
  • 数组是从栈的低地址到高地址存储的

  • 空数组在反汇编中不会回显示

  • 数组常见表现形式:[ebp+eax*数据类型宽度-最低地址]

  • 先确认这里有几个不同的低地址
    [ebp-14h];[ebp-28h]

  • 再确认数组的表现形式有几个
    [ebp+ecx4-14h];[ebp+eax4-28h];[ebp+ecx*4-3Ch]

  • 然后确定有三个数组
    [ebp-14h]:arr1
    [ebp-28h]:arr2
    [ebp-3Ch]:arr3

  1. 最后确认数组的类型和元素

dword:4 字节,int 型

int arr1[5] = {1,2,3,4,5}

int arr2[5] = {4,3,2,8,3,0}

int arr3[5]

  1. 分析循环
  • 判断循环的执行流程

jmp起始(跳到条件判断)–>条件判断(跳出循环)–>jmp结束(跳到jmp起始后面)
很明显这是一个 for 循环

  • 表达式1:第一个 jmp 前是变量赋值

i=0

  • 表达式2:条件判断与源码相反

jg(大于):<=
比较值:i<=9

  • 程序功能

arr3[i]=arr1[i]+arr2[i]

  • 表达式3

i+1

  1. 返回值

  1. 代码还原
1
2
3
4
5
6
7
8
9
10
11
void plus1()
{
int arr1[5] = {1,2,3,4,5};
int arr2[5] = {4,3,2,8,3,0};
int arr3[5];

for(int i=0;i<=9;i++)
{
arr3[i]=arr1[i]+arr2[i];
}
}
  • 本文标题:C&汇编基础-循环语句
  • 本文作者:9unk
  • 创建时间:2021-04-01 14:18:28
  • 本文链接:https://9unkk.github.io/2021/04/01/c-hui-bian-ji-chu-xun-huan-yu-ju/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!