最近在分析C++ dump 文件的時候覺得有必要將一些必要的反匯編東西總結一下以備別人參考,自己有時間的時候也可以進行更多的改進。下面通過一個簡單的C++代碼轉成匯編代碼后的詳細解釋說明一下C++和匯編的對應關系,以及如何識別匯編代碼中進行的一些操作的意義。代碼的調用關系如下圖所示:

完整C++代碼下:
int InternalFunctionA(
int nSizeA1,
int nSizeA2)
{
int localnSizeA1 = nSizeA1;
int localnSizeA2 = nSizeA2;
int nFunctionA = localnSizeA1 + localnSizeA2;
return nFunctionA;
}
int InternalFunctionB( int nSizeB1, int nSizeB2)
{
int nFunctionA = InternalFunctionA(nSizeB1, nSizeB2);
return 0;
}
int _tmain( int argc, _TCHAR* argv[])
{
int nFunctionVal = InternalFunctionB( 36, 64);
cout<< " Hello SolidMango! "<<endl;
return 0;
}
{
int localnSizeA1 = nSizeA1;
int localnSizeA2 = nSizeA2;
int nFunctionA = localnSizeA1 + localnSizeA2;
return nFunctionA;
}
int InternalFunctionB( int nSizeB1, int nSizeB2)
{
int nFunctionA = InternalFunctionA(nSizeB1, nSizeB2);
return 0;
}
int _tmain( int argc, _TCHAR* argv[])
{
int nFunctionVal = InternalFunctionB( 36, 64);
cout<< " Hello SolidMango! "<<endl;
return 0;
}
那么這段簡單的C++代碼在轉換成匯編代碼之后是什么樣子的呢?讓我們拭目以待,首先讓我們看看main函數轉換后的代碼(debug版), 如下,我們逐條來進行分析,
int _tmain(
int argc, _TCHAR* argv[])
{
00411570 push ebp //棧底壓棧
00411571 mov ebp,esp //棧底下移,更詳細的請參考我關於ebp,esp的解釋
00411573 sub esp,0CCh //局部變量預留空間
00411579 push ebx //保存ebx
0041157A push esi //保存esi
0041157B push edi //保存edi
0041157C lea edi,[ebp-0CCh] //下移edi到棧頂
00411582 mov ecx,33h //0CCh/4 = 33h
00411587 mov eax,0CCCCCCCCh //eax賦值
0041158C rep stos dword ptr es:[edi] //從edi開始做33h次賦值0CCCCCCCCh ,初始化棧內存
int nFunctionVal = InternalFunctionB( 36, 64);
0041158E push 40h //參數64入棧,
00411590 push 24h //參數36入棧
00411592 call InternalFunctionB (41101Eh) );//到41101Eh處函數調用
00411597 add esp, 8 //函數調用后將參數彈出,清理棧
0041159A mov dword ptr [nFunctionVal],eax
cout<< " Hello SolidMango! "<<endl;
0041159D mov esi,esp
0041159F mov eax,dword ptr [__imp_std::endl (41A338h)]
004115A4 push eax
004115A5 push offset string " Hello SolidMango! " (417800h)
004115AA mov ecx,dword ptr [__imp_std::cout (41A33Ch)]
004115B0 push ecx
004115B1 call std:: operator<<<std::char_traits< char> > (411163h)
004115B6 add esp, 8
004115B9 mov ecx,eax
004115BB call dword ptr [__imp_std::basic_ostream< char,std::char_traits< char> >:: operator<< (41A320h)]
004115C1 cmp esi,esp
004115C3 call @ILT+ 430(__RTC_CheckEsp) (4111B3h)
return 0;
004115C8 xor eax,eax
}
004115CA pop edi //恢復edi
004115CB pop esi //恢復esi
004115CC pop ebx //恢復ebx
004115CD add esp,0CCh //棧頂上移
004115D3 cmp ebp,esp //檢查棧平衡
004115D5 call @ILT+ 430(__RTC_CheckEsp) (4111B3h)
004115DA mov esp,ebp //恢復上一個棧幀的ebp,esp
004115DC pop ebp
004115DD ret//函數返回
{
00411570 push ebp //棧底壓棧
00411571 mov ebp,esp //棧底下移,更詳細的請參考我關於ebp,esp的解釋
00411573 sub esp,0CCh //局部變量預留空間
00411579 push ebx //保存ebx
0041157A push esi //保存esi
0041157B push edi //保存edi
0041157C lea edi,[ebp-0CCh] //下移edi到棧頂
00411582 mov ecx,33h //0CCh/4 = 33h
00411587 mov eax,0CCCCCCCCh //eax賦值
0041158C rep stos dword ptr es:[edi] //從edi開始做33h次賦值0CCCCCCCCh ,初始化棧內存
int nFunctionVal = InternalFunctionB( 36, 64);
0041158E push 40h //參數64入棧,
00411590 push 24h //參數36入棧
00411592 call InternalFunctionB (41101Eh) );//到41101Eh處函數調用
00411597 add esp, 8 //函數調用后將參數彈出,清理棧
0041159A mov dword ptr [nFunctionVal],eax
cout<< " Hello SolidMango! "<<endl;
0041159D mov esi,esp
0041159F mov eax,dword ptr [__imp_std::endl (41A338h)]
004115A4 push eax
004115A5 push offset string " Hello SolidMango! " (417800h)
004115AA mov ecx,dword ptr [__imp_std::cout (41A33Ch)]
004115B0 push ecx
004115B1 call std:: operator<<<std::char_traits< char> > (411163h)
004115B6 add esp, 8
004115B9 mov ecx,eax
004115BB call dword ptr [__imp_std::basic_ostream< char,std::char_traits< char> >:: operator<< (41A320h)]
004115C1 cmp esi,esp
004115C3 call @ILT+ 430(__RTC_CheckEsp) (4111B3h)
return 0;
004115C8 xor eax,eax
}
004115CA pop edi //恢復edi
004115CB pop esi //恢復esi
004115CC pop ebx //恢復ebx
004115CD add esp,0CCh //棧頂上移
004115D3 cmp ebp,esp //檢查棧平衡
004115D5 call @ILT+ 430(__RTC_CheckEsp) (4111B3h)
004115DA mov esp,ebp //恢復上一個棧幀的ebp,esp
004115DC pop ebp
004115DD ret//函數返回
另外兩層函數調用的匯編代碼如下,感興趣的讀者可以對比一下,和main函數的過程相似,
int InternalFunctionA(
int nSizeA1,
int nSizeA2)
{
004114C0 push ebp
004114C1 mov ebp,esp
004114C3 sub esp,0E4h
004114C9 push ebx
004114CA push esi
004114CB push edi
004114CC lea edi,[ebp-0E4h]
004114D2 mov ecx,39h
004114D7 mov eax,0CCCCCCCCh
004114DC rep stos dword ptr es:[edi]
int localnSizeA1 = nSizeA1;
004114DE mov eax,dword ptr [nSizeA1]
004114E1 mov dword ptr [localnSizeA1],eax
int localnSizeA2 = nSizeA2;
004114E4 mov eax,dword ptr [nSizeA2]
004114E7 mov dword ptr [localnSizeA2],eax
int nFunctionA = localnSizeA1 + localnSizeA2;
004114EA mov eax,dword ptr [localnSizeA1]
004114ED add eax,dword ptr [localnSizeA2]
004114F0 mov dword ptr [nFunctionA],eax
return nFunctionA;
004114F3 mov eax,dword ptr [nFunctionA]
}
004114F6 pop edi
004114F7 pop esi
004114F8 pop ebx
004114F9 mov esp,ebp
004114FB pop ebp
004114FC ret
int InternalFunctionB( int nSizeB1, int nSizeB2)
{
00411510 push ebp
00411511 mov ebp,esp
00411513 sub esp,0CCh
00411519 push ebx
0041151A push esi
0041151B push edi
0041151C lea edi,[ebp-0CCh]
00411522 mov ecx,33h
00411527 mov eax,0CCCCCCCCh
0041152C rep stos dword ptr es:[edi]
int nFunctionA = InternalFunctionA(nSizeB1, nSizeB2);
0041152E mov eax,dword ptr [nSizeB2]
00411531 push eax
00411532 mov ecx,dword ptr [nSizeB1]
00411535 push ecx
00411536 call InternalFunctionA (411140h)
0041153B add esp, 8
0041153E mov dword ptr [nFunctionA],eax
return 0;
00411541 xor eax,eax
}
00411543 pop edi
00411544 pop esi
00411545 pop ebx
00411546 add esp,0CCh
0041154C cmp ebp,esp
0041154E call @ILT+ 430(__RTC_CheckEsp) (4111B3h)
00411553 mov esp,ebp
00411555 pop ebp
00411556 ret
{
004114C0 push ebp
004114C1 mov ebp,esp
004114C3 sub esp,0E4h
004114C9 push ebx
004114CA push esi
004114CB push edi
004114CC lea edi,[ebp-0E4h]
004114D2 mov ecx,39h
004114D7 mov eax,0CCCCCCCCh
004114DC rep stos dword ptr es:[edi]
int localnSizeA1 = nSizeA1;
004114DE mov eax,dword ptr [nSizeA1]
004114E1 mov dword ptr [localnSizeA1],eax
int localnSizeA2 = nSizeA2;
004114E4 mov eax,dword ptr [nSizeA2]
004114E7 mov dword ptr [localnSizeA2],eax
int nFunctionA = localnSizeA1 + localnSizeA2;
004114EA mov eax,dword ptr [localnSizeA1]
004114ED add eax,dword ptr [localnSizeA2]
004114F0 mov dword ptr [nFunctionA],eax
return nFunctionA;
004114F3 mov eax,dword ptr [nFunctionA]
}
004114F6 pop edi
004114F7 pop esi
004114F8 pop ebx
004114F9 mov esp,ebp
004114FB pop ebp
004114FC ret
int InternalFunctionB( int nSizeB1, int nSizeB2)
{
00411510 push ebp
00411511 mov ebp,esp
00411513 sub esp,0CCh
00411519 push ebx
0041151A push esi
0041151B push edi
0041151C lea edi,[ebp-0CCh]
00411522 mov ecx,33h
00411527 mov eax,0CCCCCCCCh
0041152C rep stos dword ptr es:[edi]
int nFunctionA = InternalFunctionA(nSizeB1, nSizeB2);
0041152E mov eax,dword ptr [nSizeB2]
00411531 push eax
00411532 mov ecx,dword ptr [nSizeB1]
00411535 push ecx
00411536 call InternalFunctionA (411140h)
0041153B add esp, 8
0041153E mov dword ptr [nFunctionA],eax
return 0;
00411541 xor eax,eax
}
00411543 pop edi
00411544 pop esi
00411545 pop ebx
00411546 add esp,0CCh
0041154C cmp ebp,esp
0041154E call @ILT+ 430(__RTC_CheckEsp) (4111B3h)
00411553 mov esp,ebp
00411555 pop ebp
00411556 ret
總結:通過這幾篇文章的總結,相信大家已經可以看懂一些常規的C++反匯編代碼,應該可以對付一般的應用,如果大家還有什么問題,或者建議歡迎討論。
