C语言反汇编代码(三大结构)

时间:2021-01-14 01:22:00

空函数

#include <stdio.h>

void Test1(){}  
void Test2(int a, int b){}
void Test3()
{
    int a = 10;
    int b = a + 20;
}
void Test4(int a, int b)
{
    int c = a + b;
}
int main()
{
    char *p1 = "无参数空函数!";//定义一个字符串 在OD中容易定位
    Test1();
    char *p2 = "有参数空函数!";//定义一个字符串 在OD中容易定位
    Test2(1,2);
    char *p3 = "无参数有局部变量函数!";//定义一个字符串 在OD中容易定位
    Test3();
    char *p4 = "有参数有局部变量函数!";//定义一个字符串 在OD中容易定位
    Test4(1,2);

    return 0;
}

在vs中反汇编代码如下:
Test1:

Test1:
00AE13D0 55                   push        ebp      ;保存ebp寄存器
00AE13D1 8B EC                mov         ebp,esp    
00AE13D3 81 EC C0 00 00 00    sub         esp,0C0h  ;设置栈帧 
00AE13D9 53                   push        ebx   ;保存ebx
00AE13DA 56                   push        esi   ;保存esi
00AE13DB 57                   push        edi   ;保存edi 
00AE13DC 8D BD 40 FF FF FF    lea         edi,[ebp-0C0h]  ;讲ebp-0c0h的地址 存到edi里面
00AE13E2 B9 30 00 00 00       mov         ecx,30h         ;计数器 循环0x30次
00AE13E7 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
00AE13EC F3 AB                rep stos    dword ptr es:[edi]  ;将eax值存入edi的地址 填充0x30次
00AE13EE 5F                   pop         edi  
00AE13EF 5E                   pop         esi  
00AE13F0 5B                   pop         ebx  
00AE13F1 8B E5                mov         esp,ebp  
00AE13F3 5D                   pop         ebp  
00AE13F4 C3                   ret       ;返回

OD中代码: 和vs中反汇编代码一样

00AE13D0 >  55              push ebp
00AE13D1    8BEC            mov ebp,esp
00AE13D3    81EC C0000000   sub esp,0xC0
00AE13D9    53              push ebx
00AE13DA    56              push esi                                 ; 空函数.<ModuleEntryPoint>
00AE13DB    57              push edi
00AE13DC    8DBD 40FFFFFF   lea edi,dword ptr ss:[ebp-0xC0]
00AE13E2    B9 30000000     mov ecx,0x30
00AE13E7    B8 CCCCCCCC     mov eax,0xCCCCCCCC
00AE13EC    F3:AB           rep stos dword ptr es:[edi]
00AE13EE    5F              pop edi                                  ; 空函数.00AE14EA
00AE13EF    5E              pop esi                                  ; 空函数.00AE14EA
00AE13F0    5B              pop ebx                                  ; 空函数.00AE14EA
00AE13F1    8BE5            mov esp,ebp
00AE13F3    5D              pop ebp                                  ; 空函数.00AE14EA
00AE13F4    C3              retn

Test2:

;代码和Test1一模一样,唯一不一样的是Test2堆栈中压入了参数。

OD中代码:和上面代码一样
Test3

Test3:
00AE1430 55                   push        ebp  
00AE1431 8B EC                mov         ebp,esp  
00AE1433 81 EC D8 00 00 00    sub         esp,0D8h  ;增大了
00AE1439 53                   push        ebx  
00AE143A 56                   push        esi  
00AE143B 57                   push        edi  
00AE143C 8D BD 28 FF FF FF    lea         edi,[ebp+FFFFFF28h] ;这里ebp是减少了 因为FFFFFF28是负数 值为 - 216 是0D8h的负数 
00AE1442 B9 36 00 00 00       mov         ecx,36h  
00AE1447 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
00AE144C F3 AB                rep stos    dword ptr es:[edi]    ;还是进行了填充
00AE144E C7 45 F8 0A 00 00 00 mov         dword ptr [ebp-8],0Ah  ;局部变量a 赋值10 局部变量的地址没有规定可以在开辟的栈帧内随便定义 但是传入的参数是固定的
00AE1455 8B 45 F8             mov         eax,dword ptr [ebp-8]  
00AE1458 83 C0 14             add         eax,14h ;20 
00AE145B 89 45 EC             mov         dword ptr [ebp-14h],eax   ;局部变量B B = A + 10
00AE145E 5F                   pop         edi  
00AE145F 5E                   pop         esi  
00AE1460 5B                   pop         ebx  
00AE1461 8B E5                mov         esp,ebp  
00AE1463 5D                   pop         ebp  
00AE1464 C3                   ret   

OD中代码:一样
Test4:

