Undicesimo Corso Newbies
Addio WinDasm, è tempo di IDA!

Data

by "AndreaGeddon"

 

04/02/2002

UIC's Home Page

Published by Quequero


One two buckle my shoe

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

....

Home page se presente: www.andreageddon.8m.com
E-mail: andreageddon@hotmail.com
Nick, UIN, canale IRC/EFnet frequentato   irc.azzurra.it   #crack-it
 

....

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.


Undicesimo Corso NewBies
Addio WinDasm, è tempo di Ida!
Written by AndreaGeddon

Introduzione

Spero che dopo questo crackme Ida diventerà il vostro braccio destro!

Tools usati

-IDA
-e Softice? no :-) Possiamo fare tutto direttamente da ida!

URL o FTP del programma

www.quequero.cjb.net

Notizie sul programma

Il crackme ha un solo pulsante, se lo premete vi dice che non è registrato. Non dovete patchare il crackme per ottenere la giusta MessageBox, ma dovete solo capire cosa vuole per partire.

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
.text:004016DC
  call __setenvp
.text:004016E1
  call __cinit

 
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
.text:0040175E
  push esi ; lpszCmdLine
.text:0040175F
  push 0   ; hPreInst
.text:00401761
  push 0   ; lpModuleName
.text:00401763
  call ds:GetModuleHandleA
.text:00401769
  push eax ; hInst
.text:0040176A
  call _WinMain@16

 

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
.text:004012AD  jnz short loc_0_4012D5   ; salta a non registrato
.text:004012AF
  mov eax, [esp+24h]
.text:004012B3
  push 40h
.text:004012B5
  push offset aRegistration ; "Registration"
.text:004012BA
  push offset aComplimentiCeL ; "Complimenti ce l'hai fatta!"
.text:004012BF
  push eax
.text:004012C0
  call ds:MessageBoxA

 

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
.text:0040104C  push 4000000h          ; dwFlagsAndAttributes
.text:00401051  push 0                 ; dwCreationDisposition
.text:00401053  push 0                 ; lpSecurityAttributes
.text:00401055  push 0                 ; dwShareMode
.text:00401057  push 0                 ; dwDesiredAccess
.text:00401059  push offset a_Siwvid   ; lpFileName
.text:0040105E  call ds:CreateFileA
.text:00401064  cmp eax, 0FFFFFFFFh
.text:00401067  jnz short loc_0_401070   ; questo decide l'esito
.text:00401069  or byte ptr Chiave, 10h  ; dobbiamo arrivare qui
.text:00401070  loc_0_401070:

 

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
.text:004010ED
  push 0F003Fh     ; samDesired
.text:004010F2
  push 0           ; ulOptions
.text:004010F4
  push offset aUic ; lpSubKey
.text:004010F9
  push 80000001h   ; hKey
.text:004010FE
  call ds:RegOpenKeyExA
.text:00401104
  test eax, eax
.text:00401106
  jnz short loc_0_40110F
.text:00401108
  or byte ptr Chiave, 2
.text:0040110F
  loc_0_40110F:
.text:0040110F
  xor eax, eax

 

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:00401124
  jnz short loc_0_40112D
.text:00401126
  or byte ptr Chiave, 1
.text:0040112D  loc_0_40112D:

.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
.text:00401003  push ebx
.text:00401004  push esi
.text:00401005  push edi
.text:00401006  push offset word_0_407568
; lpSystemTime
.text:0040100B  call ds:
GetSystemTime

 

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
.text:0040121D 
test eax, eax
.text:0040121F 
jz loc_0_40110F
.text:00401225  or byte ptr Chiave, 4

 

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
.text:00401442  push
80h                 ; dwFlagsAndAttributes
.text:00401447  push
3                   ; dwCreationDisposition
.text:00401449  push
0                   ; lpSecurityAttributes
.text:0040144B  push
0                   ; dwShareMode
.text:0040144D  push
80000000h           ; dwDesiredAccess
.text:00401452  push offset aCGeddon_uic
; lpFileName
.text:00401457  call ds:
CreateFileA
.text:0040145D  cmp eax,
0FFFFFFFFh
.text:00401460  jz short locret_0_401469
.text:00401462  or byte ptr
Chiave, 8
.text:00401469  locret_0_401469:
.text:00401469  retn

 

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 ;))))