MFC == Microsoft Foundation Class,微軟基礎類庫,他封裝了Windows API以便用戶更快速的開發界面功能程序 然而該庫及其龐大而復雜,需要有C++的功底否則很難解決bug,逆向起來也是需要一定技巧。 本人曾總結過Windows消息大全,他截取自winuser.h commctrl.h,如果將這些消息以及通知碼(LVN_??這樣的)總結一下,對分析很有好處: #define WM_NULL 0x0000 0 #define WM_CREATE 0x0001 #define WM_DESTROY 0x0002 #define WM_MOVE 0x0003 #define WM_SIZE 0x0005 #define WM_ACTIVATE 0x0006 #define WM_SETFOCUS 0x0007 #define WM_KILLFOCUS 0x0008 #define WM_ENABLE 0x000A #define WM_SETREDRAW 0x000B #define WM_SETTEXT 0x000C #define WM_GETTEXT 0x000D #define WM_GETTEXTLENGTH 0x000E #define WM_PAINT 0x000F 。。。。。。。。。。。。。。。 如果拿其他自己寫的程序來說明顯然沒有說服力,我們就找一個MFC寫的來看,超凡搜索BeyondSeacher ,下載下來以后主程序是P2P Searcher.exe,網上說他們抄襲了amule的,我們就來看看究竟。用peid看做初步判斷,可以看到Microsoft Visual C++ 7.0 [Debug] IDA載入,先來找入口點,Start->WinMain->可以看到了IDA識別出了Afx系內部函數,且為靜態調用。對於對話框類MFC程序,C??App和C???Dlg是關鍵類,在源碼中可以看到這一點,總是有個全局對象,例如“CtestmfcApp theApp;”,那么就需要在c庫_initc()中進行初始化(__xc_a -> __xc_z),另外C???App構造的時候會先構造父類CWinApp,且構造父類之后會設置設置虛表從而構造子類,C???Dlg過程類似。根據該原理可以定位到這2個類的位置。先找到CWinApp::CWinApp構造函數,發現索引位置 void *__thiscall sub_401850(void *this) { void *v1; // esi@1 v1 = this; CWinApp::CWinApp(this, 0); *(_DWORD *)v1 = &off_4315F8; return v1; } 顯然是C???App的構造函數,先不急着看,往上層找: int sub_42FF70() { sub_401850(&unk_43F0E0); return atexit(sub_42FFF0); } 可見此處執行的是c庫,程序啟動時構造C???App myapp,同時注冊退出時的析構函數,以便清理資源 在往上看已經是一堆要在啟動時要初始化的函數了。。。 .data:0043D000 _data segment para public 'DATA' use32 .data:0043D000 assume cs:_data .data:0043D000 ;org 43D000h .data:0043D000 dword_43D000 dd 0 ; DATA XREF: HEADER:0040025Co .data:0043D000 ; __cinit+45o .data:0043D004 dd offset ___security_init_cookie .data:0043D008 dd offset sub_42C50E .data:0043D00C dd offset sub_42C51A .data:0043D010 dd offset sub_4275B5 .data:0043D014 dd offset sub_42D447 .data:0043D018 dd offset sub_42FFB2 .data:0043D01C dd offset unknown_libname_372 ; MFC 3.1-11.0 32bit .data:0043D020 dd offset sub_42FF70 .data:0043D024 dd offset sub_42FF90 .data:0043D028 dd offset sub_42FFA6 .data:0043D02C dd offset unknown_libname_239 ; MFC 3.1-11.0 32bit .data:0043D030 dd offset unknown_libname_240 ; MFC 3.1-11.0 32bit .data:0043D034 dd offset unknown_libname_241 ; MFC 3.1-11.0 32bit .data:0043D038 dd offset sub_4269DB 。。。。。。。。。。 接着看sub_401850,其虛表為off_4315F8: .rdata:004315F8 off_4315F8 dd offset sub_42B312 ; DATA XREF: sub_401850+Ao .rdata:004315FC dd offset sub_401970 .rdata:00431600 dd offset nullsub_4 .rdata:00431604 dd offset ?OnCmdMsg@CCmdTarget@@UAEHIHPAXPAUAFX_CMDHANDLERINFO@@@Z ; CCmdTarget::OnCmdMsg(uint,int,void *,AFX_CMDHANDLERINFO *) .rdata:00431608 dd offset ?OnFinalRelease@CCmdTarget@@UAEXXZ ; CCmdTarget::OnFinalRelease(void) .rdata:0043160C dd offset sub_4229A6 .rdata:00431610 dd offset ?_Get_deleter@_Ref_count_base@std@@UBEPAXABVtype_info@@@Z_6 ; std::_Ref_count_base::_Get_deleter(type_info const &) .rdata:00431614 dd offset sub_4229AC .rdata:00431618 dd offset sub_4229AC .rdata:0043161C dd offset ?GetTypeLib@CCmdTarget@@UAEJKPAPAUITypeLib@@@Z ; CCmdTarget::GetTypeLib(ulong,ITypeLib * *) .rdata:00431620 dd offset sub_401840 .rdata:00431624 dd offset sub_422A0C .rdata:00431628 dd offset sub_4229BD .rdata:0043162C dd offset sub_422A06 .rdata:00431630 dd offset sub_4229C9 .rdata:00431634 dd offset sub_4229C3 .rdata:00431638 dd offset sub_4229FD 。。。。。。。。。。。。 根據虛函數特點,如果子類重新定義了虛函數后會覆蓋父類虛函數,因此未識別出來的均是經過修改的,那么我們只需要對照MFC源碼中CWinApp的類布局,就可以知道未識別出的函數是哪些了,具體操作不再贅述,C???App最重要的是InitInstance函數,為虛表第21個函數,我們來看他做了些什么: int __thiscall sub_401880(CWinApp *this) { CWinApp *v1; // esi@1 void *v2; // eax@1 int v3; // eax@2 char v5; // [sp+8h] [bp-2C8h]@1 int v6; // [sp+2CCh] [bp-4h]@1 v1 = this; InitCommonControls(); CWinApp::InitInstance(v1); AfxEnableControlContainer(0); sub_42B8C2("應用程序向導生成的本地應用程序"); sub_40A150(&v5, 0); v6 = 0; *((_DWORD *)v1 + 7) = &v5; CDialog: ![]() v2 = operator new(1u); LOBYTE(v6) = 1; if ( v2 ) v3 = sub_401000(v2); else v3 = 0; LOBYTE(v6) = 0; j_uninit(v3); v6 = -1; sub_409E20(&v5); return 0; } 我們只來討論和普通CWinApp構造函數不同的地方: 可以得知v5是我們的C???Dlg,而下面v2 = operator new(1u)顯然是某個構造函數,翻譯過來就是: BOOL CP2pSearcherApp::InitInstance() { InitCommonControls(); CWinApp::InitInstance(); SetRegistryKey(_T("應用程序向導生成的本地應用程序")); CP2pSearcherDlg dlg; m_pMainWnd=&Dlg; int nResponse=dlg.DoModal(); if (nResponse == IDOK) { } else if (nResponse == IDCANCEL) { } dispatch* mydispatch=new dispatch; mydispatch->uninit(); } 下面來看CP2pSearcherDlg: void *__thiscall sub_40A150(void *this, int a2) { void *v2; // esi@1 int v3; // eax@1 int v4; // eax@1 int v5; // edi@1 struct AFX_MODULE_STATE *v6; // eax@1 void *v7; // eax@1 void *v8; // eax@2 void *v9; // eax@4 bool v10; // cf@7 void *v12; // [sp+14h] [bp-30h]@7 void *v13; // [sp+18h] [bp-2Ch]@7 int v14; // [sp+28h] [bp-1Ch]@7 unsigned int v15; // [sp+2Ch] [bp-18h]@7 int v16; // [sp+30h] [bp-14h]@7 int v17; // [sp+40h] [bp-4h]@1 v2 = this; CDialog::CDialog(this, 0x66u, a2); v17 = 0; *(_DWORD *)v2 = &off_431C50; CWnd::CWnd((char *)v2 + 116); *((_DWORD *)v2 + 29) = &off_43326C; CWnd::CWnd((char *)v2 + 196); *((_DWORD *)v2 + 49) = &off_4334A4; CWnd::CWnd((char *)v2 + 276); *((_DWORD *)v2 + 69) = &off_43326C; CWnd::CWnd((char *)v2 + 356); *((_DWORD *)v2 + 89) = &off_43326C; CWnd::CWnd((char *)v2 + 436); *((_DWORD *)v2 + 109) = &off_43311C; CWnd::CWnd((char *)v2 + 516); *((_DWORD *)v2 + 129) = &off_4335F4; *((_DWORD *)v2 + 149) = 0; *((_DWORD *)v2 + 156) = 15; *((_DWORD *)v2 + 155) = 0; *((_BYTE *)v2 + 604) = 0; LOBYTE(v17) = 7; v3 = sub_402BB0((char *)v2 + 628); *((_DWORD *)v2 + 158) = v3; *(_BYTE *)(v3 + 45) = 1; *(_DWORD *)(*((_DWORD *)v2 + 158) + 4) = *((_DWORD *)v2 + 158); **((_DWORD **)v2 + 158) = *((_DWORD *)v2 + 158); *(_DWORD *)(*((_DWORD *)v2 + 158) + 8) = *((_DWORD *)v2 + 158); *((_DWORD *)v2 + 159) = 0; LOBYTE(v17) = 8; v4 = sub_402BF0((char *)v2 + 640); *((_DWORD *)v2 + 161) = v4; *(_BYTE *)(v4 + 57) = 1; *(_DWORD *)(*((_DWORD *)v2 + 161) + 4) = *((_DWORD *)v2 + 161); **((_DWORD **)v2 + 161) = *((_DWORD *)v2 + 161); *(_DWORD *)(*((_DWORD *)v2 + 161) + 8) = *((_DWORD *)v2 + 161); *((_DWORD *)v2 + 162) = 0; v5 = (int)((char *)v2 + 656); *(_DWORD *)(v5 + 4) = 0; *(_DWORD *)(v5 + 8) = 0; *(_DWORD *)(v5 + 12) = 0; LOBYTE(v17) = 10; *((_DWORD *)v2 + 168) = 0; *((_DWORD *)v2 + 169) = 0; *((_DWORD *)v2 + 170) = 0; AfxGetModuleState(); v6 = AfxGetModuleState(); *((_DWORD *)v2 + 28) = LoadIconA(*((HINSTANCE *)v6 + 3), (LPCSTR)0x80); v7 = operator new(1u); LOBYTE(v17) = 11; if ( v7 ) v8 = sub_401000(v7); else v8 = 0; LOBYTE(v17) = 10; *((_DWORD *)v2 + 149) = v8; *((_BYTE *)v2 + 684) = 0; v9 = operator new(0x10u); if ( v9 ) { *(_DWORD *)v9 = 0; *((_DWORD *)v9 + 1) = 0; *((_DWORD *)v9 + 2) = 0; *((_BYTE *)v9 + 12) = 1; } else { v9 = 0; } *((_DWORD *)v2 + 173) = v9; sub_40AB90(v9); *((_DWORD *)v2 + 172) = 0; v15 = 15; v14 = 0; LOBYTE(v13) = 0; LOBYTE(v17) = 12; sub_4016A0(&unk_431DA8, 4); v16 = 60; sub_4085C0(&v12); sub_4016A0(&unk_431B40, 6); v16 = 270; sub_4085C0(&v12); sub_4016A0(&unk_431C3C, 8); v16 = 90; sub_4085C0(&v12); sub_4016A0("hash值", 6); v16 = 280; sub_4085C0(&v12); sub_4016A0(&unk_431C34, 6); v16 = 90; sub_4085C0(&v12); v10 = v15 < 0x10; *((_DWORD *)v2 + 163) = 8; if ( !v10 ) j__free(v13); return v2; } 可以看到虛表為off_431C50: .rdata:00431C50 off_431C50 dd offset loc_42B8BC ; DATA XREF: sub_409E20+21o .rdata:00431C50 ; sub_40A150+41o .rdata:00431C50 ; Exception filter 1 for function 401990 .rdata:00431C54 dd offset sub_40A440 .rdata:00431C58 dd offset nullsub_4 .rdata:00431C5C dd offset unknown_libname_209 ; MFC 3.1-11.0 32bit .rdata:00431C60 dd offset ?OnFinalRelease@CWnd@@UAEXXZ ; CWnd::OnFinalRelease(void) .rdata:00431C64 dd offset sub_4229A6 .rdata:00431C68 dd offset ?_Get_deleter@_Ref_count_base@std@@UBEPAXABVtype_info@@@Z_6 ; std::_Ref_count_base::_Get_deleter(type_info const &) .rdata:00431C6C dd offset sub_4229AC .rdata:00431C70 dd offset sub_4229AC .rdata:00431C74 dd offset ?GetTypeLib@CCmdTarget@@UAEJKPAPAUITypeLib@@@Z ; CCmdTarget::GetTypeLib(ulong,ITypeLib * *) .rdata:00431C78 dd offset sub_401C60 .rdata:00431C7C dd offset sub_422A0C .rdata:00431C80 dd offset sub_4229BD .rdata:00431C84 dd offset sub_422A06 .rdata:00431C88 dd offset sub_423A14 .rdata:00431C8C dd offset sub_4229C3 .rdata:00431C90 dd offset sub_4229FD 同樣我們只關注很少的一些,OnInitDialog為初始化函數,GetMessageMap可以得到消息響應函數 OnInitDialog做的最重要的一件事為: if ( !sub_401020(*((_DWORD *)v1 + 149)) ) sub_4243C6("無法連入emule網絡", "警告", 0); 而sub_4243C6做的是和上面uninit對應的init,都是dispatch.dll中的 而149對應的變量則在CP2pSearcherDlg構造函數中可以找到蹤跡: v7 = operator new(1u); LOBYTE(v17) = 11; if ( v7 ) v8 = sub_401000(v7); else v8 = 0; LOBYTE(v17) = 10; *((_DWORD *)v2 + 149) = v8; *((_BYTE *)v2 + 684) = 0; v9 = operator new(0x10u); if ( v9 ) { *(_DWORD *)v9 = 0; *((_DWORD *)v9 + 1) = 0; *((_DWORD *)v9 + 2) = 0; *((_BYTE *)v9 + 12) = 1; } else { v9 = 0; } *((_DWORD *)v2 + 173) = v9; sub_40AB90(v9); *((_DWORD *)v2 + 172) = 0; v15 = 15; v14 = 0; LOBYTE(v13) = 0; LOBYTE(v17) = 12; sub_4016A0(&unk_431DA8, 4); v16 = 60; sub_4085C0(&v12); sub_4016A0(&unk_431B40, 6); v16 = 270; sub_4085C0(&v12); sub_4016A0(&unk_431C3C, 8); v16 = 90; sub_4085C0(&v12); sub_4016A0("hash值", 6); v16 = 280; sub_4085C0(&v12); sub_4016A0(&unk_431C34, 6); v16 = 90; sub_4085C0(&v12); v10 = v15 < 0x10; *((_DWORD *)v2 + 163) = 8; if ( !v10 ) j__free(v13); 看完了之后我們知道了真正做的是dispatch.dll中的init和uninit,下面我們再來看消息處理: void ****sub_401C60() { return &off_4316D0; } .rdata:004316D0 off_4316D0 dd offset off_432340 ; DATA XREF: sub_401C60o .rdata:004316D4 dd offset dword_4316D8 .rdata:004316D8 dword_4316D8 dd 113h ; DATA XREF: .rdata:004316D4o .rdata:004316DC dd 0 .rdata:004316E0 dd 0 .rdata:004316E4 dd 0 .rdata:004316E8 dd 11h .rdata:004316EC dd offset OnTimer .rdata:004316F0 dd 112h .rdata:004316F4 dd 0 .rdata:004316F8 dd 0 .rdata:004316FC dd 0 .rdata:00431700 dd 1Bh .rdata:00431704 dd offset OnSysCommand 。。。。。。。。。。。 先來看MFC里的相關知識,來說明這里為何這么做: 我們每添加一個消息,都會在消息映射里增加一條,例如 BEGIN_MESSAGE_MAP(CtestmfcDlg, CDialogEx) ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDOK, &CtestmfcDlg::OnBnClickedOk) ON_NOTIFY(NM_RCLICK, IDC_LIST1, &CtestmfcDlg::OnNMRClickList1) END_MESSAGE_MAP() 而這里的第一行和最后一行為宏,對應GetMessageMap函數和結構體 struct AFX_MSGMAP { const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)(); const AFX_MSGMAP_ENTRY* lpEntries; }; struct AFX_MSGMAP_ENTRY { UINT nMessage; // windows message UINT nCode; // control code or WM_NOTIFY code UINT nID; // control ID (or 0 for windows messages) UINT nLastID; // used for entries specifying a range of control id's UINT_PTR nSig; // signature type (action) or pointer to message # AFX_PMSG pfn; // routine to call (or special value) }; 從這里很顯然的可以看到如何對應上消息響應了。。。。。。。不用解釋了吧 如此,對照前面說的windows消息代碼,結合exescope查看控件id,可以吧004316D8開始的AFX_MSGMAP_ENTRY標注成消息回調函數: OnTimer OnSysCommand OnPaint OnDragIcon OnSearch OnSelectSource OnTcnSelChange OnLvnColumnClick OnNMLVRClickList OnNMTCRClickList OnNMLVDoubleClick OnSize 現在你來告訴我,那些函數最重要?? |
https://www.0xaa55.com/forum.php?mod=viewthread&tid=1390