C语言三大结构的反汇编学习

源代码:


#include "stdafx.h"


void test1(){}
void test2(int a,int b) {}
void test3() {
    int a = 100;
    int b = a + 50;
}

void  test4(int a, int b) {
    int c = a + b;
    int d = a*b;

}

int main()
{
    char *p1 = "没有任何参数的空函数";//定义一个字符串,在OD 里面容易定位 
    test1();
    char *p2 = "有形参的空函数";
    test2(1, 2);
    char *p3 = "没有参数但是有局部变量";
    test3();
    char *p4 = "有参数并且有局部变量";
    test4(1,2);

    return 0;
}
test1:

002C16A0 >  55              PUSH EBP
002C16A1    8BEC            MOV EBP,ESP
002C16A3    81EC C0000000   SUB ESP,0xC0//前三行开辟栈帧
002C16A9    53              PUSH EBX
002C16AA    56              PUSH ESI
002C16AB    57              PUSH EDI     //保存临时变量
002C16AC    8DBD 40FFFFFF   LEA EDI,DWORD PTR SS:[EBP-0xC0]//将EBP-0xC0中的值保存于edi中
002C16B2    B9 30000000     MOV ECX,0x30//计数器循环30002C16B7    B8 CCCCCCCC     MOV EAX,0xCCCCCCCC
002C16BC    F3:AB           REP STOS DWORD PTR ES:[EDI]//将eax中的值传入edi之中,循环30002C16BE    5F              POP EDI
002C16BF    5E              POP ESI
002C16C0    5B              POP EBX
002C16C1    8BE5            MOV ESP,EBP
002C16C3    5D              POP EBP//回收栈帧
002C16C4    C3              RETN//返回

test2:(和test1一摸一样,唯一的区别就是在call上面压入了两个参数)
002C17BE    C745 F8 306B2C0>MOV DWORD PTR SS:[EBP-0x8],空函数.002C6B30
002C17C5    E8 7BF9FFFF     CALL 空函数.002C1145                                    ; test1
002C17CA    C745 EC 4C6B2C0>MOV DWORD PTR SS:[EBP-0x14],空函数.002C6B4C
002C17D1    6A 02           PUSH 0x2
002C17D3    6A 01           PUSH 0x1
002C17D5    E8 23FBFFFF     CALL 空函数.002C12FD                                    ; test2

002C16D0 >  55              PUSH EBP
002C16D1    8BEC            MOV EBP,ESP
002C16D3    81EC C0000000   SUB ESP,0xC0
002C16D9    53              PUSH EBX
002C16DA    56              PUSH ESI
002C16DB    57              PUSH EDI
002C16DC    8DBD 40FFFFFF   LEA EDI,DWORD PTR SS:[EBP-0xC0]
002C16E2    B9 30000000     MOV ECX,0x30
002C16E7    B8 CCCCCCCC     MOV EAX,0xCCCCCCCC
002C16EC    F3:AB           REP STOS DWORD PTR ES:[EDI]
002C16EE    5F              POP EDI
002C16EF    5E              POP ESI
002C16F0    5B              POP EBX
002C16F1    8BE5            MOV ESP,EBP
002C16F3    5D              POP EBP

test3:
002C1700 >  55              PUSH EBP
002C1701    8BEC            MOV EBP,ESP
002C1703    81EC D8000000   SUB ESP,0xD8
002C1709    53              PUSH EBX
002C170A    56              PUSH ESI
002C170B    57              PUSH EDI
002C170C    8DBD 28FFFFFF   LEA EDI,DWORD PTR SS:[EBP-0xD8]
002C1712    B9 36000000     MOV ECX,0x36
002C1717    B8 CCCCCCCC     MOV EAX,0xCCCCCCCC
002C171C    F3:AB           REP STOS DWORD PTR ES:[EDI]
002C171E    C745 F8 6400000>MOV DWORD PTR SS:[EBP-0x8],0x64//局部变量a赋值100
002C1725    8B45 F8         MOV EAX,DWORD PTR SS:[EBP-0x8]
002C1728    83C0 32         ADD EAX,0x32
002C172B    8945 EC         MOV DWORD PTR SS:[EBP-0x14],EAX//局部变量b,b=a+50
002C172E    5F              POP EDI
002C172F    5E              POP ESI
002C1730    5B              POP EBX
002C1731    8BE5            MOV ESP,EBP
002C1733    5D              POP EBP
002C1734    C3              RETN

test4:
002C17F0    6A 02           PUSH 0x2
002C17F2    6A 01           PUSH 0x1
002C17F4    E8 D2FAFFFF     CALL 空函数.002C12CB                                    ; test4
002C17F9    83C4 08         ADD ESP,0x8


002C1750 >  55              PUSH EBP
002C1751    8BEC            MOV EBP,ESP
002C1753    81EC D8000000   SUB ESP,0xD8
002C1759    53              PUSH EBX
002C175A    56              PUSH ESI
002C175B    57              PUSH EDI
002C175C    8DBD 28FFFFFF   LEA EDI,DWORD PTR SS:[EBP-0xD8]
002C1762    B9 36000000     MOV ECX,0x36
002C1767    B8 CCCCCCCC     MOV EAX,0xCCCCCCCC
002C176C    F3:AB           REP STOS DWORD PTR ES:[EDI]
002C176E    8B45 08         MOV EAX,DWORD PTR SS:[EBP+0x8]//将参数a赋值给eax
002C1771    0345 0C         ADD EAX,DWORD PTR SS:[EBP+0xC]//将参数a与参数b相加赋值给eax,参数a,b为函数定义中的形参
002C1774    8945 F8         MOV DWORD PTR SS:[EBP-0x8],EAX//将a于b之和赋值给局部变量c
002C1777    8B45 08         MOV EAX,DWORD PTR SS:[EBP+0x8]//参数a赋值给eax
002C177A    0FAF45 0C       IMUL EAX,DWORD PTR SS:[EBP+0xC]//参数a于参数b相乘赋值给eax
002C177E    8945 EC         MOV DWORD PTR SS:[EBP-0x14],EAX//将a与b之积赋值给局部变量d,注意:局部变量的地址没有规定是可以在开辟的栈帧内随便定义的!!!
002C1781    5F              POP EDI
002C1782    5E              POP ESI
002C1783    5B              POP EBX
002C1784    8BE5            MOV ESP,EBP
002C1786    5D              POP EBP
002C1787    C3              RETN

for循环:
#include "stdafx.h"