Test4:
00AE1480 55                   push        ebp  
00AE1481 8B EC                mov         ebp,esp  
00AE1483 81 EC CC 00 00 00    sub         esp,0CCh  
00AE1489 53                   push        ebx  
00AE148A 56                   push        esi  
00AE148B 57                   push        edi  
00AE148C 8D BD 34 FF FF FF    lea         edi,[ebp+FFFFFF34h]  
00AE1492 B9 33 00 00 00       mov         ecx,33h  
00AE1497 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
00AE149C F3 AB                rep stos    dword ptr es:[edi]  ;进行了填充
00AE149E 8B 45 08             mov         eax,dword ptr [ebp+8]  ;将形参A赋值给eax
00AE14A1 03 45 0C             add         eax,dword ptr [ebp+0Ch]  ;将B加给eax
00AE14A4 89 45 F8             mov         dword ptr [ebp-8],eax  ;赋值局部变量
00AE14A7 5F                   pop         edi  
00AE14A8 5E                   pop         esi  
00AE14A9 5B                   pop         ebx  
00AE14AA 8B E5                mov         esp,ebp  
00AE14AC 5D                   pop         ebp  
00AE14AD C3                   ret  

OD中代码:一样的

for循环

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;
}

第一个for循环

010113AC C7 45 E0 00 00 00 00 mov         dword ptr [ebp-20h],0  ; i = 0
010113B3 EB 09                jmp         010113BE   ;跳转到了i检测条件   
010113B5 8B 45 E0             mov         eax,dword ptr [ebp-20h]  ;将i赋值给eax
010113B8 83 C0 01             add         eax,1  ;i自增1   i++
010113BB 89 45 E0             mov         dword ptr [ebp-20h],eax  
010113BE 83 7D E0 0A          cmp         dword ptr [ebp-20h],0Ah   ;jmp调到了这里  检测条件为:将i10比较
010113C2 7D 02                jge         010113C6   ;如果 i大于等于10的时候成立   这个时候就跳出了这个循环
010113C4 EB EF                jmp         010113B5   ;跳到了循环体

第二个for循环

010113CD EB FE                jmp         010113CD    ;死循环  直接一直循环

*第三个for循环

010113D6 C7 45 BC 00 00 00 00 mov         dword ptr [ebp-44h],0  ;i = 0
010113DD EB 09                jmp         010113E8    ;调到条件检查
010113DF 8B 45 BC             mov         eax,dword ptr [ebp-44h]  
010113E2 83 C0 01             add         eax,1  ;i++
010113E5 89 45 BC             mov         dword ptr [ebp-44h],eax  
010113E8 83 7D BC 0A          cmp         dword ptr [ebp-44h],0Ah   ;条件比较
010113EC 7D 0B                jge         010113F9   ;如果不满足条件 直接跳走
010113EE 8B 45 F8             mov         eax,dword ptr [ebp-8]  ;num的值
010113F1 83 C0 01             add         eax,1     ;num++
010113F4 89 45 F8             mov         dword ptr [ebp-8],eax  ;num++
010113F7 EB E6                jmp         010113DF  

while循环

    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;
}

while反汇编代码

0C3139E C7 45 F8 00 00 00 00 mov         dword ptr [ebp-8],0    ;i = 0
00C313A5 C7 45 EC 00 00 00 00 mov         dword ptr [ebp-14h],0  ;sum = 0 
00C313AC C7 45 E0 58 58 C3 00 mov         dword ptr [ebp-20h],0C35858h  ;字符串 
00C313B3 83 7D F8 0A          cmp         dword ptr [ebp-8],0Ah  ;判断条件 i和10比较 
00C313B7 7D 0B                jge         00C313C4  ;如果i >= 10 跳出循环
00C313B9 8B 45 EC             mov         eax,dword ptr [ebp-14h]  ;sum->eax 
00C313BC 03 45 F8             add         eax,dword ptr [ebp-8]    ;sum+i
00C313BF 89 45 EC             mov         dword ptr [ebp-14h],eax  ;sum=sum+i
00C313C2 EB EF                jmp         00C313B3 ;再跳转到判断条件处

do while反汇编代码

00C313CB C7 45 F8 00 00 00 00 mov         dword ptr [ebp-8],0  ;i=0
00C313D2 C7 45 EC 00 00 00 00 mov         dword ptr [ebp-14h],0  ;sum=0
00C313D9 8B 45 EC             mov         eax,dword ptr [ebp-14h]  
00C313DC 03 45 F8             add         eax,dword ptr [ebp-8]  
00C313DF 89 45 EC             mov         dword ptr [ebp-14h],eax  
00C313E2 83 7D F8 0A          cmp         dword ptr [ebp-8],0Ah  ;先执行函数体 然后再判断条件
00C313E6 7C F1                jl          00C313D9 

