高级C代码的汇编分析

在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

我们发现这段代码和上面的汇编后代码基本一样,因此我们知道,汇编中对共用体和枚举类型没有特别的处理

并不会引入新的代码,因为共用体和枚举都是方便给程序员用的,本质没什么改变

高级C代码的汇编分析

时间: 2024-10-13 17:49:07

高级C代码的汇编分析的相关文章

VC++代码的汇编分析(一)

VC++代码是最接近汇编指令的高级语言,为了更加准确和深刻理解VC++编码中所涉及的很多技术概念和编译器参数的含义,从汇编指令层面进行剖析和解读,有助于开发者更加准确.直观.深刻理解高级语言中很多概念和技术的真正含义,对程序优化和编码都有非常实用的重要价值.由于内容很多,我会分解为很多篇章进行解读实例. 从main入口开始分析,使用古老的VC6.0编译器编译,先从最简单的例子开始逐步扩展,便于大家逐步入门. VC++源代码: int main(int argc, char* argv[]) {p

FreeRTOS高级篇4---FreeRTOS任务切换分析

FreeRTOS任务相关的代码大约占总代码的一半左右,这些代码都在为一件事情而努力,即找到优先级最高的就绪任务,并使之获得CPU运行权.任务切换是这一过程的直接实施者,为了更快的找到优先级最高的就绪任务,任务切换的代码通常都是精心设计的,甚至会用到汇编指令或者与硬件相关的特性,比如Cortex-M3的CLZ指令.因此任务切换的大部分代码是由硬件移植层提供的,不同的平台,实现发方法也可能不同,这篇文章以Cortex-M3为例,讲述FreeRTOS任务切换的过程. FreeRTOS有两种方法触发任务

GDB调试汇编分析

GDB调试汇编分析 代码 本次实践我参照了许多先做了的同学的博客,有卢肖明,高其,张梓靖同学.代码借用的是卢肖明同学的代码进行调试运行. GCC编译 使用gcc -g gdbtest.c -o gdbtest -m32命令在64位的机器上产生32位汇编代码 在使用gdb进行调试运行时,有cgdb和gdb两种工具,我建议大家使用张梓靖同学使用的cgdb工具,因为使用时可以随时看到自己的源代码,看到我们的断点在哪里,每一步返回值到了哪行,更加直观. 分析过程 使用b main指令在main函数处设置

CVE-2017-7269—IIS 6.0 WebDAV远程代码执行漏洞分析

漏洞描述: 3月27日,在Windows 2003 R2上使用IIS 6.0 爆出了0Day漏洞(CVE-2017-7269),漏洞利用PoC开始流传,但糟糕的是这产品已经停止更新了.网上流传的poc下载链接如下. github地址:https://github.com/edwardz246003/IIS_exploit 结合上面的POC,我们对漏洞的成因及利用过程进行了详细的分析.在分析过程中,对poc的exploit利用技巧感到惊叹,多次使用同一个漏洞函数触发,而同一个漏洞同一段漏洞利用代码

MDU某产品OMCI模块代码质量现状分析

说明 本文参考MDU系列某产品OMCI模块现有代码,提取若干实例以说明目前的代码质量. 本文旨在就事论事,而非否定前人(没有前人的努力也难有后人的进步).希望以史为鉴,不破不立,最终产出高质量的代码. 一  质量现状 不考虑业务实现,现有的OMCI模块代码质量不甚理想.无论是理解上手.修改扩展和测试排障,可以用举步维艰形容.尤其是二层通道计算相关代码,堪比令史前动物无法自拔的"焦油坑". 本节将不考虑流程设计,仅就函数粒度列举目前存在的较为突出的代码质量问题. 1.1 巨型函数 通过S

FreeRTOS高级篇8---FreeRTOS任务通知分析

在FreeRTOS版本V8.2.0中推出了全新的功能:任务通知.在大多数情况下,任务通知可以替代二进制信号量.计数信号量.事件组,可以替代数长度为1的队列(可以保存一个32位整数或指针值),并且任务通知速度更快.使用的RAM更少!我在< FreeRTOS系列第14篇---FreeRTOS任务通知>一文中介绍了任务通知如何使用以及局限性,今天我们将分析任务通知的实现源码,看一下任务通知是如何做到效率与RAM消耗双赢的.        在<FreeRTOS高级篇6---FreeRTOS信号量

Taitherm (ex-Radtherm) v12.0.0 Win64 &amp; Linux64 2CD高级热管理设计与分析

Taitherm (ex-Radtherm) v12.0.0 Win64 & Linux64 2CD高级热管理设计与分析工一款用于计算辐射视角系数和阳光照射的先进光线跟踪技术,是新一代高级热管理设计与分析工具,堪称目前市场上最快的辐射换热求解器之 一.在近20年前,ThermoAnalytics的创始人设计了只能用于放射和辐射的求解器,被命名为RadTherm.在过去的二十年中,这款软件已经发 展到了支持分析计算所有的热传递模式:辐射.传导.对流.以及平流等.正如发布的Taitherm (ex-

【JS 设计模式 】用组合模式来实现树形导航--代码结构思路分析(一)

树导航效果图: 组合模式的描述: 将对象组合成树形结构以表示"部分-整体"的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性. 我们把部分用Leaf表示, 把整体用Composite表示.组合模式是有一定规律的,在实现树导航的情况下,Composite需要包含一个以上Leaf,也可以包含一个以上Leaf和一个以Composite,为什么说要包含一个以上的,如果Composite不包含任何子child的话那么它就是Leaf,Leaf表示是最后一层结节. 树形导航代码片段:

【JS 设计模式 】用组合模式来实现树形导航--JS代码结构思路分析(二)

[JS 设计模式 ]用组合模式来实现树形导航--代码结构思路分析(一) 根据上一节中的HTML代码结构我们通过JS来渲染HTML代码,我们先提供一下JS的代码片段,这代码代码不是一个完整的代码是经过简化的.通过JS代码来分析如何组装HTML的 Composite类型的代码: function TreeComposite(id, name, total, level, last) { var root = document.createDocumentFragment(); var panel =