int main()
{
    int num = 0; //局部变量num
    char *p1 = "这是第一个循环";
    for (int i = 0; i < 10; i++)
    {
    }
    char *p2 = "这是第二个循环";
    for (;;)
    {
    }
    char *p3 = "这是第三个循环";
    for (int i = 0; i < 10; i++)
    {
        num++;
    }
    return 0;

}
主函数:
00311650 >  55              PUSH EBP
00311651    8BEC            MOV EBP,ESP
00311653    81EC 08010000   SUB ESP,0x108
00311659    53              PUSH EBX
0031165A    56              PUSH ESI
0031165B    57              PUSH EDI
0031165C    8DBD F8FEFFFF   LEA EDI,DWORD PTR SS:[EBP-0x108]
00311662    B9 42000000     MOV ECX,0x42
00311667    B8 CCCCCCCC     MOV EAX,0xCCCCCCCC
0031166C    F3:AB           REP STOS DWORD PTR ES:[EDI]
0031166E    C745 F8 0000000>MOV DWORD PTR SS:[EBP-0x8],0x0
00311675    C745 EC 306B310>MOV DWORD PTR SS:[EBP-0x14],for循环.00316B30
0031167C    C745 E0 0000000>MOV DWORD PTR SS:[EBP-0x20],0x0
00311683    EB 09           JMP SHORT for循环.0031168E
00311685    8B45 E0         MOV EAX,DWORD PTR SS:[EBP-0x20]
00311688    83C0 01         ADD EAX,0x1
0031168B    8945 E0         MOV DWORD PTR SS:[EBP-0x20],EAX
0031168E    837D E0 0A      CMP DWORD PTR SS:[EBP-0x20],0xA
00311692    7D 02           JGE SHORT for循环.00311696
00311694  ^ EB EF           JMP SHORT for循环.00311685
00311696    C745 D4 446B310>MOV DWORD PTR SS:[EBP-0x2C],for循环.00316B44
0031169D  - EB FE           JMP SHORT for循环.0031169D
0031169F    C745 C8 586B310>MOV DWORD PTR SS:[EBP-0x38],for循环.00316B58
003116A6    C745 BC 0000000>MOV DWORD PTR SS:[EBP-0x44],0x0
003116AD    EB 09           JMP SHORT for循环.003116B8
003116AF    8B45 BC         MOV EAX,DWORD PTR SS:[EBP-0x44]
003116B2    83C0 01         ADD EAX,0x1
003116B5    8945 BC         MOV DWORD PTR SS:[EBP-0x44],EAX
003116B8    837D BC 0A      CMP DWORD PTR SS:[EBP-0x44],0xA
003116BC    7D 0B           JGE SHORT for循环.003116C9
003116BE    8B45 F8         MOV EAX,DWORD PTR SS:[EBP-0x8]
003116C1    83C0 01         ADD EAX,0x1
003116C4    8945 F8         MOV DWORD PTR SS:[EBP-0x8],EAX
003116C7  ^ EB E6           JMP SHORT for循环.003116AF
003116C9    33C0            XOR EAX,EAX
003116CB    5F              POP EDI
003116CC    5E              POP ESI
003116CD    5B              POP EBX
003116CE    8BE5            MOV ESP,EBP
003116D0    5D              POP EBP
003116D1    C3              RETN

第一个for循环:
0031166E    C745 F8 0000000>MOV DWORD PTR SS:[EBP-0x8],0x0
00311675    C745 EC 306B310>MOV DWORD PTR SS:[EBP-0x14],for循环.00316B30
0031167C    C745 E0 0000000>MOV DWORD PTR SS:[EBP-0x20],0x0//i = 0;
00311683    EB 09           JMP SHORT for循环.0031168E//跳转到i的检测条件,即i<10,汇编里面是将i与10做比较
00311685    8B45 E0         MOV EAX,DWORD PTR SS:[EBP-0x20]//将i赋值给eax
00311688    83C0 01         ADD EAX,0x1//i++,i自增1
0031168B    8945 E0         MOV DWORD PTR SS:[EBP-0x20],EAX//将i+1之后的值再次赋值给i,实现了i++的功能
0031168E    837D E0 0A      CMP DWORD PTR SS:[EBP-0x20],0xA//上面的jmp跳转至此处,检测条件为:将i和10进行比较
00311692    7D 02           JGE SHORT for循环.00311696//如果i大于10就会跳出此循环
00311694    EB EF           JMP SHORT for循环.00311685//跳转至上面的地址继续执行循环

小结:
  • 三个jmp,下面最后一个jmp跳往最上面一个jmp的后面,即:三个jmp,最后一个jmp跳往第一个jmp的后面一句,
(jmp+cmp,条件跳+jmp往上跳)
第二个for循环:
0031169D  - EB FE           JMP SHORT for循环.0031169D//死循环,一直在本地址跳转

第三个for循环:
003116A6    C745 BC 0000000 MOV DWORD PTR SS:[EBP-0x44],0x0//i=0;
003116AD    EB 09           JMP SHORT for循环.003116B8//跳到条件检查,同上面第一个for循环
003116AF    8B45 BC         MOV EAX,DWORD PTR SS:[EBP-0x44]//将i值赋给eax
003116B2    83C0 01         ADD EAX,0x1//i++
003116B5    8945 BC         MOV DWORD PTR SS:[EBP-0x44],EAX//将i++后的值再次赋值给i,实现了i++
003116B8    837D BC 0A      CMP DWORD PTR SS:[EBP-0x44],0xA//比较的条件
003116BC    7D 0B           JGE SHORT for循环.003116C9//大于等于则直接跳出循环
003116BE    8B45 F8         MOV EAX,DWORD PTR SS:[EBP-0x8]//num的值赋值给eax
003116C1    83C0 01         ADD EAX,0x1//num++
003116C4    8945 F8         MOV DWORD PTR SS:[EBP-0x8],EAX//实现了num++
003116C7    EB E6           JMP SHORT for循环.003116AF//跳到上面的地址继续执行循环体
总结:大体上逻辑与第一个for循环的逻辑一致,不过是多了num++的三句汇编
小结:
  • 三个jmp,最后一个jmp跳往第一个jmp的后面一句,
(jmp+cmp,条件跳+jmp往上跳)
while循环
#include "stdafx.h"


int main()
{

    int i = 0;
    int sum = 0;
    char*p = "这是while循环";
    while (i < 10) {
        sum += i;
    }
    char*p2 = "这是do while循环";
    i = 0;
    sum = 0;
    do {
        sum += i;
    } while (i < 10);
    return 0;
}

OD中对应汇编:

01041650 >  55              PUSH EBP
01041651    8BEC            MOV EBP,ESP
01041653    81EC F0000000   SUB ESP,0xF0
01041659    53              PUSH EBX
0104165A    56              PUSH ESI
0104165B    57              PUSH EDI
0104165C    8DBD 10FFFFFF   LEA EDI,DWORD PTR SS:[EBP-0xF0]
01041662    B9 3C000000     MOV ECX,0x3C
01041667    B8 CCCCCCCC     MOV EAX,0xCCCCCCCC
0104166C    F3:AB           REP STOS DWORD PTR ES:[EDI]
0104166E    C745 F8 0000000>MOV DWORD PTR SS:[EBP-0x8],0x0
01041675    C745 EC 0000000>MOV DWORD PTR SS:[EBP-0x14],0x0
0104167C    C745 E0 CC6C040>MOV DWORD PTR SS:[EBP-0x20],while.01046CCC                              ; ASCII "这是while循环"
01041683    837D F8 0A      CMP DWORD PTR SS:[EBP-0x8],0xA
01041687    7D 0B           JGE SHORT while.01041694
01041689    8B45 EC         MOV EAX,DWORD PTR SS:[EBP-0x14]
0104168C    0345 F8         ADD EAX,DWORD PTR SS:[EBP-0x8]
0104168F    8945 EC         MOV DWORD PTR SS:[EBP-0x14],EAX
01041692  ^ EB EF           JMP SHORT while.01041683
01041694    C745 D4 306B040>MOV DWORD PTR SS:[EBP-0x2C],while.01046B30
0104169B    C745 F8 0000000>MOV DWORD PTR SS:[EBP-0x8],0x0
010416A2    C745 EC 0000000>MOV DWORD PTR SS:[EBP-0x14],0x0
010416A9    8B45 EC         MOV EAX,DWORD PTR SS:[EBP-0x14]
010416AC    0345 F8         ADD EAX,DWORD PTR SS:[EBP-0x8]
010416AF    8945 EC         MOV DWORD PTR SS:[EBP-0x14],EAX
010416B2    837D F8 0A      CMP DWORD PTR SS:[EBP-0x8],0xA
010416B6  ^ 7C F1           JL SHORT while.010416A9
010416B8    33C0            XOR EAX,EAX
010416BA    5F              POP EDI
010416BB    5E              POP ESI
010416BC    5B              POP EBX
010416BD    8BE5            MOV ESP,EBP
010416BF    5D              POP EBP
010416C0    C3              RETN
while反汇编:
0104166E    C745 F8 00000000                     MOV DWORD PTR SS:[EBP-0x8],0x0//i=0;
01041675    C745 EC 00000000                     MOV DWORD PTR SS:[EBP-0x14],0x0//sum=0
0104167C    C745 E0 CC6C0401                     MOV DWORD PTR SS:[EBP-0x20],while.01046CCC            ; //字符串,ASCII "这是while循环"
01041683    837D F8 0A                           CMP DWORD PTR SS:[EBP-0x8],0xA//判断条件,i和10比较
01041687    7D 0B                                JGE SHORT while.01041694   //如果i>=10,跳出循环
01041689    8B45 EC                              MOV EAX,DWORD PTR SS:[EBP-0x14]//sum=eax
0104168C    0345 F8                              ADD EAX,DWORD PTR SS:[EBP-0x8]//sum+i
0104168F    8945 EC                              MOV DWORD PTR SS:[EBP-0x14],EAX//sum=sum+i
01041692  ^ EB EF                                JMP SHORT while.01041683//跳转至判断条件处

