MFC逆向-消息響應函數的定位


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:oModal((CDialog *)&v5);
  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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM