Zoom Icon

Basic MFC Reversing

From UIC

(Redirected from Basis MFC Reversing)


This page has been translated to English Image:Flag uk.gif.

Guide linea al reversing di MFC

Contents


Infos
Author: Pnluck
Email: pnluck@virgilio.it
Website: http://pnluck.netsons.org
Date: 25/08/2008 (dd/mm/yyyy)
Level: Slightly hard
Language: Italian Image:Flag_Italian.gif
Comments: Questo è reversing, non è cracking!



Tools - Riferimenti

IDA
Reversing Microsoft Visual C++ Part II: Classes, Methods and RTTI
Crackme


Prologo: Che cosa è MFC?

Microsoft Foundation Classes, meglio conosciuta con l'acronimo MFC, è una libreria di classi C++ prodotta da Microsoft con lo scopo di incapsulare le Windows API. È definita una classe per ciascun oggetto di Windows dotato di handle, e anche per le finestre predefinite e per i controlli comuni


Introduzione

I programmi scritti con MFC possono importare o no MFC80U.dll (è il nome dell'ultima versione, mentre sto scrivendo, della dll che gestisce MFC), tutto dipende dall' opzione usata per compilare MFC: static library o shared DLL.
In questa guida analizzeremo un programma che importa quella dll e che ha le info per il debug, tutto ciò per facilitarci l'analisi.
Una volta capito come funge MFC, vi sarà più semplice comprendere qualsiasi programma scritto con MFC, anche compilato staticamente: in questo caso basta applicare le signature MFC e VisualC in IDA.


Essay

Inizio col mostrarvi una parte di source, di un programma scritto solo col C:

LRESULT CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
        switch(uMsg)
        {
        case WM_COMMAND:
                switch(LOWORD(wParam))
                {

                case IDC_ABOUT:
                        DialogBoxParam(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG1), NULL, (DLGPROC)MainDialogProc, 0);
                        break;
                       
                        // ...
                }
        }
}

Ed ecco l'equivalente in MFC:

class CAboutDlg : public CDialog
{
public:
        CAboutDlg();

// Dialog Data
        enum { IDD = IDD_ABOUTBOX };

protected:
        virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
        DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)  //al costruttore viene passato l'ID della dialog
                                                                                                  //presente nel resource file
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
        CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) //Mappa dei messaggi della dialog: e' tipo la DialogProc della Dialog.
END_MESSAGE_MAP()

// App command to run the dialog
void CProvaRevApp::OnAppAbout()
{
        CAboutDlg aboutDlg;
        aboutDlg.DoModal();
}

Come potete immaginare il disasm di un programma sviluppato con MFC è pò più complesso da analizzare.

Il Main di MFC

Il disasm del main si presenta in questo modo:

.text:00401CBB                 public start
.text:00401CBB                 call    ___security_init_cookie
.text:00401CC0                 jmp     ___tmainCRTStartup

.text:004019FB ___tmainCRTStartup proc near            ; CODE XREF: start+5�j
.text:004019FB
.text:004019FB                 push    5Ch
.text:004019FD                 push    offset unk_403DD8
.text:00401A02                 call    __SEH_prolog4
;... altro codice di inizializzazione
.text:00401B3E                 push    ecx             ; nShowCmd
.text:00401B3F                 push    eax             ; lpCmdLine
.text:00401B40                 push    ebx             ; hPrevInstance
.text:00401B41                 push    400000h         ; hInstance
.text:00401B46                 call    _wWinMain@16    ; wWinMain(x,x,x,x)

; int __stdcall wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)
_wWinMain@16 proc near
        jmp     ?AfxWinMain@@YGHPAUHINSTANCE__@@0PA_WH@Z ; AfxWinMain(HINSTANCE__ *,HINSTANCE__ *,wchar_t *,int)
_wWinMain@16 endp