do while反汇编代码:
0104169B    C745 F8 00000000                     MOV DWORD PTR SS:[EBP-0x8],0x0//i=0
010416A2    C745 EC 00000000                     MOV DWORD PTR SS:[EBP-0x14],0x0//sum=0
010416A9    8B45 EC                              MOV EAX,DWORD PTR SS:[EBP-0x14]
010416AC    0345 F8                              ADD EAX,DWORD PTR SS:[EBP-0x8]
010416AF    8945 EC                              MOV DWORD PTR SS:[EBP-0x14],EAX
010416B2    837D F8 0A                           CMP DWORD PTR SS:[EBP-0x8],0xA//先执行函数体,然后再判断条件
010416B6    7C F1                                JL SHORT while.010416A9
while总结:
  • while是判断条件不符合,直接跳转到循环外面,否则就一直执行循环体 (while和for循环有点类似),cmp+2个jmp,
while:cmp+条件跳+jmp往上跳
  • do while 是先执行函数体,然后再判断,cmp+条件跳(往上跳)
if语句
#include "stdafx.h"
int main()
{

    int num = 10;
    if (num == 10)
    {
        num = 20;
    }
    else if (num == 20)
    {
        num = 30;
    }
    num = 2;
    if (num == 0)
    {
        num++;

    }
    if (num == 2)
    {
        num++;

    }
    return 0;
}
00241675    837D F8 0A                           CMP DWORD PTR SS:[EBP-0x8],0xA//num和10比较
00241679    75 09                                JNZ SHORT if语句.00241684//如果不为10,就跳转至else if处,为10就不跳
0024167B    C745 F8 14000000                     MOV DWORD PTR SS:[EBP-0x8],0x14//num=20
00241682    EB 0D                                JMP SHORT if语句.00241691//跳走至00241691
00241684    837D F8 14                           CMP DWORD PTR SS:[EBP-0x8],0x14//和20比较
00241688    75 07                                JNZ SHORT if语句.00241691//如果不为20,就跳至00241691

第二个if语句:

00241698    837D F8 00                           CMP DWORD PTR SS:[EBP-0x8],0x0//num和0比较
0024169C    75 09                                JNZ SHORT if语句.002416A7//如果为0就不跳转,否则跳转至下个判断句
0024169E    8B45 F8                              MOV EAX,DWORD PTR SS:[EBP-0x8]
002416A1    83C0 01                              ADD EAX,0x1//num++
002416A4    8945 F8                              MOV DWORD PTR SS:[EBP-0x8],EAX
002416A7    837D F8 02                           CMP DWORD PTR SS:[EBP-0x8],0x2//num和2比较
002416AB    75 09                                JNZ SHORT if语句.002416B6//如果不是2,则直接跳转,否则直接运行代码
002416AD    8B45 F8                              MOV EAX,DWORD PTR SS:[EBP-0x8]
002416B0    83C0 01                              ADD EAX,0x1//num++
002416B3    8945 F8                              MOV DWORD PTR SS:[EBP-0x8],EAX

