空函数
#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调到了这里 检测条件为:将i和10比较
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 ;num和10比较
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 = 9 和6比较
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… 代码一模一样。