博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++反汇编: 基础知识(7)
阅读量:5118 次
发布时间:2019-06-13

本文共 44089 字,大约阅读时间需要 146 分钟。

反汇编(Disassembly),即把目标二进制机器码转为汇编代码的过程,该技术常用于软件破解、外挂技术、病毒分析、逆向工程、软件汉化等领域,学习和理解反汇编语言对软件调试、漏洞分析、内核原理及理解高级语言代码都有相当大的帮助,软件一切神秘的运行机制全在反汇编代码里面,该笔记整理了C++反汇编的一些常识.

变量与常量

数值类型变量: 整数,浮点数,等类型其反汇编结果基本相同.

int main(int argc, char* argv[]){    int x = 10;    int y = 20;    int z = 0;    z = x + y;    return 0;}

反汇编结果如下,首先lea取地址,然后ECX=13,这里的13是因为我们有3个整数型变量,每个变量占用4个字节,所以4x3=12次,将EAX设置为CCCCCCC,并通过rep指令填充内存地址从[edi]指向的位置开始填充,填充14次,同样的也初始化了堆栈,接着通过mov赋值语句将内存地址分别初始化为指定的数值.

0040D709  |.  8D7D B4       lea     edi, dword ptr [ebp-4C]0040D70C  |.  B9 13000000   mov     ecx, 130040D711  |.  B8 CCCCCCCC   mov     eax, CCCCCCCC0040D716  |.  F3:AB         rep     stos dword ptr es:[edi]0040D718  |.  C745 FC 0A000>mov     dword ptr [ebp-4], 0A0040D71F  |.  C745 F8 14000>mov     dword ptr [ebp-8], 140040D726  |.  C745 F4 00000>mov     dword ptr [ebp-C], 00040D72D  |.  8B45 FC       mov     eax, dword ptr [ebp-4]0040D730  |.  0345 F8       add     eax, dword ptr [ebp-8]0040D733  |.  8945 F4       mov     dword ptr [ebp-C], eax

字符类型:

int main(int argc, char* argv[]){    char x = 'a';    char y = 'b';    char z = 'c';    z = x+y;    printf("%s",z);    return 0;}

反汇编结果如下,观察发现字符型的表现形式与整数类型基本一致,只是在数据位大小方面有所区别,如上int类型使用dword作为存储单位,而字符类型则默认使用byte形式存储.

00410659  |.  8D7D B4       lea     edi, dword ptr [ebp-4C]0041065C  |.  B9 13000000   mov     ecx, 1300410661  |.  B8 CCCCCCCC   mov     eax, CCCCCCCC00410666  |.  F3:AB         rep     stos dword ptr es:[edi]00410668  |.  C645 FC 61    mov     byte ptr [ebp-4], 610041066C  |.  C645 F8 62    mov     byte ptr [ebp-8], 6200410670  |.  C645 F4 63    mov     byte ptr [ebp-C], 6300410674  |.  0FBE45 FC     movsx   eax, byte ptr [ebp-4]00410678  |.  0FBE4D F8     movsx   ecx, byte ptr [ebp-8]0041067C  |.  03C1          add     eax, ecx0041067E  |.  8845 F4       mov     byte ptr [ebp-C], al

字符串:

int main(int argc, char* argv[]){    char x[] = "hello lyshark";    printf("%s",x);    return 0;}
00401019  |.  8D7D B0            lea     edi, dword ptr [ebp-50]0040101C  |.  B9 14000000        mov     ecx, 1400401021  |.  B8 CCCCCCCC        mov     eax, CCCCCCCC00401026  |.  F3:AB              rep     stos dword ptr es:[edi]00401028  |.  A1 1C204200        mov     eax, dword ptr [42201C]0040102D  |.  8945 F0            mov     dword ptr [ebp-10], eax00401030  |.  8B0D 20204200      mov     ecx, dword ptr [422020]00401036  |.  894D F4            mov     dword ptr [ebp-C], ecx00401039  |.  8B15 24204200      mov     edx, dword ptr [422024]0040103F  |.  8955 F8            mov     dword ptr [ebp-8], edx00401042  |.  66:A1 28204200     mov     ax, word ptr [422028]00401048  |.  66:8945 FC         mov     word ptr [ebp-4], ax0040104C  |.  8D4D F0            lea     ecx, dword ptr [ebp-10]   ; 存储字符串首地址

长字符串:

int main(int argc, char* argv[]){    char temp[] = "welcome to lyshark blog";    printf("%s",temp);    return 0;}
00401019  |.  8D7D A8            lea     edi, dword ptr [ebp-58]0040101C  |.  B9 16000000        mov     ecx, 1600401021  |.  B8 CCCCCCCC        mov     eax, CCCCCCCC00401026  |.  F3:AB              rep     stos dword ptr es:[edi]00401028  |.  B9 06000000        mov     ecx, 60040102D  |.  BE AC2F4200        mov     esi, 00422FAC                              ;  ASCII "welcome to lyshark blog"00401032  |.  8D7D E8            lea     edi, dword ptr [ebp-18]00401035  |.  F3:A5              rep     movs dword ptr es:[edi], dword ptr [esi]00401037  |.  8D45 E8            lea     eax, dword ptr [ebp-18]0040103A  |.  50                 push    eax                                        ; /<%s>0040103B  |.  68 04244200        push    00422404                                   ; |format = "%s"00401040  |.  E8 3BC60000        call    printf                                     ; \printf

字符串指针:

int main(int argc, char* argv[]){    char *x = "hello lyshark";    printf("%s",x);    return 0;}
00401019  |.  8D7D BC            lea     edi, dword ptr [ebp-44]0040101C  |.  B9 11000000        mov     ecx, 1100401021  |.  B8 CCCCCCCC        mov     eax, CCCCCCCC00401026  |.  F3:AB              rep     stos dword ptr es:[edi]00401028  |.  C745 FC 1C204200   mov     dword ptr [ebp-4], 0042201C0040102F  |.  8B45 FC            mov     eax, dword ptr [ebp-4]           ;  aaa.0042201C00401032  |.  50                 push    eax                              ; /<%s>00401033  |.  68 04244200        push    00422404                         ; |format = "%s"00401038  |.  E8 43C60000        call    printf                           ; \printf

数组类型:

int main(int argc, char* argv[]){    int array[] = {1,2,3,4,5};    printf("%d\n",array[0]);    printf("%d\n",array[1]);    return 0;}
0040D718  |.  C745 EC 01000000   mov     dword ptr [ebp-14], 10040D71F  |.  C745 F0 02000000   mov     dword ptr [ebp-10], 20040D726  |.  C745 F4 03000000   mov     dword ptr [ebp-C], 30040D72D  |.  C745 F8 04000000   mov     dword ptr [ebp-8], 40040D734  |.  C745 FC 05000000   mov     dword ptr [ebp-4], 50040D73B  |.  8B45 EC            mov     eax, dword ptr [ebp-14]0040D73E  |.  50                 push    eax                                        ; /<%d> = 10040D73F  |.  68 1C204200        push    0042201C                                   ; |format = "%d"0040D744  |.  E8 37FFFFFF        call    printf                                     ; \printf0040D749  |.  83C4 08            add     esp, 80040D74C  |.  8B4D F0            mov     ecx, dword ptr [ebp-10]0040D74F  |.  51                 push    ecx                                        ; /<%d>0040D750  |.  68 1C204200        push    0042201C                                   ; |format = "%d"0040D755  |.  E8 26FFFFFF        call    printf                                     ; \printf