if语句总结:
  • if…else if… 会出现多个JMP跳到判断外的同一个地址,
  • if…if…. 跳转到的地方不一样,第一个会跳到的地方与第二个跳到的地方不一样。中间没有JMP跳转。
switch语句
int main()
{
    int num = 10;
    switch (num)
    {
    case 1:  num = 1; break;
    case 2:  num = 2; break;
    case 4:  num = 4; break;
    case 5:  num = 5; break;
    case 6:
    case 7:  num = 7; break;
    default: num = 0; break;
    }
    return 0;
}
0035166E    C745 F8 0A000000                     MOV DWORD PTR SS:[EBP-0x8],0xA//num=10
00351675    8B45 F8                              MOV EAX,DWORD PTR SS:[EBP-0x8]
00351678    8985 30FFFFFF                        MOV DWORD PTR SS:[EBP-0xD0],EAX//将num的值放在ebp-0xd00035167E    8B8D 30FFFFFF                        MOV ECX,DWORD PTR SS:[EBP-0xD0]
00351684    83E9 01                              SUB ECX,0x1//将num-1=9
00351687    898D 30FFFFFF                        MOV DWORD PTR SS:[EBP-0xD0],ECX
0035168D    83BD 30FFFFFF 06                     CMP DWORD PTR SS:[EBP-0xD0],0x6//将num-1=96做比较
00351694    77 3A                                JA SHORT switch.003516D0//如果大于6  直接跳到 num= 0 处 也就是 default处
00351696    8B95 30FFFFFF                        MOV EDX,DWORD PTR SS:[EBP-0xD0]
0035169C    FF2495 E0163500                      JMP DWORD PTR DS:[EDX*4+0x3516E0]//这个地方非常巧妙 0x3516E0位置是跳转表的地址   前面edx*4 代表索引   因为每个地址占4字节  因此每次增加4
$LN6:
003516A3    C745 F8 01000000                     MOV DWORD PTR SS:[EBP-0x8],0x1//num=1
003516AA    EB 2B                                JMP SHORT switch.003516D7//break
003516AC    C745 F8 02000000                     MOV DWORD PTR SS:[EBP-0x8],0x2//num=2
003516B3    EB 22                                JMP SHORT switch.003516D7//break
003516B5    C745 F8 04000000                     MOV DWORD PTR SS:[EBP-0x8],0x4//num=4
003516BC    EB 19                                JMP SHORT switch.003516D7//break
003516BE    C745 F8 05000000                     MOV DWORD PTR SS:[EBP-0x8],0x5//num=5
003516C5    EB 10                                JMP SHORT switch.003516D7//break
003516C7    C745 F8 07000000                     MOV DWORD PTR SS:[EBP-0x8],0x7//num=7
003516CE    EB 07                                JMP SHORT switch.003516D7//break
003516D0    C745 F8 00000000                     MOV DWORD PTR SS:[EBP-0x8],0x0
003516D7    33C0                                 XOR EAX,EAX
003516D9    5F                                   POP EDI
003516DA    5E                                   POP ESI
003516DB    5B                                   POP EBX
003516DC    8BE5                                 MOV ESP,EBP
003516DE    5D                                   POP EBP
003516DF    C3                                   RETN


总结:

如果出现多次JMP跳到同一个位置,可以初步判断就是switch
另外 跳转表这个位置是数据,不是代码 如果出现* jmp dword ptr [edx*4+ 0x3516E0]* 这样的代码,那就是switch。

另外,如果case分支非常少,编译器会将其优化成if…else if… 代码一模一样。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值