Undicesimo Corso Newbies |
||
Data |
by "AndreaGeddon" |
|
04/02/2002 |
Published by Quequero |
|
three
four shut the door |
Da quanto tempo non venivo a romperti nel tuo spazio riservato!! hihihihihi :-P Eh...Gioca con il fuoco tu che un giorno ti bruci hihihihi intanto gia siamo partiti col cervello che non devi avere in buono stato visti i colori very-psichedelici che usi per IDA dhe hi hi :P |
five six pick up sticks seven eight let them straight |
.... |
|
.... |
Difficoltà |
(x)NewBies ( )Intermedio ( )Avanzato ( )Master |
|
Tutti i newbies spesso si rifiutano di passare a Ida, quindi eccovi un corso in cui sarete costretti a usarlo! Infatti con il WDasm non riuscirete a disassemblarlo, e comunque vediamo come usare Ida per risolvere facilmente questo crackme.
Introduzione |
Tools usati |
URL o FTP del programma |
Notizie sul programma |
Essay |
Niente patching, quindi mano al disassemblatore e vediamo cosa dobbiamo fare. Come già detto WinDasm è inutile, quindi mano a Ida perchè se non lo conoscete è ora di imparare a usarlo! Innanzitutto come riferimento potete leggere il megatutorial su Ida scritto da Que, davvero completissimo e semplice. Io sto usando la versione 4.17, ma va bene anche qualsiasi versione precedente. Let's start.
Piccola Introduzione
Quando scegliete di aprire l'undicesimo corso vi verrà chiesto se aprirlo come PE, come normale exe (MZ) o come file binario. Voi ovviamente scegliete PE. Le altre opzioni non sono fondamentali, ma se volete conoscerle leggete il tute di Que. Bene fatelo disassemblare. Come vedete anche se il crackme è piccolo ci mette più tempo del Wdasm, e questo già è indice di tutto il lavoro di analisi che viene fatto! Quando Ida avrà finito il semaforino in alto a destra sarà verde e nella log window vi scriverà:
The initial autoanalysis is finished.
A questo punto dovrebbe avervi messo già sul corpo della WinMain (che in questo prog sta all'indirizzo 00401000). Ma vediamo un pò di esaminare a fondo la cosa. Andiamo all'entry point. Menu Jump->Jump to entry point. Vi verrà mostrata una finestra che contiene un solo entry point, se disassemblate una dll gli entry point saranno molti, uno per ogni export :-). Bene ora che siete all'entry point (riga 00401630) potete vedere il codice della funzione WinMain (non il corpo, ma la funzione stessa). Facciamo un pò di teoria su come funziona una applicazione scritta in C. Ogni applicazione ha la sua procedura WinMain, definita come:
int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // pointer to command line
int nCmdShow // show state of window
);
il programma che viene scritto dal programmatore inizia DENTRO la win main, cioè nel punto in cui Ida ci aveva portato all'inizio (00401000), ma l'entry point vero e proprio parte dal codice della WinMain, cioè quel codice che si occupa di chiamare la linea 00401000 e di fornire i quattro parametri (oltre a fare vari lavori di inizializzazione dell'heap etc etc). Potete vedere come quasi tutte le call hanno un nome, tipo
.text:004016D7
call __setargv |
in quanto ida le riconosce e le identifica come costrutti standard. Già questo
aiuta molto. Scorrete un pò il codice in basso fino alla riga
.text:0040176A call _WinMain@16 |
ed ecco la call che vi porterà al codice vero e proprio che il programmatore ha scritto. Tutto questo finora non c'entrava nulla col crackme, perchè ci perdiamo tempo? Beh perchè la maggior parte dei programmi viene scritta in C, quindi quando li steppate dall'inizio è inutile perdervi nelle inizializzazioni della WinMain, andate direttamente alla chiamata alla WinMain che sta sempre dopo GetModuleHandle. Infatti:
.text:0040175D
push eax ; nCmdShow |
come vedete Ida vi risolve anche i parametri della WinMain! E questo per tutte le api supportate, quindi la vita diventa moolto più semplice. Okei finita questa parentesi introduttiva passiamo al crackme vero e proprio.
Iniziamo il lavoro
Alla riga 0040176A cliccate due volte sulla _WinMain@16 e verrete mandati direttamente alla riga della funzione stessa. Un pò come premere "destra" in windasm. Okei ora la prima cosa da fare è rintracciare la MessageBox che ci dà l'errore e capire che cosa viene controllato per poterci registrare. Come al solito cerchiamo la stringa di errore. Ora quasi tutti lamentano problemi con Ida perchè non sanno trovare le string reference. A parte alcuni plugin che io non trovo granchè utili, le string ref in Ida ci sono :-). Andate nel menu View e da lì a seconda della versione o avete direttamente nel menu la voce "Names" o la trovate nel sottomenu "Open SubViews". Vi si aprirà una finestra contenente tutte le stringhe del programma, siano esse stringhe, funzioni importate, esportate o interne! Nella lista avete alla sinistra di ogni stringa l'icona di una lettera che ne identifica il tipo, ad esempio "A" sta per le stringhe, "I" sta per le funzioni importate, "L" per le funzioni locali etc etc. Quindi dobbiamo controllare le stringhe di tipo A. Avrete già notato che abbiamo a disposizione un "search", quindi cerchiamo "Registration" e nella finestra names avrete selezionata la stringa. Notate che ida alle stringhe aggiunge una "a" davanti, se volete queste opzioni posso essere modificate. Due righe sopra sRegistration abbiamo la stringa aNonRegistrato, Ida toglie anche gli spazi quindi quando cercate le stringhe ricordatevi di questi particolari! Cmq doppio click sulla stringa aNonRegistrato e verrete portati alla riga 0040502C. Questa riga è nella sezione dati, infatti vedete lì intorno tutte le altre stringhe etc etc. Ora come facciamo a trovare il codice che si riferiva alla stringa di non registrazione? Con le xref!
.data:0040502C aNonRegistrato db 'Non registrato!',0 ; DATA XREF: .text:004012E0 |
vedete quel DATA XREF? ci dice da quali righe viene chiamata la stringa in questione. In questo caso il programma è piccolo e le xref sono poche, di solito le xref di un dato sono molte per cui abiutuatevi a cercare direttamente nell'apposita xref window. La trovate nello stesso menu in cui avete trovato la voce "Names", si chiama "Cross references". Si aprirà la finestra e avrete la lista di tutte le xref per la linea che avete selezionato. In questo caso c'è una sola reference, doppio cliccateci sopra e ida vi porterò alla riga 004012E0. Vediamo un pò il codice lì intorno:
.text:004012A5
cmp word_0_407580, 1Fh |
il JNZ decide se mandargi alla registrazione oppure no, quindi il compare precedente (riga 004012A5) deve essere quello che controlla la registrazione. Notate che quando siete su una riga potete premere ";" o ":" per inserire i vostri commenti nel codice! Così se volete appuntarvi delle note potete farlo! Ma torniamo a noi: per registrarsi il programma ha bisogno che la word all'indirizzo 00407580 sia uguale a 1Fh. Quando avviene ciò? Di nuovo ricorreremo alle xref per vedere in quali punti il codice agisce su quella variabile, ma prima facilitiamoci la vita: Ida permette di rinominare praticamente tutto, quindi rinominiamo la variabile in "Chiave", socì si sarà più facile la lettura del codice. Per rinominare la variabile potete o cliccare col tasto destro sulla word_0_407580 e scegliere rename, oppure doppioclick sulla word e ida vi porterà alla riga 00407580, a quel punto rinominate l'address. Il renaming dipende dalle versioni. Cmq dopo che avrete rinominato la variabile la precedente riga vi apparirà così:
.text:004012A5 cmp Chiave, 1Fh |
suona meglio vero? Ora come prima andiamo alla riga 00407580 (quella della var Chiave) e da lì scegliamo xref.
| Direction | Type | Address | Instruction |
| Up | w | text.00401069 | or byte ptr Chiave, 10h |
| Up | w | text.00401108 | or byte ptr Chiave, 02 |
| Up | w | text.00401126 | or byte ptr Chiave, 01 |
| Up | w | text.00401225 | or byte ptr Chiave, 04 |
| Up | r | text.004012A5 | cmp Chiave, 1Fh |
| Up | w | text.00401462 | or byte ptr Chiave, 08 |
et voilà! Praticamente già da qui si capisce molto. Il tipo di xref indica r = read oppure w = write, in questo caso in r abbiamo solo la xref corrispondente al cmp, tutti gli altri sono w. Ora notate che 1 + 2 + 4 + 8 + 10h = 1Fh, quindi il cmp controlla se tutti i cinque flag sono attivi nella word:
bin 00000001 = hex 01
bin 00000010 = hex 02
bin 00000100 = hex 04
bin 00001000 = hex 08
bin 00010000 = hex 10
tutte le istruzioni OR di ogni xref corrispondono appunto all'attivazione del flag stesso, e ovviamente ognuno di questi flag dovrà corrispondere a un requisito occorrente alla registrazione. Quindi analizziamo tutte le xref. Partiamo dalla prima.
Il primo trick
.text:0040104A push
0
; hTemplateFile |
il CreateFileA sembra decidere l'attivazione del flag. Analizziamo quindi i parametri della chiamata: come vedete ida in automatico mette il commento ad ogni parametro così da non dover sempre correre sulla reference :-). I parametri = 0 non ci interessano, prendiamo quelli usati:
dwFlagsAttributes = FILE_FLAG_DELETE_ON_CLOSE (valore numerico: 4000000h)
lpFileName = .data:00405020 a_Siwvid db '\\.\siwvid',0 (mmm driver del softice!)
avete capito ora? Questo è un banalissimo MeltIce! FFFFFFFFh è il valore numerico di INVALID_HANDLE_VALUE, quindi viene tentata l'apertura del driver del softice, se l'apertura avviene allora il driver è presente (e quindi anche il softice) e quindi CreateFile restituirà un handle valido in EAX che sarà diverso da FFFFFFFFh, per cui il flag non viene attivato. Se invece il CreateFile fallisce allora non è riuscita l'apertura del driver, quindi il softice non c'è e il flag viene attivato. Quindi per risolvere questo primo trick basta o non avere softice caricato, o se avete softice basta usare FrogSice o IceDump per nasconderlo.
Il secondo trick
Vediamo ora il secondo trick:
.text:004010E8 lea ecx, [esp+2Ch] .text:004010EC
push ecx
; phkResult |
stavolta ida non mette i commenti in automatico, li ho aggiunti io per semplicità. Innanzitutto stavolta vediamo che l'attivazione del flag è decisa dal buon esito dell'apertura di una chiave del registro. Analizziamo i parametri di RegOpenKeyEx:
hKey = 80000001h = HKEY_CURRENT_USER (ramo predefinito del registro)
lpSubKey = offset aUic = stringa "UIC" (nome della sottochiave)
samDesired = F003Fh = KEY_ALL_ACCESS
phkResult = buffer che conterrà l'handle della chiave aperta.
quindi viene aperta la chiave
HKEY_CURRENT_USER -> UIC
se la chiave è trovata il flag è attivato, altrimenti nisba. Per cui per risolvere questo secondo trick vi basta creare la suddetta sottochiave (non valore, CHIAVE!) e avrete risolto.
Il terzo trick
.text:0040111B
cmp word_0_407568, 7CDh .text:0040112D call sub_0_401440 |
stavolta le cose sono un pò più complicate: come vedete c'è solo un CMP, niente funzioni o altro. Come fare allora? Semplice, rimettiamo mano alle xref! Infatti il test decisivo è il CMP tra word_0_407568 e 7CDh. Quindi prendiamo le xref della word in questione: troverete una xref che vi porta al compare appena visto e una che vi porta a 00401006:
.text:00401000 sub esp,
1Ch |
okey quindi l'offset 00407568 è l'offset di una struttura di tipo SYSTEMTIME che viene riempita dall'apposita api GetSystemTime. Ma viene controllata tutta la struttura? No.
typedef struct _SYSTEMTIME { // st
WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;
} SYSTEMTIME;
il CMP che a noi interessa è sulla WORD puntata da 00407568, cioè della prima word della struttura che appunto è rappresentata dal campo SYSTEMTIME.wYear. Quindi il CMP interessato adesso lo vediamo così:
CMP SYSTEMTIME.wYear, 1997dec (7CDhex)
a questo punto è chiaro che viene controllato se l'anno in corso è il 1997. Se siamo nel 1997 il flag viene attivato, quindi per superare questo trick mettete indietro la data del clock di win :-)
Il quarto trick:
Questo è semplicissimo:
.text:00401217
call ds:IsZoomed |
IsZoomed controlla se la finestra è massimizzata, in tal caso restituisce nonzero. Se invece restituisce zero il JZ ci fa evitare l'attivazione del flag, per cui è necessario massimizzare la finestra per evitare questo trick.
Il quinto ed ultimo trick
|
.text:00401440 push
0
; hTemplateFile |
ecco un altro CreateFile. Stavolta niente controlli su driver, analizziamo i parametri:
dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL
dwCreationDisposition = OPEN_EXISTING
dwDesiredAccess = GENERIC_READ
plFileName = "c:\geddon.uic"
come prima viene tentata l'apertura del file c:\geddon.uic. Se il file è trovato il flag sarà attivato, altrimenti nada. Create quindi tale file e siete a posto.
A questo punto se avete sistemato tutti e cinque i trick dovreste ottenere il messaggio di complimenti :-). Riepiloghiamo: per farvi registrare dovete:
1- non far rilevare il softice al programma
2- fargli trovare la chiave HKEY_CURRENT_USER\UIC\ nel registry
3- fargli credere di essere nel 1997
4- ingrandire il crackme a schermo intero
5- fargli trovare il file C:\geddon.uic
l'ordinedei cinque passi non è importante. Riavviate il crackme ed è fatta :-)
Ultime note
Spero che a questo punto vi siate convinti che WinDasm è solo un giocattolo rispetto a Ida. Ricordate che in IDA potete rinominare praticamente TUTTO: funzioni, variabili locali e globali, locazioni e molto altro. Per qualsiasi dubbio potete consultare il tutorial di Que. Nota che una volta disassemblato potete produrre vari output file: semplice testo, map e altri. In particolare il map è utile perchè poi potete usare l'utility MSYM di softice per trasformare il map in symbols, e i symbols poi li potete usare nel softice per avere tutti i nomi a disposizione in fase di debugging :-) volete fare la prova?
disassemblate il programma
File->Produce->Create MAP file
MSYM file.map e ottenete file.sym
Aprite il SiceLodaer32!
File->OpenModule e aprite il file.sym, non l'exe!
Module->Load
File->OpenModule programma.exe
ora lanciate il programma. In Softice non dovreste vedere niente perchè dovete rilocare i simboli. Se usate il comando SYM dovrebbe farvi vedere una lista di simboli, se non la vedete allora avete sbagliato qualcosa. Se la vedete usate:
SYMLOC n seg base_addr
per ogni sezione, dove n è il numero della sezione (numero 1-based), seg è il segmento della sezione e base_addr è l'indirizzo di base della sezione. Ad esempio
SYMLOC 1 0167 00401000
SYMLOC 2 016F 00404000
per la sezione di codice, e così via. Al posto di 167 dovete mettere il segmento del vostro CS
SYMLOC 2 016F 00404000
per la sezione data etc etc. Usate map32 per avere lista e baseaddress delle sezioni e usate il symloc su tutte (anche se in realtà bastano code + data).
Poi andate all'entry point
u 00401630
e vedrete un esempio di cosa vuol dire avere tutti i nomi risolti :-) In questo modo non solo vi sarà più facile debuggare e disassemblare, ma inizierete anche a pensare da veri reverser.
Byeeee
AndreaGeddon
Note finali |
Un saluto a tutta la ML e i frequentatori di #crack-it, in particolare un saluto a Yado che mi sta mettendo sotto torchio :-P e ad Acid-Leo che è una vita che non lo vedevo! Anche un saluto a Giocrack (che mi ha fornito l'ultima ida!), a Killo che è sempre disponibile a spiegarci gli internals di win2k e un salutone a Lee :-* Ciao gente! (volevo salutare pure Phobolo ma è troppo grosso poi il tutorial viene di dieci mega :-P)
Disclaimer |
Se vi è piaciuto questo corso o la UIC in generale mandate a me o a Quequero il vostro numero di cc e ci farete felici e contenti >:-) e ricordate che i crackme vanno comprati e non rubati!! :-P
-> Noi reversiamo al solo scopo informativo e di miglioramento del linguaggio Assembly
|
v
Questa è proprio una ca.. una vera cazza.. una enorme, gigantesca, stepitosa c@%%@ta!!
Capitoooooooo????? Bhè credo di si ;))))