二维数组是一位的高阶抽象.

常量折叠: 在编译前遇到常量,都会进行计算,得出一个新的常量值,这样则可以直接Push常量节约资源.

int main(int argc, char* argv[]){    printf("%d\n",1+2);     // 常量+常量    return 0;}
0040D438  |.  C745 FC 00000000   mov     dword ptr [ebp-4], 10040D43F  |.  C745 F8 01000000   mov     dword ptr [ebp-8], 20040D446  |.  6A 03              push    3                                          ; 1+2直接Push30040D448  |.  68 1C204200        push    0042201C                                   ; |format = "%d"0040D44D  |.  E8 9E020000        call    printf                                     ; \printf0040D452  |.  83C4 08            add     esp, 8

常量传播: 如果两个变量从来都没被修改过,也没有传入过参数,在VS2013编译器中会被优化成常量.

int main(int argc, char* argv[]){    int x = 1;    int y = 3;    printf("%d\n",x+y);     // 变量+变量    return 0;}
0040D438  |.  C745 FC 01000>mov     dword ptr [ebp-4], 10040D43F  |.  C745 F8 03000>mov     dword ptr [ebp-8], 30040D44C  |.  50            push    4                                ; /<%d>0040D44D  |.  68 1C204200   push    0042201C                         ; |format = "%d"0040D452  |.  E8 99020000   call    printf                           ; \printf0040D457  |.  83C4 08       add     esp, 8

窥孔优化:一种很局部的优化方式,编译器仅仅在一个基本块或者多个基本块中,针对已经生成的代码,结合CPU自己指令的特点,过一些认为可能带来性能提升的转换规则,或者通过整体的分析,通过指令转换,提升代码性能。这个窥孔,你可以认为是一个滑动窗口,编译器在实施窥孔优化时,就仅仅分析这个窗口内的指令。每次转换之后,可能还会暴露相邻窗口之间的某些优化机会,所以可以多次调用窥孔优化,尽可能提升性能

运算符相关

乘法:

int main(int argc, char* argv[]){    int x = 10;    int y = 300;    int z = 0;    z = x * y;    printf("%d\n",z);    return 0;}
0040D438  |.  C745 FC 0A000>mov     dword ptr [ebp-4], 0A0040D43F  |.  C745 F8 2C010>mov     dword ptr [ebp-8], 12C0040D446  |.  C745 F4 00000>mov     dword ptr [ebp-C], 00040D44D  |.  8B45 FC       mov     eax, dword ptr [ebp-4]0040D450  |.  0FAF45 F8     imul    eax, dword ptr [ebp-8]0040D454  |.  8945 F4       mov     dword ptr [ebp-C], eax0040D457  |.  8B4D F4       mov     ecx, dword ptr [ebp-C]0040D45A  |.  51            push    ecx                              ; /<%d>0040D45B  |.  68 1C204200   push    0042201C                         ; |format = "%d"0040D460  |.  E8 8B020000   call    printf                           ; \printf

除法: cdq指令扩展标志位 edx 高位 :eax 低位

int main(int argc, char* argv[]){    int x = 1000;    int y = 20;    int z = 0;    z = x/y;    printf("%d\n",z);    return 0;}
0040D438  |.  C745 FC E8030>mov     dword ptr [ebp-4], 3E80040D43F  |.  C745 F8 14000>mov     dword ptr [ebp-8], 140040D446  |.  C745 F4 00000>mov     dword ptr [ebp-C], 00040D44D  |.  8B45 FC       mov     eax, dword ptr [ebp-4]0040D450  |.  99            cdq0040D451  |.  F77D F8       idiv    dword ptr [ebp-8]0040D454  |.  8945 F4       mov     dword ptr [ebp-C], eax0040D457  |.  8B45 F4       mov     eax, dword ptr [ebp-C]0040D45A  |.  50            push    eax                              ; /<%d>0040D45B  |.  68 1C204200   push    0042201C                         ; |format = "%d"0040D460  |.  E8 8B020000   call    printf                           ; \printf

复合运算:

int main(int argc, char* argv[]){    int a = 10;    int b = 20;    int x = (a*a+b);    int y = x*5;    return 0;}
00401028  |.  C745 FC 0A000>mov     dword ptr [ebp-4], 0A0040102F  |.  C745 F8 14000>mov     dword ptr [ebp-8], 1400401036  |.  8B45 FC       mov     eax, dword ptr [ebp-4]00401039  |.  0FAF45 FC     imul    eax, dword ptr [ebp-4]0040103D  |.  0345 F8       add     eax, dword ptr [ebp-8]00401040  |.  8945 F4       mov     dword ptr [ebp-C], eax00401043  |.  8B4D F4       mov     ecx, dword ptr [ebp-C]00401046  |.  6BC9 05       imul    ecx, ecx, 500401049  |.  894D F0       mov     dword ptr [ebp-10], ecx

多目运算符:

int main(int argc, char* argv[]){    unsigned int temp;    scanf("%d",&temp);    printf("%d\r\n",temp == 0 ? 0:-1);    // 针对有符号数    printf("%d\r\n",temp == 0 ? 1:0);     // 针对无符号数    printf("%d\r\n",temp >= 1 ? 35:98);   // 大于等于    return 0;}

针对有符号数

0040F979  |.  8B4D FC       mov     ecx, dword ptr [ebp-4]0040F97C  |.  F7D9          neg     ecx0040F97E  |.  1BC9          sbb     ecx, ecx0040F980  |.  51            push    ecx                              ; /<%d>0040F981  |.  68 802E4200   push    00422E80                         ; |format = "%d"0040F986  |.  E8 45FFFFFF   call    printf                           ; \printf0040F98B  |.  83C4 08       add     esp, 8

针对无符号数

0040F990  |.  837D FC 00    cmp     dword ptr [ebp-4], 00040F994  |.  0F94C2        sete    dl0040F997  |.  52            push    edx                              ; /<%d>0040F998  |.  68 802E4200   push    00422E80                         ; |format = "%d"0040F99D  |.  E8 2EFFFFFF   call    printf                           ; \printf0040F9A2  |.  83C4 08       add     esp, 8

大于等于符号

0040F9A5  |.  837D FC 01    cmp     dword ptr [ebp-4], 10040F9A9  |.  1BC0          sbb     eax, eax0040F9AB  |.  83E0 3F       and     eax, 3F0040F9AE  |.  83C0 23       add     eax, 230040F9B1  |.  50            push    eax                              ; /<%d>0040F9B2  |.  68 802E4200   push    00422E80                         ; |format = "%d"0040F9B7  |.  E8 14FFFFFF   call    printf                           ; \printf0040F9BC  |.  83C4 08       add     esp, 8

流程控制

IF

条件分支:

int main(int argc, char* argv[]){    int x = 10;    int y = 20;    int z = 30;    if( x >= y){        printf("x >= y");    }else if(z >= x){        printf("z >= x");    }    return 0;}
00401028    C745 FC 0A00000>mov     dword ptr [ebp-4], 0A0040102F    C745 F8 1400000>mov     dword ptr [ebp-8], 1400401036    C745 F4 1E00000>mov     dword ptr [ebp-C], 1E0040103D    8B45 FC         mov     eax, dword ptr [ebp-4]00401040    3B45 F8         cmp     eax, dword ptr [ebp-8]00401043    7C 0F           jl      short 0040105400401045    68 24204200     push    00422024                         ; ASCII "x >= y"0040104A    E8 51000000     call    printf0040104F    83C4 04         add     esp, 400401052    EB 15           jmp     short 0040106900401054    8B4D F4         mov     ecx, dword ptr [ebp-C]00401057    3B4D FC         cmp     ecx, dword ptr [ebp-4]0040105A    7C 0D           jl      short 004010690040105C    68 1C204200     push    0042201C                         ; ASCII "z >= x"00401061    E8 3A000000     call    printf00401066    83C4 04         add     esp, 4

嵌套条件分支:

int main(int argc, char* argv[]){    int x = 10;    int y = 20;    int z = 30;    if( z >= y){        if(x < y){            printf(" z>=y and x
=y and x >y"); } } return 0;}
00401028  |.  C745 FC 0A000000 mov     dword ptr [ebp-4], 0A0040102F  |.  C745 F8 14000000 mov     dword ptr [ebp-8], 1400401036  |.  C745 F4 1E000000 mov     dword ptr [ebp-C], 1E0040103D  |.  8B45 F4          mov     eax, dword ptr [ebp-C]00401040  |.  3B45 F8          cmp     eax, dword ptr [ebp-8]00401043  |.  7C 24            jl      short 0040106900401045  |.  8B4D FC          mov     ecx, dword ptr [ebp-4]00401048  |.  3B4D F8          cmp     ecx, dword ptr [ebp-8]0040104B  |.  7D 0F            jge     short 0040105C0040104D  |.  68 1C204200      push    0042201C                         ; /format = " z>=y and x
68 AC2F4200 push 00422FAC ; /format = " z >=y and x >y"00401061 |. E8 3A000000 call printf ; \printf00401066 |. 83C4 04 add esp, 4

and

int main(int argc, char* argv[]){    int x = 10;    int y = 20;    int z = 30;    if(x
x) { printf("x
x"); } return 0;}
00401028  |.  C745 FC 0A000000 mov     dword ptr [ebp-4], 0A0040102F  |.  C745 F8 14000000 mov     dword ptr [ebp-8], 1400401036  |.  C745 F4 1E000000 mov     dword ptr [ebp-C], 1E0040103D  |.  8B45 FC          mov     eax, dword ptr [ebp-4]00401040  |.  3B45 F8          cmp     eax, dword ptr [ebp-8]00401043  |.  7D 15            jge     short 0040105A00401045  |.  8B4D F4          mov     ecx, dword ptr [ebp-C]00401048  |.  3B4D FC          cmp     ecx, dword ptr [ebp-4]0040104B  |.  7E 0D            jle     short 0040105A0040104D  |.  68 AC2F4200      push    00422FAC                         ; /format = "x
x"00401052 |. E8 49000000 call printf ; \printf00401057 |. 83C4 04 add esp, 4

OR:

int main(int argc, char* argv[]){    int x = 10;    int y = 20;    int z = 30;    if(x
x) { printf("x
x"); } return 0;}
00401028  |.  C745 FC 0A000000 mov     dword ptr [ebp-4], 0A0040102F  |.  C745 F8 14000000 mov     dword ptr [ebp-8], 1400401036  |.  C745 F4 1E000000 mov     dword ptr [ebp-C], 1E0040103D  |.  8B45 FC          mov     eax, dword ptr [ebp-4]00401040  |.  3B45 F8          cmp     eax, dword ptr [ebp-8]00401043  |.  7C 08            jl      short 0040104D00401045  |.  8B4D F4          mov     ecx, dword ptr [ebp-C]00401048  |.  3B4D FC          cmp     ecx, dword ptr [ebp-4]0040104B  |.  7E 0D            jle     short 0040105A0040104D  |.  68 AC2F4200      push    00422FAC                         ; /format = "x
x"00401052 |. E8 49000000 call printf ; \printf00401057 |. 83C4 04 add esp, 4

While

while 单循环:

int main(int argc, char* argv[]){    int x = 0;    while(x <= 10){        printf("%d",x);        x++;    }    return 0;}

x++ 是jge来操控,++x是jg

00401028  |.  C745 FC 00000 |mov     dword ptr [ebp-4], 00040102F  |>  837D FC 0A    |cmp     dword ptr [ebp-4], 0A00401033  |.  7D 1C         |jge     short 0040105100401035  |.  8B45 FC       |mov     eax, dword ptr [ebp-4]00401038  |.  50            |push    eax                             ; /<%d>00401039  |.  68 1C204200   |push    0042201C                        ; |format = "%d"0040103E  |.  E8 5D000000   |call    printf                          ; \printf00401043  |.  83C4 08       |add     esp, 800401046  |.  8B4D FC       |mov     ecx, dword ptr [ebp-4]00401049  |.  83C1 01       |add     ecx, 10040104C  |.  894D FC       |mov     dword ptr [ebp-4], ecx0040104F  |.^ EB DE         |jmp     short 0040102F

while 嵌套循环:

int main(int argc, char* argv[]){    int x = 0;    int y = 0;    while(x <= 10){        while(y <=5){            printf("%d,%d \n",x,y);            y++;        }            x++;            y=0;    }    return 0;}
00401028  |.  C745 FC 00000000   |mov     dword ptr [ebp-4], 00040102F  |.  C745 F8 00000000   |mov     dword ptr [ebp-8], 000401036  |>  837D FC 0A         |cmp     dword ptr [ebp-4], 0A0040103A  |.  7F 38              |jg      short 004010740040103C  |>  837D F8 05         |cmp     dword ptr [ebp-8], 500401040  |.  7F 20              |jg      short 0040106200401042  |.  8B45 F8            |mov     eax, dword ptr [ebp-8]00401045  |.  50                 |push    eax                            ; /<%d>00401046  |.  8B4D FC            |mov     ecx, dword ptr [ebp-4]         ; |00401049  |.  51                 |push    ecx                            ; |<%d>0040104A  |.  68 1C204200        |push    0042201C                       ; |format = "%d,%d"0040104F  |.  E8 4C000000        |call    printf                         ; \printf00401054  |.  83C4 0C            |add     esp, 0C00401057  |.  8B55 F8            |mov     edx, dword ptr [ebp-8]0040105A  |.  83C2 01            |add     edx, 10040105D  |.  8955 F8            |mov     dword ptr [ebp-8], edx00401060  |.^ EB DA              |jmp     short 0040103C00401062  |>  8B45 FC            |mov     eax, dword ptr [ebp-4]00401065  |.  83C0 01            |add     eax, 100401068  |.  8945 FC            |mov     dword ptr [ebp-4], eax0040106B  |.  C745 F8 00000000   |mov     dword ptr [ebp-8], 000401072  |.^ EB C2              |jmp     short 00401036

do-while 循环:

int main(int argc, char* argv[]){    int x = 0;    do    {        if(x/2 == 0){            printf("%d \n",x);        }        x++;    }while(x<=10);    return 0;}
00401028  |.  C745 FC 00000000   |mov     dword ptr [ebp-4], 00040102F  |>  8B45 FC            |mov     eax, dword ptr [ebp-4]00401032  |.  99                 |cdq00401033  |.  2BC2               |sub     eax, edx00401035  |.  D1F8               |sar     eax, 100401037  |.  85C0               |test    eax, eax00401039  |.  75 11              |jnz     short 0040104C0040103B  |.  8B45 FC            |mov     eax, dword ptr [ebp-4]0040103E  |.  50                 |push    eax                             ; /<%d>0040103F  |.  68 1C204200        |push    0042201C                        ; |format = "%d"00401044  |.  E8 57000000        |call    printf                          ; \printf00401049  |.  83C4 08            |add     esp, 80040104C  |>  8B4D FC            |mov     ecx, dword ptr [ebp-4]0040104F  |.  83C1 01            |add     ecx, 100401052  |.  894D FC            |mov     dword ptr [ebp-4], ecx00401055  |.  837D FC 0A         |cmp     dword ptr [ebp-4], 0A00401059  |.^ 7E D4              |jle     short 0040102F

FOR

单分支:

int main(int argc, char* argv[]){    int x;    for(x=0;x<=10;x++)    {        printf("%d\n",x);    }    return 0;}
00401028  |.  C745 FC 00000000   |mov     dword ptr [ebp-4], 00040102F  |.  EB 09              |jmp     short 0040103A00401031  |>  8B45 FC            |mov     eax, dword ptr [ebp-4]00401034  |.  83C0 01            |add     eax, 100401037  |.  8945 FC            |mov     dword ptr [ebp-4], eax0040103A  |>  837D FC 0A         |cmp     dword ptr [ebp-4], 0A0040103E  |.  7F 13              |jg      short 0040105300401040  |.  8B4D FC            |mov     ecx, dword ptr [ebp-4]00401043  |.  51                 |push    ecx                             ; /<%d>00401044  |.  68 1C204200        |push    0042201C                        ; |format = "%d"00401049  |.  E8 52000000        |call    printf                          ; \printf0040104E  |.  83C4 08            |add     esp, 800401051  |.^ EB DE              |jmp     short 00401031

多分支:

int main(int argc, char* argv[]){    int array[2][3] = {
{1,2,3},{1,2,3}}; int x,y; for(x=0;x<2;x++) { for(y=0;y<3;y++) { printf("%d \n",array[x][y]); } } return 0;}
0040D779  |. /EB 09              |jmp     short 0040D7840040D77B  |> |8B45 E4            |mov     eax, dword ptr [ebp-1C]0040D77E  |. |83C0 01            |add     eax, 10040D781  |. |8945 E4            |mov     dword ptr [ebp-1C], eax0040D784  |> \837D E4 02         |cmp     dword ptr [ebp-1C], 20040D788  |.  7D 3A              |jge     short 0040D7C40040D78A  |.  C745 E0 00000000   |mov     dword ptr [ebp-20], 00040D791  |.  EB 09              |jmp     short 0040D79C0040D793  |>  8B4D E0            |mov     ecx, dword ptr [ebp-20]0040D796  |.  83C1 01            |add     ecx, 10040D799  |.  894D E0            |mov     dword ptr [ebp-20], ecx0040D79C  |>  837D E0 03         |cmp     dword ptr [ebp-20], 30040D7A0  |.  7D 20              |jge     short 0040D7C20040D7A2  |.  8B55 E4            |mov     edx, dword ptr [ebp-1C]0040D7A5  |.  6BD2 0C            |imul    edx, edx, 0C0040D7A8  |.  8D4415 E8          |lea     eax, dword ptr [ebp+edx-18]0040D7AC  |.  8B4D E0            |mov     ecx, dword ptr [ebp-20]0040D7AF  |.  8B1488             |mov     edx, dword ptr [eax+ecx*4]0040D7B2  |.  52                 |push    edx                            ; /<%d>0040D7B3  |.  68 1C204200        |push    0042201C                       ; |format = "%d"0040D7B8  |.  E8 E338FFFF        |call    printf                         ; \printf0040D7BD  |.  83C4 08            |add     esp, 80040D7C0  |.^ EB D1              |jmp     short 0040D7930040D7C2  |>^ EB B7              |jmp     short 0040D77B

Switch

基本循环:

int main(int argc, char* argv[]){    int temp;    scanf("%d",&temp);    switch(temp)    {    case 0:        printf("case 0");break;    case 1:        printf("case 1");break;    case 2:        printf("case 2");break;    case 3:        printf("case 3");break;    default:        printf("none");break;    }    return 0;}

jmp dword ptr [edx*4+40FA6B] 跳转的地址.

0040F9F9  |.  8B4D FC       |mov     ecx, dword ptr [ebp-4]0040F9FC  |.  894D F8       |mov     dword ptr [ebp-8], ecx0040F9FF  |.  837D F8 03    |cmp     dword ptr [ebp-8], 30040FA03  |.  77 46         |ja      short 0040FA4B0040FA05  |.  8B55 F8       |mov     edx, dword ptr [ebp-8]0040FA08  |.  FF2495 6BFA40>|jmp     dword ptr [edx*4+40FA6B]0040FA0F  |>  68 18304200   |push    00423018                         ; /format = "case 0"0040FA14  |.  E8 8716FFFF   |call    printf                           ; \printf0040FA19  |.  83C4 04       |add     esp, 40040FA1C  |.  EB 3A         |jmp     short 0040FA580040FA1E  |>  68 10304200   |push    00423010                         ; /format = "case 1"0040FA23  |.  E8 7816FFFF   |call    printf                           ; \printf0040FA28  |.  83C4 04       |add     esp, 40040FA2B  |.  EB 2B         |jmp     short 0040FA580040FA2D  |>  68 08304200   |push    00423008                         ; /format = "case 2"0040FA32  |.  E8 6916FFFF   |call    printf                           ; \printf0040FA37  |.  83C4 04       |add     esp, 40040FA3A  |.  EB 1C         |jmp     short 0040FA580040FA3C  |>  68 00304200   |push    00423000                         ; /format = "case 3"0040FA41  |.  E8 5A16FFFF   |call    printf                           ; \printf0040FA46  |.  83C4 04       |add     esp, 40040FA49  |.  EB 0D         |jmp     short 0040FA580040FA4B  |>  68 F82F4200   |push    00422FF8                         ; /format = "none"0040FA50  |.  E8 4B16FFFF   |call    printf                           ; \printf0040FA55  |.  83C4 04       |add     esp, 4

变量作用域

全局变量:

具有初始值的全局变量,其值在链接时被写入所创建的PE文件中,PE文件首先会加载这些全局变量,所以这些变量可以不受作用域的影响,在程序中的任何位置都可以被访问。

int num1 = 1;int num2 = 2;int main(int argc, char* argv[]){    scanf("%d",&num1);    printf("%d",num1);    num2=10;    return 0;}
0040F9E8  |.  68 68514200   push    offset num10040F9ED  |.  68 F82F4200   push    00422FF8                         ; /format = "%d"0040F9F2  |.  E8 79FFFFFF   call    scanf                            ; \scanf0040F9F7  |.  83C4 08       add     esp, 80040F9FA  |.  A1 68514200   mov     eax, dword ptr [num1]0040F9FF  |.  50            push    eax                              ; /<%d> => 00040FA00  |.  68 F82F4200   push    00422FF8                         ; |format = "%d"0040FA05  |.  E8 9616FFFF   call    printf                           ; \printf0040FA0A  |.  83C4 08       add     esp, 80040FA0D  |.  C705 6C514200>mov     dword ptr [num2], 0A

局部变量:

局部变量的访问是通过栈指针相对间接访问,也就是说局部变量是程序动态创建的,局部变量作用域也仅限于函数内部,且其地址也是一个未知数,编译器无法预先计算。

int main(int argc, char* argv[]){    int num1=0;    int num2=1;    scanf("%d",&num1);    printf("%d",num1);    num2=10;    return 0;}
0040F9E8  |.  C745 FC 00000 |mov     dword ptr [ebp-4], 00040F9EF  |.  C745 F8 01000>|mov     dword ptr [ebp-8], 10040F9F6  |.  8D45 FC       |lea     eax, dword ptr [ebp-4]0040F9F9  |.  50            |push    eax0040F9FA  |.  68 F82F4200   |push    00422FF8                         ; /format = "%d"0040F9FF  |.  E8 6CFFFFFF   |call    scanf                            ; \scanf0040FA04  |.  83C4 08       |add     esp, 80040FA07  |.  8B4D FC       |mov     ecx, dword ptr [ebp-4]0040FA0A  |.  51            |push    ecx                              ; /<%d>0040FA0B  |.  68 F82F4200   |push    00422FF8                         ; |format = "%d"0040FA10  |.  E8 8B16FFFF   |call    printf                           ; \printf0040FA15  |.  83C4 08       |add     esp, 80040FA18  |.  C745 F8 0A000 |mov     dword ptr [ebp-8], 0A

堆变量:

#include 
int main(int argc, char* argv[]){ int *pMalloc = (int*) malloc(10); printf("%x",pMalloc); free(pMalloc); char *pChar = new char[10]; printf("%x",pChar); delete [] pChar; return 0;}
00401038  |.  6A 0A         push    0A                               ; /size = A (10.)0040103A  |.  E8 41350000   call    malloc                           ; \malloc0040103F  |.  83C4 04       add     esp, 400401042  |.  8945 FC       mov     dword ptr [ebp-4], eax00401045  |.  8B45 FC       mov     eax, dword ptr [ebp-4]00401048  |.  50            push    eax                              ; /<%x>00401049  |.  68 1C204200   push    0042201C                         ; |format = "%x"0040104E  |.  E8 7D000000   call    printf                           ; \printf00401053  |.  83C4 08       add     esp, 800401056  |.  8B4D FC       mov     ecx, dword ptr [ebp-4]00401059  |.  51            push    ecx                              ; /block0040105A  |.  E8 A13F0000   call    free                             ; \free

关于函数

无参函数:

void Print(){    ::MessageBox(NULL,TEXT("hello lyshark"),TEXT("MSG"),MB_OK);}int main(int argc, char* argv[]){    Print();    return 0;}

上方代码定义无参数传递的函数,观察反汇编代码,函数的开场白与收场白代码,VC6.0如下。

00401020 >  55              push    ebp00401021    8BEC            mov     ebp, esp00401023    83EC 40         sub     esp, 40........    .......         ................00401058    83C4 40         add     esp, 4000401062    8BE5            mov     esp, ebp00401064    5D              pop     ebp00401065    C3              retn

传递整数: 如下C代码,传递整数参数

int Print(int x,int y){    int sum;    sum=x+y;    return (sum);}int main(int argc, char* argv[]){    int sum;    sum = Print(10,20);    printf("%d \n",sum);    return 0;}

如下代码片段为,参数调用片段,可以看到在32位汇编中是通过堆栈传递参数的,参数传递是从后向前

00401068    6A 14           push    14            push 200040106A    6A 0A           push    0A            push 100040106C    E8 9EFFFFFF     call    0040100F

观察 print()函数汇编代码片段,通过ebp指针在堆栈中取出参数,然后进行相加运算,最后将返回值放到eax中。

00401020 >  55              push    ebp00401021    8BEC            mov     ebp, esp........00401038    8B45 08         mov     eax, dword ptr [ebp+8]0040103B    0345 0C         add     eax, dword ptr [ebp+C]0040103E    8945 FC         mov     dword ptr [ebp-4], eax00401041    8B45 FC         mov     eax, dword ptr [ebp-4]........00401047    8BE5            mov     esp, ebp00401049    5D              pop     ebp0040104A    C3              retn

传递数组:

void Print(int arr[], int size){  int i=0;  for (i=0; i

观察Print的参数传递,首先传递一个0A也就是10,然后传递数组指针,最后调用Print函数.

004010FE    6A 0A           push    0A00401100    8D45 D8         lea     eax, dword ptr [ebp-28]00401103    50              push    eax00401104    E8 FCFEFFFF     call    00401005
00401038    C745 FC 0000000>mov     dword ptr [ebp-4], 00040103F    C745 FC 0000000>mov     dword ptr [ebp-4], 000401046    EB 09           jmp     short 0040105100401048    8B45 FC         mov     eax, dword ptr [ebp-4]0040104B    83C0 01         add     eax, 10040104E    8945 FC         mov     dword ptr [ebp-4], eax00401051    8B4D FC         mov     ecx, dword ptr [ebp-4]00401054    3B4D 0C         cmp     ecx, dword ptr [ebp+C]00401057    7D 19           jge     short 0040107200401059    8B55 FC         mov     edx, dword ptr [ebp-4]0040105C    8B45 08         mov     eax, dword ptr [ebp+8]0040105F    8B0C90          mov     ecx, dword ptr [eax+edx*4]00401062    51              push    ecx00401063    68 1C204200     push    0042201C                         ; ASCII "%d \r"00401068    E8 D3000000     call    printf0040106D    83C4 08         add     esp, 800401070  ^ EB D6           jmp     short 00401048

传递指针:

void Print(char *str){    printf("%s\n",str);    str = "hello world";    printf("%s\n",str);}int main(int argc, char* argv[]){    char *str = "hello lyshark";    Print(str);    return 0;}

函数调用片段。

004010B8    C745 FC C02F4200   mov     dword ptr [ebp-4], 00422FC0      ; ASCII "hello lyshark"004010BF    8B45 FC            mov     eax, dword ptr [ebp-4]004010C2    50                 push    eax004010C3    E8 47FFFFFF        call    0040100F

函数内部调用。

00401038    8B45 08            mov     eax, dword ptr [ebp+8]0040103B    50                 push    eax0040103C    68 A42F4200        push    00422FA4                         ; ASCII "%s\n"00401041    E8 FA000000        call    printf00401046    83C4 08            add     esp, 8

返回指针:

int GetAddr(int number){    int nAddr;    nAddr = *(int*)(&number-1);    return nAddr;}int main(int argc, char* argv[]){    int address = 0;    address = GetAddr(100);    printf("%x\n",address);    return 0;}

首先是函数调用代码。

00401078    C745 FC 00000000   mov     dword ptr [ebp-4], 00040107F    6A 64              push    6400401081    E8 7FFFFFFF        call    0040100500401086    83C4 04            add     esp, 400401089    8945 FC            mov     dword ptr [ebp-4], eax

函数内部核心代码,ebp+8 = 64 ,区下面的地址。

00401038    8D45 08            lea     eax, dword ptr [ebp+8]0040103B    83E8 04            sub     eax, 40040103E    8B08               mov     ecx, dword ptr [eax]00401040    894D FC            mov     dword ptr [ebp-4], ecx00401043    8B45 FC            mov     eax, dword ptr [ebp-4]

返回结构:

struct tag{    int x;    int y;    char z;};tag RetStruct(){    tag temp;    temp.x = 10;    temp.y = 20;    temp.z = 'A';    return temp;}int main(int argc, char* argv[]){    tag temp;    temp = RetStruct();    printf("%d \n",temp.x);    printf("%d \n",temp.y);    printf("%d \n",temp.z);    return 0;}

观察一下结构的初始化

0040D778    C745 F4 0A000000   mov     dword ptr [ebp-C], 0A0040D77F    C745 F8 14000000   mov     dword ptr [ebp-8], 140040D786    C645 FC 41         mov     byte ptr [ebp-4], 410040D78A    8B45 08            mov     eax, dword ptr [ebp+8]0040D78D    8B4D F4            mov     ecx, dword ptr [ebp-C]0040D790    8908               mov     dword ptr [eax], ecx0040D792    8B55 F8            mov     edx, dword ptr [ebp-8]0040D795    8950 04            mov     dword ptr [eax+4], edx0040D798    8B4D FC            mov     ecx, dword ptr [ebp-4]0040D79B    8948 08            mov     dword ptr [eax+8], ecx0040D79E    8B45 08            mov     eax, dword ptr [ebp+8]
0040D7D4    8B08               mov     ecx, dword ptr [eax]0040D7D6    894D E8            mov     dword ptr [ebp-18], ecx0040D7D9    8B50 04            mov     edx, dword ptr [eax+4]0040D7DC    8955 EC            mov     dword ptr [ebp-14], edx0040D7DF    8B40 08            mov     eax, dword ptr [eax+8]0040D7E2    8945 F0            mov     dword ptr [ebp-10], eax0040D7E5    8B4D E8            mov     ecx, dword ptr [ebp-18]0040D7E8    894D F4            mov     dword ptr [ebp-C], ecx0040D7EB    8B55 EC            mov     edx, dword ptr [ebp-14]0040D7EE    8955 F8            mov     dword ptr [ebp-8], edx0040D7F1    8B45 F0            mov     eax, dword ptr [ebp-10]0040D7F4    8945 FC            mov     dword ptr [ebp-4], eax0040D7F7    8B4D F4            mov     ecx, dword ptr [ebp-C]0040D7FA    51                 push    ecx0040D7FB    68 A42F4200        push    00422FA4                         ; ASCII "%d \n"0040D800    E8 CB38FFFF        call    printf0040D805    83C4 08            add     esp, 80040D808    8B55 F8            mov     edx, dword ptr [ebp-8]0040D80B    52                 push    edx0040D80C    68 A42F4200        push    00422FA4                         ; ASCII "%d \n"0040D811    E8 BA38FFFF        call    printf0040D816    83C4 08            add     esp, 8

数组与指针

简单的数组: 一维数组的寻址方式。

int main(int argc ,char *argv[]){    int array[5] = { 1, 2, 3, 4, 5 };    int x;    for (x = 0; x < 5; x++){        printf("%d \n", array[x]);    }    return 0;}

其反汇编代码如下,其中数组的寻址方式使用了 [ebp+ecx*4-0x14] 比例因子寻址。

00401028  |.  C745 EC 01000>mov     dword ptr [ebp-0x14], 0x10040102F  |.  C745 F0 02000>mov     dword ptr [ebp-0x10], 0x200401036  |.  C745 F4 03000>mov     dword ptr [ebp-0xC], 0x30040103D  |.  C745 F8 04000>mov     dword ptr [ebp-0x8], 0x400401044  |.  C745 FC 05000>mov     dword ptr [ebp-0x4], 0x50040104B  |.  C745 E8 00000>mov     dword ptr [ebp-0x18], 0x000401052  |.  EB 09         jmp     short 0040105D00401054  |>  8B45 E8       /mov     eax, dword ptr [ebp-0x18]00401057  |.  83C0 01       |add     eax, 0x10040105A  |.  8945 E8       |mov     dword ptr [ebp-0x18], eax0040105D  |>  837D E8 05     cmp     dword ptr [ebp-0x18], 0x500401061  |.  7D 17         |jge     short 0040107A00401063  |.  8B4D E8       |mov     ecx, dword ptr [ebp-0x18]00401066  |.  8B548D EC     |mov     edx, dword ptr [ebp+ecx*4-0x14]0040106A  |.  52            |push    edx                                        ; /<%d>0040106B  |.  68 1C204200   |push    0042201C                                   ; |format = "%d "00401070  |.  E8 3B000000   |call    printf                                     ; \printf00401075  |.  83C4 08       |add     esp, 0x800401078  |.^ EB DA         \jmp     short 00401054

二维数组:

int main(int argc ,char *argv[]){    int array[2][3] ={
{1,2,3},{4,5,6}}; int x =0; int *Pointer = &array[0][0]; printf("Base: %x \n",Pointer); printf("%d\n",*(Pointer+2)); printf("%d\n",*(Pointer+4)); return 0;}

如下汇编代码就是二维数组的表现形式,可以看出二维数组的存储方式与一维相同.

00401028    C745 E8 0100000>mov     dword ptr [ebp-18], 10040102F    C745 EC 0200000>mov     dword ptr [ebp-14], 200401036    C745 F0 0300000>mov     dword ptr [ebp-10], 30040103D    C745 F4 0400000>mov     dword ptr [ebp-C], 400401044    C745 F8 0500000>mov     dword ptr [ebp-8], 50040104B    C745 FC 0600000>mov     dword ptr [ebp-4], 600401052    C745 E4 0000000>mov     dword ptr [ebp-1C], 000401059    8D45 E8         lea     eax, dword ptr [ebp-18]0040105C    8945 E0         mov     dword ptr [ebp-20], eax

寻址代码如下,其通过dword ptr [ebp-20]指向第1个元素,通过[edx+8]遍历第3个元素

00401070    8B55 E0         mov     edx, dword ptr [ebp-20] ;指向第1个元素前1个元素00401073    8B42 08         mov     eax, dword ptr [edx+8]  ;遍历第2个元素00401076    50              push    eax00401077    68 1C204200     push    0042201C0040107C    E8 5F000000     call    printf00401081    83C4 08         add     esp, 8

稍微修改下代码.

int main(int argc ,char *argv[]){    int array[2][3] ={
{1,2,3},{4,5,6}}; int x=0,y=1; array[x][y] = 0; return 0;}

在Debug模式下,其公式: 数组首地址 + sizeof(type[一维数组元素]) * x + sizeof(数据类型) * y

0040106E    8B45 E4                 mov     eax, dword ptr [ebp-1C]        ; eax = x 坐标00401071    6BC0 0C                 imul    eax, eax, 0C                   ; eax = x * 0c 索引数组00401074    8D4C05 E8               lea     ecx, dword ptr [ebp+eax-18]    ; ecx = y 坐标00401078    8B55 E0                 mov     edx, dword ptr [ebp-20]        ; edx = 10040107B    C70491 00000000         mov     dword ptr [ecx+edx*4], 0 ; 1+1*4=5 4字节中的5,指向第2个元素

上方汇编代码,解释:

1.第1条代码中的EAX是获取到的x的值,此处为C语言中的x=0.
2.第2条代码中的0C: 每个元素占4字节,而每个数组有3个元素,3x4=0C.
3.第3条代码中的ECX: 代表数组的y坐标.
4.第5条代码:ecx + edx * 4相当于数组首地址 + sizeof(int) * y.

三维数组:

int main(int argc, char* argv[]){    int Array[2][3][4] = {NULL};    int x = 0;    int y = 1;    int z = 2;    Array[x][y][z] = 3;    return 0;}

针对三维数组 int Array[M][C][H]其下标操作Array[x][y][z]=3数组寻址公式为:

Array + sizeof(type[C][H]) * x + sizeof(type[H])*y + sizeof(type)*z

00401056  |.  8B45 9C       mov     eax, dword ptr [ebp-64]      ; eax=x00401059  |.  6BC0 30       imul    eax, eax, 30                 ; sizeof(type[C][H])*x0040105C  |.  8D4C05 A0     lea     ecx, dword ptr [ebp+eax-60]  ; 00401060  |.  8B55 98       mov     edx, dword ptr [ebp-68]      ; Array[C]00401063  |.  C1E2 04       shl     edx, 400401066  |.  03CA          add     ecx, edx00401068  |.  8B45 94       mov     eax, dword ptr [ebp-6C]      ; Array[Z]0040106B  |.  C70481 030000>mov     dword ptr [ecx+eax*4], 3

上方汇编代码,解释:

1.第1条指令中得出eax=x的值.
2.第2条指令eax * 30,相当于求出sizeof(type[C][H]) * x
3.第3条指令求出数组首地址+eax-60也就求出Array[M]位置,并取地址放入ECX
4.第4条指令:[ebp-68]存放Y的值,此处就是求出y的值
5.第5条指令:左移4位,相当于2^4次方也就是16这一步相当于求sizeof(type[H])的值
6.Array[M] + sizeof(type[H])的值求出Array[M][C]的值

存放指针类型数据的数组: 数组中各数据元素都是由相同类型的指针组成,我们就称之为指针数组.

指针数组主要用于管理同种类型的指针,一般用于处理若干个字符串的操作,使用指针数组处理多字符串更加的方便,简洁,高效,需要注意的是,虽然同属于数组但是指针数组,但与常规的数组还有所差别,指针数组中的数据为地址类型,寻址时需要再次进行间接访问才能够获取到真正的数据,这也是他们之间最大的不同.

int main(int argc, char* argv[]){    char *pBuffer[3] = {        "hello ",        "lyshark ",        "!\r\n"    };    for (int x = 0; x < 3; x++){        printf(pBuffer[x]);    }    return 0;}

上方的代码经过编译后,我们定位到字符串初始化的位置,发现字符串数组中只向数组的第1个成员赋值字符串的首地址.

00401028  |.  C745 F4 2C204200    mov     dword ptr [ebp-C], 0042202C      ; ASCII "hello "0040102F  |.  C745 F8 20204200    mov     dword ptr [ebp-8], 00422020      ; ASCII "lyshark "00401036  |.  C745 FC 1C204200    mov     dword ptr [ebp-4], 0042201C      ; ASCII "!\r\n"

如下片段代码就是打印环节了,由于指针数组本质上也是数组,故寻址方式与我们的数组基本相同.

0040103D  |.  C745 F0 00000000    |mov     dword ptr [ebp-10], 0            ; x=000401044  |.  EB 09               |jmp     short 0040104F00401046  |>  8B45 F0             |mov     eax, dword ptr [ebp-10]          ; 取出x00401049  |.  83C0 01             |add     eax, 1                           ; 递增10040104C  |.  8945 F0             |mov     dword ptr [ebp-10], eax0040104F  |>  837D F0 03          |cmp     dword ptr [ebp-10], 3            ; 与3作比较00401053  |.  7D 12               |jge     short 0040106700401055  |.  8B4D F0             |mov     ecx, dword ptr [ebp-10]          ; 取出下标值00401058  |.  8B548D F4           |mov     edx, dword ptr [ebp+ecx*4-C]     ; 定位字符串首地址0040105C  |.  52                  |push    edx                              ; format0040105D  |.  E8 3E000000         |call    printf                           ; printf00401062  |.  83C4 04             |add     esp, 400401065  |.^ EB DF               |jmp     short 00401046

上方代码定义了1维字符串数组,该数组由3个指针变量组成,故长度为12字节,数组所指向的字符串长度与数组本身没有关系,而2维数组则与之不同,我们接着将上方代码稍加修改:

int main(int argc, char* argv[]){    char cArray[2][10] = {        {"hello"},        {"lyshark"}    };    for(int x=0;x<2;x++)    {        printf(cArray[x]);    }    return 0;}

以下反汇编代码可看出,2维字符数组初始化过程中,赋值的不是字符串地址,而是其中的字符数据,据此可以明显的区分它与字符指针数组的区别.

00401057  |.  C745 E8 00000000    |mov     dword ptr [ebp-18], 00040105E  |.  EB 09               |jmp     short 0040106900401060  |>  8B45 E8             |mov     eax, dword ptr [ebp-18]00401063  |.  83C0 01             |add     eax, 100401066  |.  8945 E8             |mov     dword ptr [ebp-18], eax00401069  |>  837D E8 02          |cmp     dword ptr [ebp-18], 20040106D  |.  7D 15               |jge     short 004010840040106F  |.  8B4D E8             |mov     ecx, dword ptr [ebp-18]00401072  |.  6BC9 0A             |imul    ecx, ecx, 0A                    ; 遍历数组每次递增1000401075  |.  8D540D EC           |lea     edx, dword ptr [ebp+ecx-14]     ; 取出1维数组首地址00401079  |.  52                  |push    edx                             ; format = "hello"0040107A  |.  E8 21000000         |call    printf                          ; printf0040107F  |.  83C4 04             |add     esp, 400401082  |.^ EB DC               |jmp     short 00401060

总结:字符指针数组寻址后,得到的是数组成员内容,而2维字符数组寻址后,得到的却是数组中某个1维数组的首地址.

指向数组的指针变量: 当指针变量保存的数据为数组的首地址,且将此地址解释为数组时,此指针变量被称为数组指针.

如下我们定义了指向数组的指针为char (*pArray)[10]=Array,并通过循环遍历指针中的数据.

int main(int argc, char* argv[]){    char Array[3][10] = { "hello","lyshark","! \r\n" };    char (*pArray)[10] = Array;    for(int x=0;x<3;x++)    {        printf(*pArray);        pArray++;       }    return 0;}

反汇编代码如下,程序通过lea eax, dword ptr [ebp-20]遍历数组元素,指针[ebp-24]每次递增10,递增10是因为char类型为1个字节,而1维数组为10所以递增为10,如果为整数类型就需要递增4*10

0040D790  |.  8D45 E0             |lea     eax, dword ptr [ebp-20]     ; 取打印元素0040D793  |.  8945 DC             |mov     dword ptr [ebp-24], eax0040D796  |.  C745 D8 00000000    |mov     dword ptr [ebp-28], 0       ; 初始化x=00040D79D  |.  EB 09               |jmp     short 0040D7A80040D79F  |>  8B4D D8             |mov     ecx, dword ptr [ebp-28]0040D7A2  |.  83C1 01             |add     ecx, 1                      ; x每次递增0040D7A5  |.  894D D8             |mov     dword ptr [ebp-28], ecx0040D7A8  |>  837D D8 03          |cmp     dword ptr [ebp-28], 30040D7AC  |.  7D 17               |jge     short 0040D7C50040D7AE  |.  8B55 DC             |mov     edx, dword ptr [ebp-24]0040D7B1  |.  52                  |push    edx                         ; format0040D7B2  |.  E8 E938FFFF         |call    printf                      ; printf0040D7B7  |.  83C4 04             |add     esp, 40040D7BA  |.  8B45 DC             |mov     eax, dword ptr [ebp-24]0040D7BD  |.  83C0 0A             |add     eax, 0A                     ; 指针递增100040D7C0  |.  8945 DC             |mov     dword ptr [ebp-24], eax0040D7C3  |.^ EB DA               |jmp     short 0040D79F

指向函数的指针: 程序通过CALL指令跳转到函数首地址执行代码,既然是地址那就可以使用指针变量来存储函数的首地址,该指针变量被乘坐函数指针.

void __stdcall Show(){    printf("hello lyshark\n");}int main(int argc, char* argv[]){    void (__stdcall *pShow)(void) = Show;    pShow();    Show();    return 0;}

函数指针的类型由返回值,参数信息,调用约定组成,它决定了函数指针在函数调用过程中参数的传递,返回,以及如何堆栈平衡等,上方的代码中__stdcall就是VC编译器中的默认平栈方式,这里也可以省略.

0040D788  |.  C745 FC 0F104000    mov     dword ptr [ebp-4], 0040100F      ; 入口地址0040D78F  |.  8B45 FC             mov     eax, dword ptr [ebp-4]0040D792  |.  8945 FC             mov     dword ptr [ebp-4], eax0040D795  |.  8BF4                mov     esi, esp0040D797  |.  FF55 FC             call    dword ptr [ebp-4]                ; 间接调用函数0040D79A  |.  3BF4                cmp     esi, esp                         ; 检查栈平衡0040D79C  |.  E8 7F39FFFF         call    _chkesp0040D7A1  |.  E8 6938FFFF         call    0040100F                         ; 直接调用函数0040D7A6  |.  33C0                xor     eax, eax

如上代码清单,演示了函数指针的赋值和调用过程,与函数调用最大的区别在于函数是直接调用,而函数指针的调用需要取出指针变量中保存的地址,然后进行call dword ptr [ebp-4]间接的调用,将C代码稍作修改.

int __stdcall Show(int nShow){    printf("hello %d\n",nShow);    return nShow;}int main(int argc, char* argv[]){    int (__stdcall *pShow)(int) = Show;        int Ret = pShow(10);    printf("Ret = %d \n",Ret);    return 0;}

如下反汇编代码,代码中的函数指针调用只是多了参数的传递,返回值的接收,其他地方没有太大变化,都是间接调用函数.

0040D788  |.  C745 FC 14104000    mov     dword ptr [ebp-4], 004010140040D78F  |.  8B45 FC             mov     eax, dword ptr [ebp-4]0040D792  |.  8945 FC             mov     dword ptr [ebp-4], eax0040D795  |.  8BF4                mov     esi, esp          ; 保存进入函数前的堆栈,用于检查0040D797  |.  6A 0A               push    0A                               ; 传递参数0040D799  |.  FF55 FC             call    dword ptr [ebp-4] ; 获取函数指针中的地址,间接调用函数0040D79C  |.  3BF4                cmp     esi, esp0040D79E  |.  E8 7D39FFFF         call    _chkesp0040D7A3  |.  8945 F8             mov     dword ptr [ebp-8], eax  ; 接收函数返回数据0040D7A6  |.  8B4D F8             mov     ecx, dword ptr [ebp-8]0040D7A9  |.  51                  push    ecx                              ; <%d>0040D7AA  |.  68 1C204200         push    0042201C                         ; format = "Re =%d"0040D7AF  |.  E8 EC38FFFF         call    printf                           ; printf0040D7B4  |.  83C4 08             add     esp, 8

未完待续............................

结构与联合体

转载于:https://www.cnblogs.com/LyShark/p/11528801.html

你可能感兴趣的文章
惯例优于配置原则(学习笔记)
查看>>
蓝桥杯- 奇妙的数字-java
查看>>
Speex manul中文版
查看>>
【原】移动web点5像素的秘密
查看>>
【原】js数组对象去重最简单的方法
查看>>
织梦文章内容页如何调用点击数
查看>>
Ubuntu修改apt-get源
查看>>
Day Three(Beta)
查看>>
selenium alert JS弹窗问题处理
查看>>
Cocos2d-x-2.2.2开发环境配置
查看>>
Windows 窗体控件中的多线程处理之:如何使用后台线程搜索文件
查看>>
java框架---->quartz的使用(一)
查看>>
【Java每日一题】20170316
查看>>
day22-python之模块
查看>>
[Swift]LeetCode200.岛屿的个数 | Number of Islands
查看>>
selenium学习笔记(xpath和css定位)
查看>>
(转)30 IMP-00019: row rejected due to ORACLE error 12899
查看>>
[Algorithm] Dynamic programming: Find Sets Of Numbers That Add Up To 16
查看>>
[Mockito] Mock List interface
查看>>
[React Native] Reusable components with required propType
查看>>