Zoom Icon

Lezione2 zmaster solution

From UIC Archive

Soluzione lezione 2

Contents


Lezione2 zmaster solution
Author: Zmaster
Email: [email protected]
Website:
Date: 17/09/2008 (dd/mm/yyyy)
Level: Working brain required
Language: Italian Flag Italian.gif
Comments:



Introduzione

Eccomi a fare il mio primo tute… da qualche parte bisogna pure iniziare, perciò ho pensato di farlo dall’inizio :)
Non ho considerazioni particolari da fare, questo primo reversing è molto semplice, immagino che sia stato compilato apposta per facilitare al massimo le cose.
Rileggendo il tute mi è venuto il dubbio di essere stato un po’ prolisso, il motivo è che ho cercato di non dare certe cose per scontate, secondo me chi si avvicina al mondo del reversing spesso ha bisogno di fare “il primo passo” e magari alcune cose è meglio ripeterle piuttosto che ometterle.


Tools

OllyDbg 1.10, beh questo mi sembra ovvio
Stealth64(plug-in di Olly), a me è necessario per poter usare OllyDbg 1.10 su Vista64.


Essay

Dunque, la consegna era di analizzare un po’ più nel dettaglio il funzionamento del programma allegato alla Lezione2, a tale scopo ci viene chiesto di brekkare nel punto di creazione della finestra principale del programma e dare poi un occhio alla DialogProc.

Iniziamo: avviamo Olly e carichiamo lezione2.exe. Olly in pochi istanti carica e analizza il tutto e ci posiziona all’Entry Point del programma, ovvero il punto da cui parte l’esecuzione.
Come richiesto settiamo un break alla chiamata di DialogBoxParam, per fare questo digitiamo nella command line:

bp DialogBoxParamA

e premiamo F9 per avviare l’esecuzione.
Olly brekka subito all’indirizzo 4010C5: 004010B0 /$ 8B4424 04 MOV EAX,DWORD PTR SS:[ESP+4] 004010B4 |. 6A 00 PUSH 0  ; /lParam = NULL 004010B6 |. 68 00104000 PUSH lezione2.00401000  ; |DlgProc = lezione2.00401000 004010BB |. 6A 00 PUSH 0  ; |hOwner = NULL 004010BD |. 6A 6A PUSH 6A  ; |pTemplate = 6A 004010BF |. 50 PUSH EAX  ; |hInst 004010C0 |. A3 B0B64000 MOV DWORD PTR DS:[40B6B0],EAX  ; | 004010C5 |. FF15 E8804000 CALL DWORD PTR DS:[<&USER32.DialogBoxPar>; \DialogBoxParamA 004010CB |. 33C0 XOR EAX,EAX 004010CD \. C2 1000 RETN 10 Notiamo che all’indirizzo 4010B0 è presente un $ che ci indica che si tratta di un indirizzo utilizzato da un CALL , e che dopo più avanti c’è un RET: si tratta rispettivamente di inizio e fine di una funzione. Chi ha preparato il programma per evitarci confusione ha avuto l’accortezza di fare la chiamata all’interno di una funzione e focalizzare la nostra attenzione su quelle poche righe.
Apriamo il menù contestuale con un click destro sulla riga con la CALL e scegliamo “Help on symbolic name” per avere informazioni su cosa fa questa funzione (bisogna aver settato il percorso di win32.hlp) . L’help spiega che la funzione fa apparire una Dialog prendendola dalle risorse del modulo.
Diamo una rapida occhiata agli argomenti che vengono passati attraverso delle PUSH nello stack, Olly ci aiuta scrivendoci nomi e valori nella 4° colonna:

hInst, è l’handle del modulo che serve alla funzione per recuperare la Dialog dalle risorse.
pTemplate = 0x6A, si tratta dell’ID della finestra nelle risorse. Se apriamo l’EXE con ResHack o un altro editor di risorse troveremo solo una finestra con ID 106 (106 == 0x6A).
hOwner = NULL, è l’handle della finestra genitore. Essendo NULL non ha genitore. .
DlgProc, questa è una cosa interessante: è la funzione che si occupa di gestire i messaggi della finestra. E’ qui che tra molto poco andremo a vedere cosa viene fatto..
lParam, è un parametro che viene passato all’init della Dialog, in questo caso non è importante..

Questo lo abbiamo capito nel giro di pochissimo tempo, come sarebbe stato senza gli aiuti di Olly? Ci sarebbe voluto un po’ più tempo… :S Hehe, spesso non ci si rende conto di quanto utile è una cosa finche non ci si trova senza. Mi è venuto in mente perché un paio d’anni fa devo aver provato ad usare Sice e non mi ricordo che fosse tutto così rose e fiori! :)

