C++程序正向编译逆向反编译(一)

C++程序正向编译逆向反编译(一)

1.需求

逆向工程师必须先是一个正向开发工程师,如果没有C++/MFC的开发经验,就不会懂得如何逆向分析C++/MFC的程序,本文完成一个helloworld的C++正逆向过程。

2.C++程序源码

编译环境:visual studio 2022

#include

#include

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程序,导入Ghidra,分析完毕后,在symbol tree窗口,输入main查找到主函数位置:

3.反编译结果

3.1 Ghidra反汇编

int __cdecl main(int _Argc,char **_Argv,char **_Env)

{

basic_ostream_> *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)

static local (stored at 00412494)

static local (stored at 0041248c)

static local (stored at 004124a0)

static local (stored at 00412494)

static local (stored at 0041248c) */

for (local_20[1] = 0; local_20[1] < local_10[0]; local_20[1] = local_20[1] + 1) {

pcVar3 = std::endl_>;

this = std::operator<<_>

((basic_ostream_> *)cout_exref,"Hello World! ");

std::basic_ostream_>::operator<<

((basic_ostream_> *)this,pcVar3);

_RTC_CheckEsp();

}

std::basic_istream_>::operator>>

((basic_istream_> *)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 结果

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::cout, "Hello World! ");

std::ostream::operator<<(v0, std::endl>);

}

std::istream::operator>>(std::cin, &a);

return 0;

}

4.Visual studio 里查看汇编代码

在正向开发的过程中,可以在编译器Visual studio里,查看C++代码的汇编代码,在程序中设置断点,F5编译,等程序停住后,才有查看汇编选项:

汇编代码如下:

--- C:\Users\paul\source\repos\helloc++\helloc++\helloc++.cpp ------------------

1: // helloc++.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。

2: //

3:

4: #include

5: #include

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 > (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<< > (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 >::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 >::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.小结

IDA反编译的结果更接近源程序,因为1.读取了pdb文件,2.不显示参数检查的反编译代码( __security_cookie和_RTC_CheckStackVars等)。

5.1 什么是security cookie

并不是windows系统自带的保护机制,并不是说一个确实存在溢出漏洞的程序,放到带security cookie保护的环境中,就不能正常溢出了。其原理是在所有变量入栈前,多压入一个变量(随机数),然后函数执行完之后,再去检查这个数是不是一样的,

5.2 什么是_RTC_CheckStackVars。

这也是一个编译器行为,_RTC_CheckStackVars第一个参数是函数要检查的栈顶地址,第二个参数指向结构体_RTC_framedesc。该结构体第一个参数是压栈的局部变量个数,第二个参数保存局部变量相关信息。分别是变量的栈偏移地址,变量大小和变量的名字。因此我们可以通过地址跳转最终找到出错的变量

猜你喜欢

36秒等于多少分钟
365bet备用线路

36秒等于多少分钟

📅 10-31 ❤️ 980
没有找到站点
365bet官方

没有找到站点

📅 07-18 ❤️ 491
怎么向佛祖求姻缘
365bet官方

怎么向佛祖求姻缘

📅 10-10 ❤️ 472
“辰”的五笔编码是什么、“辰”五笔怎么样拆分、“辰”怎么读、“辰”笔画、“辰”意思
美瞳一般多少钱
365bet备用线路

美瞳一般多少钱

📅 10-01 ❤️ 451
苹果7指纹解锁和密码解锁同步怎么设置
365bet官方

苹果7指纹解锁和密码解锁同步怎么设置

📅 07-02 ❤️ 467
派派交友怎么加入家族 派派加入家族教程介绍
天界BOSS和地下BOSS
中信精彩365

天界BOSS和地下BOSS

📅 10-26 ❤️ 894
魔力百科魔力怀旧新手纠结那点事(二)
中信精彩365

魔力百科魔力怀旧新手纠结那点事(二)

📅 07-07 ❤️ 476