Come vedete la funzione WinMain non fa altro che chiamare AfxWinMain. Se avete il VisualStudio potete vedere il source di MFC, qui vi riporto solo le funzioni necessarie.

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        _In_ LPTSTR lpCmdLine, int nCmdShow)
{
        ASSERT(hPrevInstance == NULL);

        int nReturnCode = -1;
        CWinThread* pThread = AfxGetThread();
        CWinApp* pApp = AfxGetApp();

        // AFX internal initialization
        if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
                goto InitFailure;

        // App global initializations (rare)
        if (pApp != NULL && !pApp->InitApplication())
                goto InitFailure;

        // Perform specific initializations
        if (!pThread->InitInstance())
        {
                if (pThread->m_pMainWnd != NULL)
                {
                        TRACE(traceAppMsg, 0, "Warning: Destroying non-NULL m_pMainWnd\n");
                        pThread->m_pMainWnd->DestroyWindow();
                }
                nReturnCode = pThread->ExitInstance();
                goto InitFailure;
        }
        nReturnCode = pThread->Run();

InitFailure:
        AfxWinTerm();
        return nReturnCode;
}

Ora vi mostro il disasm di questa funzione

.text:7831D2D2                 public AfxWinMain
.text:7831D2D2 AfxWinMain      proc near
.text:7831D2D2                 push    ebx
.text:7831D2D3                 push    esi
.text:7831D2D4                 push    edi
.text:7831D2D5                 or      ebx, 0FFFFFFFFh
.text:7831D2D8                 call    AfxGetModuleThreadState
.text:7831D2DD                 mov     esi, [eax+4] ;pThread
.text:7831D2E0                 call    AfxGetModuleState
.text:7831D2E5                 push    [esp+0Ch+arg_C]
.text:7831D2E9                 mov     edi, [eax+4]  ;pApp
.text:7831D2EC                 push    [esp+10h+arg_8]
.text:7831D2F0                 push    [esp+14h+arg_4]
.text:7831D2F4                 push    [esp+18h+arg_0]
.text:7831D2F8                 call    AfxWinInit
.text:7831D2FD                 test    eax, eax
.text:7831D2FF                 jz      short loc_7831D33D
.text:7831D301                 test    edi, edi    
.text:7831D303                 jz      short loc_7831D313
.text:7831D305                 mov     eax, [edi]
.text:7831D307                 mov     ecx, edi
.text:7831D309                 call    dword ptr [eax+98h]
.text:7831D30F                 test    eax, eax
.text:7831D311                 jz      short loc_7831D33D
.text:7831D313
.text:7831D313 loc_7831D313:
.text:7831D313                 mov     eax, [esi]
.text:7831D315                 mov     ecx, esi
.text:7831D317                 call    dword ptr [eax+58h]
.text:7831D31A                 test    eax, eax
.text:7831D31C                 jnz     short loc_7831D334
.text:7831D31E                 cmp     [esi+20h], eax
.text:7831D321                 jz      short loc_7831D32B
.text:7831D323                 mov     ecx, [esi+20h]
.text:7831D326                 mov     eax, [ecx]
.text:7831D328                 call    dword ptr [eax+68h]
.text:7831D32B
.text:7831D32B loc_7831D32B:
.text:7831D32B                 mov     eax, [esi]
.text:7831D32D                 mov     ecx, esi
.text:7831D32F                 call    dword ptr [eax+70h]
.text:7831D332                 jmp     short loc_7831D33B
.text:7831D334
.text:7831D334 loc_7831D334:
.text:7831D334                 mov     eax, [esi]
.text:7831D336                 mov     ecx, esi
.text:7831D338                 call    dword ptr [eax+5Ch]
.text:7831D33B
.text:7831D33B loc_7831D33B:  
.text:7831D33B                 mov     ebx, eax
.text:7831D33D
.text:7831D33D loc_7831D33D:
.text:7831D33D                 call    AfxWinTerm
.text:7831D342                 pop     edi
.text:7831D343                 pop     esi
.text:7831D344                 mov     eax, ebx
.text:7831D346                 pop     ebx
.text:7831D347                 retn    10h
.text:7831D347 AfxWinMain      endp

Come vedete ci sono molte call del tipo call [eax+XXh], infatti con la chiamata a AfxGetApp (e AfxGetThread), ritorna un puntatore ad una struttura che contiene l'offset di tutte le funzioni usate da MFC.
Nel caso del programma che sto analizzando, edi (pApp) è 405498, ed a quest'indirizzo troviamo un valore, che non è altro l'offset a 40349C, e lì si trova proprio un' istanza statica, la virtual functions table, di CWinApp:

.rdata:0040349C off_40349C      dd offset ?GetRuntimeClass@CWinApp@@UBEPAUCRuntimeClass@@XZ ;CWinApp::GetRuntimeClass(void)
.rdata:004034A0                 dd offset sub_401010
.rdata:004034A4                 dd offset nullsub_1
.rdata:004034A8                 dd offset nullsub_2
.rdata:004034AC                 dd offset nullsub_1
.rdata:004034B0                 dd offset ?OnCmdMsg@CCmdTarget@@UAEHIHPAXPAUAFX_CMDHANDLERINFO@@@Z ; CCmdTarget::OnCmdMsg(uint,int,void *,AFX_CMDHANDLERINFO *)
.rdata:004034B4                 dd offset ?OnFinalRelease@CCmdTarget@@UAEXXZ ; CCmdTarget::OnFinalRelease(void)
.rdata:004034B8                 dd offset ?IsInvokeAllowed@CCmdTarget@@UAEHJ@Z ; CCmdTarget::IsInvokeAllowed(long)
.rdata:004034BC                 dd offset ?GetDispatchIID@CCmdTarget@@UAEHPAU_GUID@@@Z ; CCmdTarget::GetDispatchIID(_GUID *)
.rdata:004034C0                 dd offset ?GetTypeInfoCount@CCmdTarget@@UAEIXZ ; CCmdTarget::GetTypeInfoCount(void)
.rdata:004034C4                 dd offset ?GetTypeLibCache@CCmdTarget@@UAEPAVCTypeLibCache@@XZ ; CCmdTarget::GetTypeLibCache(void)
.rdata:004034C8                 dd offset ?GetTypeLib@CCmdTarget@@UAEJKPAPAUITypeLib@@@Z ; CCmdTarget::GetTypeLib(ulong,ITypeLib * *)
.rdata:004034CC                 dd offset sub_401000
;.......................................................

Spero che a questo punto vi sorga una curiosità: da dove ricava quell'indirizzo? Analizzando i riferimenti con IDA...

.text:004023B0 sub_4023B0      proc near              
.text:004023B0                 push    0
.text:004023B2                 mov     ecx, offset dword_405498
.text:004023B7                 call    ??0CWinApp@@QAE@PB_W@Z ; CWinApp::CWinApp(wchar_t const *)
.text:004023BC                 push    offset sub_4023F0 ; void (__cdecl *)()
.text:004023C1                 mov     dword_405498, offset off_40349C ;<-- ecco il nostro offset
.text:004023CB                 call    _atexit
.text:004023D0                 pop     ecx
.text:004023D1                 retn
.text:004023D1 sub_4023B0      endp

E l'offset di questa funzione è presenta in una struttura