Ok ok, andiamo avanti. Andiamo all’indirizzo della DlgProc cioè 401000, per fare questo premiamo CTRL+G e inseriamo tale valore. Ecco la nostra funzione: 00401000 . 83EC 2C SUB ESP,2C 00401003 . A1 10A04000 MOV EAX,DWORD PTR DS:[40A010] 00401008 . 33C4 XOR EAX,ESP 0040100A . 894424 28 MOV DWORD PTR SS:[ESP+28],EAX 0040100E . 8B4424 34 MOV EAX,DWORD PTR SS:[ESP+34] 00401012 . 83E8 10 SUB EAX,10  ; Switch (cases 10..111) 00401015 . 8B4C24 30 MOV ECX,DWORD PTR SS:[ESP+30] 00401019 . 74 79 JE SHORT lezione2.00401094 0040101B . 2D 00010000 SUB EAX,100 00401020 . 74 4B JE SHORT lezione2.0040106D 00401022 . 83E8 01 SUB EAX,1 00401025 . 75 76 JNZ SHORT lezione2.0040109D 00401027 . B8 E8030000 MOV EAX,3E8  ; Case 111 (WM_COMMAND) of switch 00401012 0040102C . 66:394424 38 CMP WORD PTR SS:[ESP+38],AX 00401031 . 75 6A JNZ SHORT lezione2.0040109D 00401033 . 6A 14 PUSH 14  ; /Count = 14 (20.) 00401035 . 8D5424 04 LEA EDX,DWORD PTR SS:[ESP+4]  ; | 00401039 . 52 PUSH EDX  ; |Buffer 0040103A . 68 E9030000 PUSH 3E9  ; |ControlID = 3E9 (1001.) 0040103F . 51 PUSH ECX  ; |hWnd 00401040 . FF15 EC804000 CALL DWORD PTR DS:[<&USER32.GetDlgItemTe>; \GetDlgItemTextW 00401046 . 6A 00 PUSH 0  ; /Style = MB_OK|MB_APPLMODAL 00401048 . 68 3C814000 PUSH lezione2.0040813C  ; |Title = "Caption" 0040104D . 8D4424 08 LEA EAX,DWORD PTR SS:[ESP+8]  ; | 00401051 . 50 PUSH EAX  ; |Text 00401052 . 6A 00 PUSH 0  ; |hOwner = NULL 00401054 . FF15 F0804000 CALL DWORD PTR DS:[<&USER32.MessageBoxW>>; \MessageBoxW 0040105A . 33C0 XOR EAX,EAX 0040105C . 8B4C24 28 MOV ECX,DWORD PTR SS:[ESP+28] 00401060 . 33CC XOR ECX,ESP 00401062 . E8 69000000 CALL lezione2.004010D0 00401067 . 83C4 2C ADD ESP,2C 0040106A . C2 1000 RETN 10 0040106D > 6A 00 PUSH 0  ; /Style = MB_OK|MB_APPLMODAL; Case 110 (WM_INITDIALOG) of switch 00401012 0040106F . 68 30814000 PUSH lezione2.00408130  ; |Title = "InitDialog" 00401074 . 68 00A04000 PUSH lezione2.0040A000  ; |Text = "breakpointMe" 00401079 . 6A 00 PUSH 0  ; |hOwner = NULL 0040107B . FF15 F4804000 CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; \MessageBoxA 00401081 . 33C0 XOR EAX,EAX 00401083 . 8B4C24 28 MOV ECX,DWORD PTR SS:[ESP+28] 00401087 . 33CC XOR ECX,ESP 00401089 . E8 42000000 CALL lezione2.004010D0 0040108E . 83C4 2C ADD ESP,2C 00401091 . C2 1000 RETN 10 00401094 > 6A 00 PUSH 0  ; /Result = 0; Case 10 (WM_CLOSE) of switch 00401012 00401096 . 51 PUSH ECX  ; |hWnd 00401097 . FF15 F8804000 CALL DWORD PTR DS:[<&USER32.EndDialog>]  ; \EndDialog 0040109D > 8B4C24 28 MOV ECX,DWORD PTR SS:[ESP+28]  ; Default case of switch 00401012 004010A1 . 33CC XOR ECX,ESP 004010A3 . 33C0 XOR EAX,EAX 004010A5 . E8 26000000 CALL lezione2.004010D0 004010AA . 83C4 2C ADD ESP,2C 004010AD . C2 1000 RETN 10 La funzione è decisamente più corposa della precedente ma tutto sommato non è poi tanto complessa. Se consultiamo win32.hlp alla voce DialogProc ci viene mostrato il prototipo di questa funzione. Non penso che sia il caso di mettersi a descrivere per filo e per segno il funzionamento di windows e dei messaggi alle finestre, questo tutorial riguarda l’uso di Olly. Diciamo solo la cosa più importante: la funzione viene chiamata per processare dei messaggi che vengono inviati in varie circostanze, nel codice c’è uno switch…case che a seconda del tipo esegue operazioni diverse, le istruzioni che saltano ai vari case sono situate tra 401012 e 401025.

In questa DialogProc vengono gestiti 3 messaggi, ognuno dei quali in un case riconosciuto ed evidenziato da Olly che associa al suo codice il nome. A 401027 viene processato WM_COMMAND, questo accade quando si clicca sul pulsante o si eseguono altre azioni sui controlli.
A 40106F viene processato WM_INITDIALOG, questo accade subito dopo la creazione della Dialog e dei suoi controlli, come dice il nome viene utilizzata per inizializzare il valore di questi ultimi.
A 401094 viene processato WM_CLOSE, questo accade premendo la X in cima alla finestra per terminare il programma o premendo ALT+F4.
Mettiamo un break ad ognuno di questi indirizzi con F2 ed eseguiamo il programma con F9 per vedere cosa succede quando vengono gestiti.

Il primo a brekkare è quello relativo a WM_INITDIALOG, come ci si poteva aspettare. Steppando pochi passi vediamo che vengono passati i parametri e chiamata la funzione MessageBoxA, e voilà, la prima messagebox appare! Mmm tutto ciò appare un po’ strano: stiamo creando la finestra principale del programma e invece ci ritroviamo il messaggio. Non doveva apparire PRIMA della finestra principale? E in effetti la finestra principale non è ancora visualizzata: cosa sta succedendo, non è già stata creata?
In effetti si poteva immaginare che la MessageBox fosse visualizzata chiamando l’opportuna API PRIMA della DialogBoxParam, qui invece viene fatto “durante” la chiamata alla DialogBoxParam. Se infatti scorriamo verso il basso lo Stack ci accorgeremo che sono state eseguite una miriade di CALL, ma siamo ancora all’interno di questa funzione, quindi l’esecuzione è stata bloccata dalla MessageBox e non proseguirà finchè l’utente non la chiuderà.
Consultando l’help della DialogBoxParam scopriamo che questa funzione:

  • crea la finestra
  • invia ad essa il messaggio WM_INITDIALOG
  • visualizza la finestra creata ed inizializzata

Quindi ecco quello che succede: la finestra principale viene creata ma non è ancora visibile, viene mandato il messaggio WM_INITDIALOG e quindi viene visualizzata la MessageBox, quando l’utente la chiude l’esecuzione della DialogBoxParam prosegue e la finestra viene finalmente visualizzata.

Il programma è ora in esecuzione, se proviamo a fare qualcosa OllyDbg poppa subito sulla WM_COMMAND. Questo perché questo messaggio viene inviato per varie notifiche, se notiamo le prime tre righe fanno una comparazione ed eventualmente escono subito dal case. Questa comparazione non fa altro che controllare l’ID del controllo oggetto della notifica: significa “se il componente non ci interessa (cioè l’ID non è quello del pulsante) allora ignoralo”. Dato che vogliamo vedere cosa viene fatto premendo il pulsante posizioniamoci subito dopo queste tre istruzioni e riproviamo a scrivere qualcosa nella casella di testo. Questa volta tutto liscio, premiamo Ok ed ecco che Olly poppa! :)
Anche in questo caso è facile vedere quello che viene fatto: viene letto ciò che è stato scritto nella casella di testo con la GetDlgItemTextW e viene generata una MessageBox con lo stesso testo con la MessageBoxW... non occorrerebbe neanche steppare.

Ok, rimandiamo in esecuzione il programma premendo F9. Ora proviamo a chiuderlo premendo il tasto X in alto a destra della finestra: Olly poppa nel case della WM_CLOSE.
Anche qui nulla di particolare, viene chiamata la EndDialog che serve a far chiudere la finestra e a ritornare dalla DialogBoxParam.

In tutti i 3 case (e anche in quello di default, nel quale prosegue l’esecuzione dal case del messaggio WM_CLOSE) c’è una CALL a 4010D0 che è piuttosto misteriosa, a occhio mi verrebbe da dire che riguarda le eccezioni non gestite ma non ne ho ancora ben chiaro il funzionamento, debuggando ho potuto constatare che la funzione ritorna subito perché non viene mai effettuato il salto condizionale a 4010D6: 004010D0 $ 3B0D 10A04000 CMP ECX,DWORD PTR DS:[40A010] 004010D6 . 75 02 JNZ SHORT lezione2.004010DA 004010D8 . F3: PREFIX REP:  ; Superfluous prefix 004010D9 . C3 RETN Ne consegue che la funzione non fa mai nulla ed è come non ci fosse.


Note Finali

Ecco conclusa la mia analisi della DialogProc, si tratta di un caso molto semplice ma che mi ha permesso di provare varie funzionalità di Olly. Non ho ulteriormente divagato per non appesantire il testo dato che le prove che ho fatto non avevano una finalità ben precisa. Tanto per citarne un paio trovo che siano molto utili le funzioni “Follow in Dump/Stack” e “Find references to”.

Colgo l’occasione per ringraziare tutti i docenti e studenti della UIC per dare a tutti quelli come me un “trampolino” da cui partire.


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 malevole 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.