总结:while是判断条件不符合,直接跳转到循环外面,否则就一直执行循环体
do while 是判断条件是否符合,如果符合就跳转到下一个循环体,否则不跳转,直接运行下条代码。


if语句

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;
}

第一个if语句

001A13A5 83 7D F8 0A          cmp         dword ptr [ebp-8],0Ah   ;num10比较
001A13A9 75 09                jne         001A13B4   ;如果不为10 调到else if处  为10 就不跳
001A13AB C7 45 F8 14 00 00 00 mov         dword ptr [ebp-8],14h   ; num = 20
001A13B2 EB 0D                jmp         001A13C1   ;跳走
001A13B4 83 7D F8 14          cmp         dword ptr [ebp-8],14h  ;和20比较
001A13B8 75 07                jne         001A13C1  ;如果不为20 跳走

第二个if语句

001A13C8 83 7D F8 00          cmp         dword ptr [ebp-8],0   ;num和0比较
001A13CC 75 09                jne         001A13D7    ;如果为0 就不跳走  否则调到下个判断语句
001A13CE 8B 45 F8             mov         eax,dword ptr [ebp-8]  
001A13D1 83 C0 01             add         eax,1      ;num++
001A13D4 89 45 F8             mov         dword ptr [ebp-8],eax  
001A13D7 83 7D F8 02          cmp         dword ptr [ebp-8],2  ;num和2比较
001A13DB 75 09                jne         001A13E6  ;如果不是2  直接跳走  否则直接运行代码
001A13DD 8B 45 F8             mov         eax,dword ptr [ebp-8]  
001A13E0 83 C0 01             add         eax,1    ;num++
001A13E3 89 45 F8             mov         dword ptr [ebp-8],eax  

总结: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;
}

反汇编代码

00E7139E C7 45 F8 0A 00 00 00 mov         dword ptr [num],0Ah   ;num = 10
00E713A5 8B 45 F8             mov         eax,dword ptr [num]  
00E713A8 89 85 30 FF FF FF    mov         dword ptr [ebp-0D0h],eax   ;将num的值放在 ebp-od0 处 也就是esp处
00E713AE 8B 8D 30 FF FF FF    mov         ecx,dword ptr [ebp-0D0h]  ;
00E713B4 83 E9 01             sub ecx,1 ;将num-1 = 9
00E713B7 89 8D 30 FF FF FF    mov         dword ptr [ebp-0D0h],ecx  
00E713BD 83 BD 30 FF FF FF 06 cmp         dword ptr [ebp-0D0h],6    ;将num - 1 = 96比较
00E713C4 77 3A                ja          $LN6+2Dh (0E71400h)       ;如果大于6  直接跳到 num= 0 处 也就是 default处
00E713C6 8B 95 30 FF FF FF    mov         edx,dword ptr [ebp-0D0h]  
00E713CC FF 24 95 10 14 E7 00 jmp         dword ptr [edx*4+0E71410h]  ;这个地方非常巧妙 0E71410位置是跳转表的地址   前面edx*4 代表索引   因为每个地址占4字节  因此每次增加4
$LN6:
00E713D3 C7 45 F8 01 00 00 00 mov         dword ptr [num],1  ;num = 1
00E713DA EB 2B                jmp         $LN6+34h (0E71407h) ;break 
$LN5:
00E713DC C7 45 F8 02 00 00 00 mov         dword ptr [num],2  ;num=2
00E713E3 EB 22                jmp         $LN6+34h (0E71407h)  ;break 
$LN4:
00E713E5 C7 45 F8 04 00 00 00 mov         dword ptr [num],4  ;num =4
00E713EC EB 19                jmp         $LN6+34h (0E71407h)  ;break 
$LN3:
00E713EE C7 45 F8 05 00 00 00 mov         dword ptr [num],5  ;num = 5
00E713F5 EB 10                jmp         $LN6+34h (0E71407h)  ;break 
$LN2:
00E713F7 C7 45 F8 07 00 00 00 mov         dword ptr [num],7   ;num =7
00E713FE EB 07                jmp         $LN6+34h (0E71407h)  ;break 
00E71400 C7 45 F8 00 00 00 00 mov         dword ptr [num],0    ;default  num= 0

下面是 0E71410h位置的数据:

0x00E71410  d3 13 e7 00  ?.?.   ;ln6      1
0x00E71414  dc 13 e7 00  ?.?.   ;ln5      2
0x00E71418  00 14 e7 00  ..?.   ;default 3
0x00E7141C  e5 13 e7 00  ?.?.   ;ln4      4
0x00E71420  ee 13 e7 00  ?.?.   ;ln3      5
0x00E71424  f7 13 e7 00  ?.?.   ;         6
0x00E71428  f7 13 e7 00  ?.?.   ;ln2      7

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

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