.rdata:00403304 unk_403304      db    0    
.rdata:00403305                 db    0
.rdata:00403306                 db    0
.rdata:00403307                 db    0
.rdata:00403308                 dd offset _pre_cpp_init
.rdata:0040330C                 dd offset ??__E_afxInitAppState@@YAXXZ ; `dynamic initializer for '_afxInitAppState''(void)
.rdata:00403310                 dd offset sub_4023B0

che viene passata alla funzione __initterm, chiamata prima del WinMain

.text:00401AAC                 push    offset unk_403314
.text:00401AB1                 push    offset unk_403304
.text:00401AB6                 call    _initterm

Dopo questo breve excursus, ritorniamo ad analizzare AfxWinMain:
vedendo la tabella si capisce che call dword ptr [eax+98h] (40349C + 98 = 00403534) non fa altro che chiamare

.text:00403534                 dd offset ?InitApplication@CWinApp@@UAEHXZ ; CWinApp::InitApplication(void)

Mentre call dword ptr [eax+58h], che sarebbe pThread->InitInstance, invece chiama la funzione:

.rdata:004034F4                 dd offset sub_401030

Questa call non fa altro che far apparire la Dialog del programma, ecco la parte principale di codice:

.text:00401030 sub_401030      proc near  
.text:00401030                 push    ebp
.text:00401031                 mov     ebp, esp
;..........................................................................
.text:0040109F                 call    sub_401130
;--------------------------------------------------------------------------
;entrato nella call
.text:00401155                 push    0               ; lpIconName
.text:00401157                 push    66h             ; ID della Dialog da caricare
.text:00401159                 mov     ecx, esi
.text:0040115B                 call    ??0CDialog@@QAE@IPAVCWnd@@@Z ; CDialog::CDialog(uint,CWnd *)
.text:00401160                 mov     [esp+14h+var_4], 0
.text:00401168                 mov     dword ptr [esi], offset off_403744 ;virtual functions table offset che viene salvato
; in CDialog.DoModal -> CDialog__PreModal -> AfxHookWindowCreate  
.text:0040116E                 call    ?AfxGetModuleState@@YGPAVAFX_MODULE_STATE@@XZ ; AfxGetModuleState(void)
;esco dalla call
;---------------------------------------------------------------------------
.text:004010A4                 lea     edx, [esp+8+arg_4]
.text:004010A8                 mov     [esp+8+arg_88], 0
.text:004010B3                 mov     ecx, edx
.text:004010B5                 mov     [esi+20h], edx
.text:004010B8                 call    ?DoModal@CDialog@@UAEHXZ ; CDialog::DoModal(void)
.text:004010BD                 lea     ecx, [esp+8+arg_4]
.text:004010C1                 mov     [esp+8+arg_88], 0FFFFFFFFh
.text:004010CC                 call    ??1CDialog@@UAE@XZ ; CDialog::~CDialog(void)
;..........................................................................
.text:004010E3                 mov     esp, ebp
.text:004010E5                 pop     ebp
.text:004010E6                 retn

Ricaviamo la MESSAGE_MAP

Ora dobbiamo capire dove è MESSAGE_MAP: essa viene ricavata in

BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
     // ....
     const AFX_MSGMAP* pMessageMap;
     pMessageMap = GetMessageMap();
     // ....
          if ((lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries, message, 0, 0)) != NULL)
     // ...
 
}

Ecco a voi il disasm

.text:78312E91                 mov     eax, [edi] ; eax = 403744
.text:78312E93                 mov     ecx, edi
.text:78312E95                 call    dword ptr [eax+30h] ; eax+30h = 00403774, sarebbe a dire GetMessageMap()
;.rdata:00403774                 dd offset sub_4011E0
;...................................................................
.text:78312F1B                 push    0
.text:78312F1D                 push    0
.text:78312F1F                 jnb     short loc_78312F67
.text:78312F21                 push    [ebp+arg_0] ;messagge
.text:78312F24                 push    dword ptr [esi+4] ; lpEntries (in questo caso 0040362C)
.text:78312F27                 call    AfxFindMessageEntry

La call in 78312E95 chiama:

;GetMessageMap()
.text:004011E0                 mov     eax, offset off_403628 ;eax = pMessageMap
.text:004011E5                 retn
;----------------------------------------------------------------
;pMessageMap
.rdata:00403628 off_403628      dd offset ?GetThisMessageMap@CDialog@@KGPBUAFX_MSGMAP@@XZ
.rdata:00403628                                         ; CDialog::GetThisMessageMap(void)
.rdata:0040362C                 dd offset unk_403580 ;pMessageMap->lpEntries

Ed a 403580 c'è proprio MESSAGE_MAP per la dialog.

Quindi possiamo ricavare la MessageMap velocemente in questo modo:

  1. Cerchiamo prima di CDialog:DoModal un mov dword ptr [esi], offset off_XXXXXX (serve a caricare la virtual functions table).
  2. Aggiungiamo a quell'offset 0x30 per trovare la funzione GetMessageMap: andate nella funzione e troverete un mov eax, offset off_XXXXXX, dove eax è pMessageMap
  3. Aggiungete a pMessageMap 4, e troverete la MESSAGE_MAP della Dialog



Ora vi mostro come funziona: ecco a voi il resource della dialog che ho preso in esame:

CONTROL "Register", 1006, BUTTON, //1006 = 0x3ee
CONTROL "About", 1007, BUTTON, //1007 = 0x3ef
CONTROL "Cancel", 1008, BUTTON, //1008 = 0x3f0


Ed ora vi mostro la MESSAGE_MAP, che non è altro un array di strutture
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)
};


.rdata:00403580 MESSAGE_MAP    dd 112h                
.rdata:00403584                 dd 0
.rdata:00403588                 dd 0
.rdata:0040358C                 dd 0
.rdata:00403590                 dd 1Eh
.rdata:00403594                 dd offset sub_4012D0

.rdata:00403598                 dd 0Fh
.rdata:0040359C                 dd 0
.rdata:004035A0                 dd 0
.rdata:004035A4                 dd 0
.rdata:004035A8                 dd 13h
.rdata:004035AC                 dd offset sub_401370

.rdata:004035B0                 dd 37h
.rdata:004035B4                 dd 0
.rdata:004035B8                 dd 0
.rdata:004035BC                 dd 0
.rdata:004035C0                 dd 28h
.rdata:004035C4                 dd offset sub_401450

.rdata:004035C8                 dd 111h
.rdata:004035CC                 dd 0
.rdata:004035D0                 dd 3EFh  
.rdata:004035D4                 dd 3EFh  
.rdata:004035D8                 dd 38h
.rdata:004035DC                 dd offset sub_401460

.rdata:004035E0                 dd 111h
.rdata:004035E4                 dd 0
.rdata:004035E8                 dd 3F0h  
.rdata:004035EC                 dd 3F0h
.rdata:004035F0                 dd 38h
.rdata:004035F4                 dd offset sub_4014F0

.rdata:004035F8                 dd 111h
.rdata:004035FC                 dd 0
.rdata:00403600                 dd 3EEh  
.rdata:00403604                 dd 3EEh
.rdata:00403608                 dd 38h
.rdata:0040360C                 dd offset sub_401510

.rdata:00403610                 dd 0
...

Come vedete per ogni evento è stata creata un struttura, nella quale vengono memorizzati gli ID della window, se presenti, con la funzione associata.

IDC Script

Per semplificare l'analisi della struttura ho fatto un piccolo IDC script per IDA

// mfc_message_map.idc version 0.2 by Pnluck 2008
#include <idc.idc>

//non tutti i WM_ vengono identificati
static messageName(ptr, message) {
       
        if(message == 1) // WM_CREATE
                MakeComm(ptr, "WM_CREATE");
        else if(message == 2) // WM_DESTROY
                MakeComm(ptr, "WM_DESTROY");
        else if(message == 5) // WM_SIZE
                MakeComm(ptr, "WM_SIZE");
        else if(message == 0x10) // WM_CLOSE
                MakeComm(ptr, "WM_CLOSE");
        else if(message == 0x18) // WM_SHOWWINDOW
                MakeComm(ptr, "WM_SHOWWINDOW");
       
        else if(message == 0x0100) // WM_KEYDOWN
                MakeComm(ptr, "WM_KEYDOWN");
        else if(message == 0x0101) // WM_KEYUP
                MakeComm(ptr, "WM_KEYUP");
        else if(message == 0x0102) // WM_CHAR
                MakeComm(ptr, "WM_KEYCHAR");
       
        else if(message == 0x0110) // WM_INITDIALOG
                MakeComm(ptr, "WM_INITDIALOG");
        else if(message == 0x0111) // WM_COMMAND
                MakeComm(ptr, "WM_COMMAND");
        else if(message == 0x0112) // WM_SYSCOMMAND
                MakeComm(ptr, "WM_SYSCOMMAND");
        else if(message == 0x0113) // WM_TIMER
                MakeComm(ptr, "WM_TIMER");
        else if(message == 0x0116) // WM_INITMENU
                MakeComm(ptr, "WM_INITMENU");
        else if(message == 0x0117) // WM_INITMENUPOPUP
                MakeComm(ptr, "WM_INITMENUPOPUP");
        else if(message == 0x0126) // WM_MENUCOMMAND
                MakeComm(ptr, "WM_MENUCOMMAND");

}
static DefineStruct() {
        auto idStruct;
       
        idStruct = AddStrucEx(-1,"AFX_MSGMAP_ENTRY",0);
        if(idStruct == 0) return 0;
       
        if(AddStrucMember(idStruct, "nMessage", 0, FF_DWRD|FF_DATA, -1, 4) != 0) {
                Warning("\n1\n");
                DelStruc(idStruct);
                return 0;
        }
       
        if(AddStrucMember(idStruct, "nCode", 4, FF_DWRD|FF_DATA, -1, 4) != 0) {
                Warning("\n2\n");
                DelStruc(idStruct);
                return 0;
        }
       
        if(AddStrucMember(idStruct, "nID", 8, FF_DWRD|FF_DATA, -1, 4) != 0) {
                Warning("\n3\n");
                DelStruc(idStruct);
                return 0;
        }
       
        if(AddStrucMember(idStruct, "nLastID", 12, FF_DWRD|FF_DATA, -1, 4) != 0) {
                Warning("\n4\n");
                DelStruc(idStruct);
                return 0;
        }
       
        if(AddStrucMember(idStruct, "nSignature", 16, FF_DWRD|FF_DATA, -1, 4) != 0) {
                Warning("\n5\n");
                DelStruc(idStruct);
                return 0;
        }
       
        if(AddStrucMember(idStruct, "pFunction", 20, FF_DWRD|FF_0OFF, -1, 4) != 0) {
                Warning("\n6\n");
                DelStruc(idStruct);
                return 0;
        }
       
        return idStruct;
}

static GenerateMFCMap(addr) {
        auto idStruct, ptr, message, isOk;
       
        idStruct = GetStrucIdByName("AFX_MSGMAP_ENTRY");
        if( idStruct == -1) {
                idStruct = DefineStruct();
                if(idStruct == 0) {
                        Warning("\nImpossible declare the structure\n");  
                        return;
                }
        }
       
        ptr = addr;
        isOk = 1;
       
        while( Dword(ptr) != 0) {
                if(MakeStructEx(ptr, 24, "AFX_MSGMAP_ENTRY") == 0) {
                        isOk = 0;
                        break;
                }
                                messageName(ptr,Dword(ptr));
                               
                ptr = ptr + 24;
        }
               
        if(isOk == 0) {
                Warning("\nImpossible set the structure at %x\n", addr);
        } else {
                Message("Complete");
        }
       
        return;
}

Ecco lo script applicato alla MessageMap precedente

.rdata:00403580 stru_403580     AFX_MSGMAP_ENTRY <112h, 0, 0, 0, 1Eh, offset sub_4012D0> ; WM_SYSCOMMAND
.rdata:00403580                                         ; DATA XREF: .rdata:0040362C�o
.rdata:00403598                 AFX_MSGMAP_ENTRY <0Fh, 0, 0, 0, 13h, offset sub_401370>
.rdata:004035B0                 AFX_MSGMAP_ENTRY <37h, 0, 0, 0, 28h, offset sub_401450>
.rdata:004035C8                 AFX_MSGMAP_ENTRY <111h, 0, 3EFh, 3EFh, 38h, offset sub_401460> ; WM_COMMAND
.rdata:004035E0                 AFX_MSGMAP_ENTRY <111h, 0, 3F0h, 3F0h, 38h, offset sub_4014F0> ; WM_COMMAND
.rdata:004035F8                 AFX_MSGMAP_ENTRY <111h, 0, 3EEh, 3EEh, 38h, offset sub_401510> ; WM_COMMAND
.rdata:00403610                 db    0

Catturiamo WM_COMMAND

La gestione del messaggio WM_COMMAND è affidata alla funzione BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo), ma più esattamente a _AfxDispatchCmdMsg.
Infatti se settiamo un bp sull'entry della funzione (7833B515 nel mio caso), potete notare che appena premete su un pulsante o su un menù, il debugger ferma l'esecuzione, e steppando potremo arrivare comodamente alla funzione che gestisce quel determinato evento, senza dover ricavare MESSAGE_MAP.



Note Finali

Ringrazio calorosamente la M$ per MFC (una cosa più semplice da reversare no??), e poi Nt, EvilCry, Que, emdel ed ocean che ho incontrato al MOCA 08 dove c'era anche John T. Draper aka Captain Crunch (mitiko!!!), e tutta la ciurmaglia di IRC.
Pnluck


Disclaimer

I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.

Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevoli e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.