1.需求
? ? ? ? 逆向工程師必須先是一個(gè)正向開發(fā)工程師,如果沒有C++/MFC的開發(fā)經(jīng)驗(yàn),就不會(huì)懂得如何逆向分析C++/MFC的程序,本文完成一個(gè)helloworld的C++正逆向過程。
2.C++程序源碼
? ? 編譯環(huán)境:visual studio 2022
#include <iostream>
#include <cstdlib>
using namespace std;
int main()
{
int a;
a = 100;
for (int i = 0; i < a; i++)
{
cout << "Hello World! " << endl;
}
cin >> a;
return 0;
}
編譯完畢后生成exe程序,導(dǎo)入Ghidra,分析完畢后,在symbol tree窗口,輸入main查找到主函數(shù)位置:
3.反編譯結(jié)果
3.1 Ghidra反匯編
int __cdecl main(int _Argc,char **_Argv,char **_Env)
{
basic_ostream<char,std::char_traits<char>_> *this;
int iVar1;
_RTC_framedesc *extraout_EDX;
int *piVar2;
code *pcVar3;
int local_20 [4];
int local_10 [2];
uint local_8;
piVar2 = local_20;
for (iVar1 = 7; iVar1 != 0; iVar1 = iVar1 + -1) {
*piVar2 = -0x33333334;
piVar2 = piVar2 + 1;
}
local_8 = __security_cookie ^ (uint)&stack0xfffffffc;
local_10[0] = 100;
/* static local (stored at 004124a0) <NoType>
static local (stored at 00412494) <NoType>
static local (stored at 0041248c) <NoType>
static local (stored at 004124a0) <NoType>
static local (stored at 00412494) <NoType>
static local (stored at 0041248c) <NoType> */
for (local_20[1] = 0; local_20[1] < local_10[0]; local_20[1] = local_20[1] + 1) {
pcVar3 = std::endl<char,std::char_traits<char>_>;
this = std::operator<<<std::char_traits<char>_>
((basic_ostream<char,std::char_traits<char>_> *)cout_exref,"Hello World! ");
std::basic_ostream<char,struct_std::char_traits<char>_>::operator<<
((basic_ostream<char,struct_std::char_traits<char>_> *)this,pcVar3);
_RTC_CheckEsp();
}
std::basic_istream<char,struct_std::char_traits<char>_>::operator>>
((basic_istream<char,struct_std::char_traits<char>_> *)cin_exref,local_10);
_RTC_CheckEsp();
iVar1 = 0;
_RTC_CheckStackVars((void *)0x0,extraout_EDX);
__security_check_cookie(local_8 ^ (uint)&stack0xfffffffc);
local_8 = 0x412487;
_RTC_CheckEsp();
return iVar1;
}
3.2 IDA 結(jié)果
int __cdecl main()
{
std::ostream *v0; // eax
int i; // [esp+D0h] [ebp-18h]
int a; // [esp+DCh] [ebp-Ch] BYREF
a = 100;
for ( i = 0; i < a; ++i )
{
v0 = std::operator<<<std::char_traits<char>>(std::cout, "Hello World! ");
std::ostream::operator<<(v0, std::endl<char,std::char_traits<char>>);
}
std::istream::operator>>(std::cin, &a);
return 0;
}
4.Visual studio 里查看匯編代碼
在正向開發(fā)的過程中,可以在編譯器Visual studio里,查看C++代碼的匯編代碼,在程序中設(shè)置斷點(diǎn),F(xiàn)5編譯,等程序停住后,才有查看匯編選項(xiàng):
?匯編代碼如下:
--- C:\Users\paul\source\repos\helloc++\helloc++\helloc++.cpp ------------------
1: // helloc++.cpp : 此文件包含 "main" 函數(shù)。程序執(zhí)行將在此處開始并結(jié)束。
2: //
3:
4: #include <iostream>
5: #include <cstdlib>
6: using namespace std;
7:
8:
9: int main()
10: {
003F23D0 55 push ebp
003F23D1 8B EC mov ebp,esp
003F23D3 81 EC DC 00 00 00 sub esp,0DCh
003F23D9 53 push ebx
003F23DA 56 push esi
003F23DB 57 push edi
003F23DC 8D 7D E4 lea edi,[ebp-1Ch]
003F23DF B9 07 00 00 00 mov ecx,7
003F23E4 B8 CC CC CC CC mov eax,0CCCCCCCCh
003F23E9 F3 AB rep stos dword ptr es:[edi]
003F23EB A1 04 C0 3F 00 mov eax,dword ptr [__security_cookie (03FC004h)]
003F23F0 33 C5 xor eax,ebp
003F23F2 89 45 FC mov dword ptr [ebp-4],eax
11: int a;
12: a = 100;
003F23F5 C7 45 F4 64 00 00 00 mov dword ptr [a],64h
13: for (int i = 0; i < a; i++)
003F23FC C7 45 E8 00 00 00 00 mov dword ptr [ebp-18h],0
003F2403 EB 09 jmp __$EncStackInitStart+32h (03F240Eh)
003F2405 8B 45 E8 mov eax,dword ptr [ebp-18h]
003F2408 83 C0 01 add eax,1
003F240B 89 45 E8 mov dword ptr [ebp-18h],eax
003F240E 8B 45 E8 mov eax,dword ptr [ebp-18h]
003F2411 3B 45 F4 cmp eax,dword ptr [a]
003F2414 7D 2B jge __$EncStackInitStart+65h (03F2441h)
14: {
15: cout << "Hello World! " << endl;
003F2416 8B F4 mov esi,esp
003F2418 68 3C 10 3F 00 push offset std::endl<char,std::char_traits<char> > (03F103Ch)
003F241D 68 30 9B 3F 00 push offset string "Hello World! " (03F9B30h)
003F2422 A1 DC D0 3F 00 mov eax,dword ptr [__imp_std::cout (03FD0DCh)]
003F2427 50 push eax
003F2428 E8 7C ED FF FF call std::operator<<<std::char_traits<char> > (03F11A9h)
003F242D 83 C4 08 add esp,8
003F2430 8B C8 mov ecx,eax
003F2432 FF 15 A8 D0 3F 00 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (03FD0A8h)]
003F2438 3B F4 cmp esi,esp
003F243A E8 50 EE FF FF call __RTC_CheckEsp (03F128Fh)
16: }
003F243F EB C4 jmp __$EncStackInitStart+29h (03F2405h)
17: cin >> a;
003F2441 8B F4 mov esi,esp
003F2443 8D 45 F4 lea eax,[a]
003F2446 50 push eax
003F2447 8B 0D 98 D0 3F 00 mov ecx,dword ptr [__imp_std::cin (03FD098h)]
003F244D FF 15 9C D0 3F 00 call dword ptr [__imp_std::basic_istream<char,std::char_traits<char> >::operator>> (03FD09Ch)]
003F2453 3B F4 cmp esi,esp
003F2455 E8 35 EE FF FF call __RTC_CheckEsp (03F128Fh)
18: return 0;
003F245A 33 C0 xor eax,eax
19:
20: }
003F245C 52 push edx
003F245D 8B CD mov ecx,ebp
003F245F 50 push eax
003F2460 8D 15 8C 24 3F 00 lea edx,ds:[3F248Ch]
003F2466 E8 C0 ED FF FF call @_RTC_CheckStackVars@8 (03F122Bh)
003F246B 58 pop eax
003F246C 5A pop edx
003F246D 5F pop edi
003F246E 5E pop esi
003F246F 5B pop ebx
003F2470 8B 4D FC mov ecx,dword ptr [ebp-4]
003F2473 33 CD xor ecx,ebp
003F2475 E8 02 ED FF FF call @__security_check_cookie@4 (03F117Ch)
003F247A 81 C4 DC 00 00 00 add esp,0DCh
003F2480 3B EC cmp ebp,esp
003F2482 E8 08 EE FF FF call __RTC_CheckEsp (03F128Fh)
003F2487 8B E5 mov esp,ebp
003F2489 5D pop ebp
003F248A C3 ret
003F248B 90 nop
003F248C 01 00 add dword ptr [eax],eax
003F248E 00 00 add byte ptr [eax],al
003F2490 94 xchg eax,esp
003F2491 24 3F and al,3Fh
003F2493 00 F4 add ah,dh
003F2495 FF ?? ??????
003F2496 FF ?? ??????
19:
20: }
003F2497 FF 04 00 inc dword ptr [eax+eax]
003F249A 00 00 add byte ptr [eax],al
003F249C A0 24 3F 00 61 mov al,byte ptr ds:[61003F24h]
003F24A1 00 CC add ah,cl
5.小結(jié)
IDA反編譯的結(jié)果更接近源程序,因?yàn)?.讀取了pdb文件,2.不顯示參數(shù)檢查的反編譯代碼(?__security_cookie和_RTC_CheckStackVars等)。
5.1 什么是security cookie
并不是windows系統(tǒng)自帶的保護(hù)機(jī)制,并不是說一個(gè)確實(shí)存在溢出漏洞的程序,放到帶security cookie保護(hù)的環(huán)境中,就不能正常溢出了。其原理是在所有變量入棧前,多壓入一個(gè)變量(隨機(jī)數(shù)),然后函數(shù)執(zhí)行完之后,再去檢查這個(gè)數(shù)是不是一樣的,文章來源:http://www.zghlxwxcb.cn/news/detail-798672.html
5.2 什么是_RTC_CheckStackVars。
這也是一個(gè)編譯器行為,_RTC_CheckStackVars第一個(gè)參數(shù)是函數(shù)要檢查的棧頂?shù)刂?,第二個(gè)參數(shù)指向結(jié)構(gòu)體_RTC_framedesc。該結(jié)構(gòu)體第一個(gè)參數(shù)是壓棧的局部變量個(gè)數(shù),第二個(gè)參數(shù)保存局部變量相關(guān)信息。分別是變量的棧偏移地址,變量大小和變量的名字。因此我們可以通過地址跳轉(zhuǎn)最終找到出錯(cuò)的變量文章來源地址http://www.zghlxwxcb.cn/news/detail-798672.html
到了這里,關(guān)于C++程序正向編譯逆向反編譯(一)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!