在windows上,常用的函数调用方式有:
Pascal方式,WINAPI(_stdcall)方式 和C方式(_cdecl)
_cdecl调用规则:
1,参数从右到左入堆栈
2,在函数返回后,调用者要负责清除堆栈
所以这种调用常会生成较大的可执行文件。
_stdcall又称为WINAPI调用方式,规则:
1,参数从右向左入堆栈
2,被调用的函数在返回前自行清理堆栈
所以这种调用会生成比cdecl小的代码
Pascal调用方式,主要用在WIN16函数库中,现在基本不用
规则:
1,参数从左向右入堆栈
2,被调用函数在返回前自行清理堆栈
此外,在Windows内核中还常见的有快速调用方式(_fastcall)
在C++编译的代码中有this call方式(_thiscall)
在windows中,不管哪种方式,返回值都写在eax中,外部从中获取返回值
_cdecl方式步骤
1,保存ebp
2,保存esp到ebp
3,在堆栈中腾出一个区域来保存局部变量
4,保存ebx,esi,edi到堆栈中,函数调用完后返回
5,把局部变量区域初始化为0xcccccccch,实际上是int 3指令机器码,这是一个断点软中断
6,做函数里应该做的事情
7,恢复ebx,esi,edi,esp,ebp,最后返回
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 |
2: int
func( int
a, int b) 3: { 00401010 push ebp 00401011 mov ebp,esp 00401013 sub esp,44h 00401016 push ebx 00401017 push esi 00401018 push edi 00401019 lea edi,[ebp-44h] 0040101C mov ecx,11h 00401021 mov eax,0CCCCCCCCh 00401026 rep stos dword ptr [edi] 4: int
c = a + b; 00401028 mov eax,dword ptr [ebp+8] 0040102B add eax,dword ptr [ebp+0Ch] 0040102E mov dword ptr [ebp-4],eax 5: return
c; 00401031 mov eax,dword ptr [ebp-4] 6: } 00401034 pop edi 00401035 pop esi 00401036 pop ebx 00401037 mov esp,ebp 00401039 pop ebp 0040103A ret |
for循环的汇编代码分析:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 |
6: int
i; 7: for (i = 0 ;i < 50 ; i ++) 0040B501 mov dword ptr [ebp-8],0 0040B508 jmp func+33h (0040b513) 0040B50A mov ecx,dword ptr [ebp-8] 0040B50D add ecx,1 0040B510 mov dword ptr [ebp-8],ecx 0040B513 cmp dword ptr [ebp-8],32h 0040B517 jge func+44h (0040b524) 8: c = c + i; 0040B519 mov edx,dword ptr [ebp-4] 0040B51C add edx,dword ptr [ebp-8] 0040B51F mov dword ptr [ebp-4],edx 0040B522 jmp func+2Ah (0040b50a) 9: 10: return
c; 0040B524 mov eax,dword ptr [ebp-4] 11: } |
从上面的汇编代码可以分析出,for循环就是cmp指令+jmp指令
根据cmp判断然后跳转到那个位置执行代码
do...while循环分析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 |
5: 6: int
i = 0; 0040B501 mov dword ptr [ebp-8],0 7: 8: do
{ 9: c = c +i; 0040B508 mov ecx,dword ptr [ebp-4] 0040B50B add ecx,dword ptr [ebp-8] 0040B50E mov dword ptr [ebp-4],ecx 10: } while (c < 50); 0040B511 cmp dword ptr [ebp-4],32h 0040B515 jl func+28h (0040b508) 11: 12: return
c; 0040B517 mov eax,dword ptr [ebp-4] 13: } 0040B51A pop edi 0040B51B pop esi 0040B51C pop ebx 0040B51D mov esp,ebp 0040B51F pop ebp 0040B520 ret |
从上面代码可以看出
本质do...while循环和for差不多
while循环:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 |
6: int
i = 0; 0040B501 mov dword ptr [ebp-8],0 7: 8: while (i < 50) 0040B508 cmp dword ptr [ebp-8],32h 0040B50C jge func+39h (0040b519) 9: { 10: c = c +i; 0040B50E mov ecx,dword ptr [ebp-4] 0040B511 add ecx,dword ptr [ebp-8] 0040B514 mov dword ptr [ebp-4],ecx 11: }; 0040B517 jmp func+28h (0040b508) 12: 13: return
c; 0040B519 mov eax,dword ptr [ebp-4] 14: } 0040B51C pop edi 0040B51D pop esi 0040B51E pop ebx 0040B51F mov esp,ebp 0040B521 pop ebp 0040B522 ret |
if...else if...else语句分析
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
41
42
43
44
45
46
47
48 |
: 6: int
i = 0; 0040B501 mov dword ptr [ebp-8],0 7: 8: if (c>0 && c < 10) 0040B508 cmp dword ptr [ebp-4],0 0040B50C jle func+43h (0040b523) 0040B50E cmp dword ptr [ebp-4],0Ah 0040B512 jge func+43h (0040b523) 9: { 10: printf ( "c > 0" ); 0040B514 push offset string "c > 0"
(0041ff5c) 0040B519 call printf
(0040b780) 0040B51E add esp,4 11: } 12: else
if (c>10 && c<00) 0040B521 jmp func+6Bh (0040b54b) 0040B523 cmp dword ptr [ebp-4],0Ah 0040B527 jle func+5Eh (0040b53e) 0040B529 cmp dword ptr [ebp-4],0 0040B52D jge func+5Eh (0040b53e) 13: { 14: printf ( "c>10 && c<100" ); 0040B52F push offset string "c>10 && c<100"
(0041ff4c) 0040B534 call printf
(0040b780) 0040B539 add esp,4 15: } 16: else 0040B53C jmp func+6Bh (0040b54b) 17: { 18: printf ( "c>10 && c < 100" ); 0040B53E push offset string "c>10 && c < 100"
(0041ff3c) 0040B543 call printf
(0040b780) 0040B548 add esp,4 19: } 20: 21: return
c; 0040B54B mov eax,dword ptr [ebp-4] 22: } 0040B54E pop edi 0040B54F pop esi 0040B550 pop ebx 0040B551 add esp,48h 0040B554 cmp ebp,esp 0040B556 call __chkesp (0040b4a0) 0040B55B mov esp,ebp 0040B55D pop ebp 0040B55E ret |
switch...case 代码分析
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
41
42
43
44
45 |
4: int
c = a + b; 0040B4F8 mov eax,dword ptr [ebp+8] 0040B4FB add eax,dword ptr [ebp+0Ch] 0040B4FE mov dword ptr [ebp-4],eax 5: 6: switch (c) 7: { 0040B501 mov ecx,dword ptr [ebp-4] 0040B504 mov dword ptr [ebp-8],ecx 0040B507 cmp dword ptr [ebp-8],0 0040B50B je func+35h (0040b515) 0040B50D cmp dword ptr [ebp-8],1 0040B511 je func+42h (0040b522) 0040B513 jmp func+51h (0040b531) 8: case
0: 9: printf ( "c>0" ); 0040B515 push offset string "c>0"
(0041ff4c) 0040B51A call printf
(0040b780) 0040B51F add esp,4 10: case
1: 11: printf ( "c>10 && c<100" ); 0040B522 push offset string "c>10 && c<100"
(0041ff3c) 0040B527 call printf
(0040b780) 0040B52C add esp,4 12: break ; 0040B52F jmp func+5Eh (0040b53e) 13: default : 14: printf ( "c>10 && c<100" ); 0040B531 push offset string "c>10 && c<100"
(0041ff3c) 0040B536 call printf
(0040b780) 0040B53B add esp,4 15: } 16: 17: return
c; 0040B53E mov eax,dword ptr [ebp-4] 18: } 0040B541 pop edi 0040B542 pop esi 0040B543 pop ebx 0040B544 add esp,48h 0040B547 cmp ebp,esp 0040B549 call __chkesp (0040b4a0) 0040B54E mov esp,ebp 0040B550 pop ebp 0040B551 ret |
结构体分析
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 |
1: 2: typedef
struct { 3: int
a; 4: int
b; 5: int
c; 6: }mystruct; 7: 8: int
func( int
a, int b) 9: { 0040B800 push ebp 0040B801 mov ebp,esp 0040B803 sub esp,1D8h 0040B809 push ebx 0040B80A push esi 0040B80B push edi 0040B80C lea edi,[ebp-1D8h] 0040B812 mov ecx,76h 0040B817 mov eax,0CCCCCCCCh 0040B81C rep stos dword ptr [edi] 10: 11: unsigned char
*buf[100]; 12: mystruct *strs = (mystruct *)buf; 0040B81E lea eax,[ebp-190h] 0040B824 mov dword ptr [ebp-194h],eax 13: int
i; 14: for (i=0; i<5; i++) 0040B82A mov dword ptr [ebp-198h],0 0040B834 jmp func+45h (0040b845) 0040B836 mov ecx,dword ptr [ebp-198h] 0040B83C add ecx,1 0040B83F mov dword ptr [ebp-198h],ecx 0040B845 cmp dword ptr [ebp-198h],5 0040B84C jge func+94h (0040b894) 15: { 16: strs[i].a=0; 0040B84E mov edx,dword ptr [ebp-198h] 0040B854 imul edx,edx,0Ch 0040B857 mov eax,dword ptr [ebp-194h] 0040B85D mov dword ptr [eax+edx],0 17: strs[i].b=1; 0040B864 mov ecx,dword ptr [ebp-198h] 0040B86A imul ecx,ecx,0Ch 0040B86D mov edx,dword ptr [ebp-194h] 0040B873 mov dword ptr [edx+ecx+4],1 18: strs[i].c=2; 0040B87B mov eax,dword ptr [ebp-198h] 0040B881 imul eax,eax,0Ch 0040B884 mov ecx,dword ptr [ebp-194h] 0040B88A mov dword ptr [ecx+eax+8],2 19: } 0040B892 jmp func+36h (0040b836) 20: 21: return
0; 0040B894 xor eax,eax 22: } 0040B896 pop edi 0040B897 pop esi 0040B898 pop ebx 0040B899 mov esp,ebp 0040B89B pop ebp 0040B89C ret |
从上面不难看出,结构体赋值是先经过计算,然后把基址存放的一个变量
然后计算每个结构体的偏移量,然后对每个struct进行定数累加赋值
枚举,联合,结构结合分析:
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80 |
1: typedef
enum { 2: ENUM_1 = 1, 3: ENUM_2 = 2, 4: ENUM_3, 5: ENUM_4 6: }myenum; 7: 8: typedef
struct { 9: int
a; 10: int
b; 11: int
c; 12: }mystruct; 13: 14: typedef
union { 15: mystruct s; 16: myenum e[3]; 17: }myunion; 18: 19: int
func( int
a, int b) 20: { 00401020 push ebp 00401021 mov ebp,esp 00401023 sub esp,0ACh 00401029 push ebx 0040102A push esi 0040102B push edi 0040102C lea edi,[ebp-0ACh] 00401032 mov ecx,2Bh 00401037 mov eax,0CCCCCCCCh 0040103C rep stos dword ptr [edi] 21: unsigned char
buf[100] = {0}; 0040103E mov byte ptr [ebp-64h],0 00401042 mov ecx,18h 00401047 xor eax,eax 00401049 lea edi,[ebp-63h] 0040104C rep stos dword ptr [edi] 0040104E stos word ptr [edi] 00401050 stos byte ptr [edi] 22: myunion *uns = (myunion *)buf; 00401051 lea eax,[ebp-64h] 00401054 mov dword ptr [ebp-68h],eax 23: 24: int
i; 25: 26: for (i = 0; i < 5; i++) 00401057 mov dword ptr [ebp-6Ch],0 0040105E jmp func+49h (00401069) 00401060 mov ecx,dword ptr [ebp-6Ch] 00401063 add ecx,1 00401066 mov dword ptr [ebp-6Ch],ecx 00401069 cmp dword ptr [ebp-6Ch],5 0040106D jge func+83h (004010a3) 27: { 28: uns[i].s.a=0; 0040106F mov edx,dword ptr [ebp-6Ch] 00401072 imul edx,edx,0Ch 00401075 mov eax,dword ptr [ebp-68h] 00401078 mov dword ptr [eax+edx],0 29: uns[i].s.b = 1; 0040107F mov ecx,dword ptr [ebp-6Ch] 00401082 imul ecx,ecx,0Ch 00401085 mov edx,dword ptr [ebp-68h] 00401088 mov dword ptr [edx+ecx+4],1 30: uns[i].e[2] = ENUM_4; 00401090 mov eax,dword ptr [ebp-6Ch] 00401093 imul eax,eax,0Ch 00401096 mov ecx,dword ptr [ebp-68h] 00401099 mov dword ptr [ecx+eax+8],4 31: } 004010A1 jmp func+40h (00401060) 32: 33: return
0; 004010A3 xor eax,eax 34: } 004010A5 pop edi 004010A6 pop esi 004010A7 pop ebx 004010A8 mov esp,ebp 004010AA pop ebp 004010AB ret |
我们发现这段代码和上面的汇编后代码基本一样,因此我们知道,汇编中对共用体和枚举类型没有特别的处理
并不会引入新的代码,因为共用体和枚举都是方便给程序员用的,本质没什么改变
原文地址:http://www.cnblogs.com/lfsblack/p/3763993.html