Corso UIC Newbies 06
From UIC
Corso newbies 6° - Registry sniffing
Contents |
| Infos | |
|---|---|
| Author: | AndreaGeddon |
| Email: | |
| Website: | http://andreageddon.8m.com |
| Date: | 03/09/2000 (dd/mm/yyyy) |
| Level: |
|
| Language: | Italian |
| Comments: | Qualche mio eventuale commento sul tutorial :))) Se scrivo qui ti arrabbi, se ti chiamo Quaqquaro ti arrabbi, ma non ho provato mai le due cose insieme: (Scrivo qui) AND (Quaqquaro) = ? Finora avevo sempre provato solo con OR Dai non te la prendere :-PPPPPPPPPPPPPPPPPP Vabbuò, oltre ai beduini tra poco incontrerari tunisini e cani focosi......hihihihihihi, sicuro che ti conviene? :) |
Introduction
Stavolta ci dedicheremo un po' alle operazioni con il registry del winzozz.
Tools usati
- SoftIce
- RegMon (un monitor degli accessi al registro - Opzionale)
- Editor di registro (quello del windogs basta e avanza)
Link e Riferimenti
Questo è il Corso UIC Newbies n°06 disponibile alla pagina Corsi UIC Newbies
Notizie sul programma
È un crackme a livelli che va a cercare ed elaborare alcune chiavi nel registro del windogs.
Essay
Okey, questo crackme si può risolvere anche soltanto con il softice, il regmon è opzionale ma molto comodo. Per questo vedremo entrambi gli approcci (softice & regmon). Iniziamo.
LIVELLO 1 - SEMPLICE CHIAVE
Come dice il crackme, questo livello consiste nella ricerca di una semplice chiave. Dove sarà mai questa chiave? Che nome deve avere? Lanciate il regmon, ora nel crackme premete il tasto del livello 1. Otterete il messaggio di errore.
Tornate nel regmon (per comodità clickate sulla lente così smetterà di hookare tutte le chiamate al registro da parte del sistema) e andiamo a esaminare quello che è successo. Tra le varie righe, andiamo a vedere solo quelle del processo che ci interessa, cioè Sesto, e troviamo:
Sesto OpenKey HKCU\AndreaGeddon NOT FOUND Sesto QueryValueEx HKCU\0xC18A3120\C:\Windows\Media\Chord.wav NOT FOUND Sesto CloseKey 0x63FBCC BADKEY
tutto claro? No? Allora vediamo di commentare un pochito: le operazioni con le chiavi si svolgono nel seguente modo:
- apertura chiave/sottochiave
- lettura valore
- chiusura chiave
in primis il programma è andato ad aprire la chiave HKCU\AndreaGeddon (dove HKCU sta per HKEY Current User ed è un ramo predefinito del registro). Il risultato NOT FOUND vuol dire che tale chiave non è stata trovata. Poi è avvenuta l'operazione CloseKey col risultato BADKEY giustamente perché la chiave non era stata aperta, quindi closekey cosa cavolo doveva chiudere? Ora direte: ma c'è anche QueryValue! Infatti, ma come vedete punta a Chord.wav, che è uno tra i suoni predefiniti del winzozz, per inciso viene richiesta questa chiave dalla message box di errore (che vi fa... DING! o quale suono avete messo al suo posto). Ora che sappiamo che cosa succede, proviamo a rimediare. Lanciate il regedit (Start -> Esegui e immettete regedit) et voilà siete nel registro. Andate sul ramo HKEY_CURRENT_USER, espandetelo se volete, cliccate col destro su tale ramo e scegliete Nuovo->Chiave. Ora rinominate tale nuova chiave in AndreaGeddon, torniamo al crackme e vediamo che succede: GOOD WORK! Primo livello superato. Come vedete col regmon è stato molto facile, ma ora vediamo di fare lo stesso usando semplicemente il softice.
Cancellate la chiave HKCU\AndreaGeddon se l'avete già creata e richiamate il softice. Settiamo un bpx RegOpenKeyExA. Se disassemblate il crackme troverete tra le import le funzioni
RegOpenKeyExA RegQueryValueExA RegCloseKey
che appunto sono usate per la apertura, lettura e chiusura delle chiavi. Ci sono anche altre api che potranno servirvi, in genere basta che diate un occhiata alle import di un qualsiasi programma e vedere quelle del modulo ADVAPI.DLL, che sono quelle che dovrebbero agire sul registro. Il mio crackme è piccolo è stupido, indi ci sono solo quelle 3. Comunque settate il break e andiamo nel crackme a premere il bottone del Livello1.Il sice popperà sul modulo ADVAPI appunto. Premete F12 e vi ritroverete nel processo del Sesto:
00401531 lea eax, dword ptr [esp]
00401535 push esi
00401536 push eax
00401537 push 000F003F
0040153C push 00000000
* Possible StringData Ref from Data Obj ->"AndreaGeddon"
0040153E push 00404094 se visualizzate col sice questa locazione ci troverete
la striga AndreaGeddon
00401543 mov esi, ecx
00401545 push 80000001
* Reference To: ADVAPI32.RegOpenKeyExA, Ord:012Eh
0040154A Call dword ptr [00405290] col sice Poppate qui
00401550 test eax, eax qui controlla il valore restituito dall'apertura
della chiave
00401552 je 00401575 se è zero la chiave è stata aperta con successo
00401554 push 00000010
* Possible StringData Ref from Data Obj ->"Lamah"
00401556 push 0040408C
* Possible StringData Ref from Data Obj ->"Non ci siamo"
0040155B push 00404070 se arriviamo qui vuol dire che la chiave non
è stata aperta
00401560 mov ecx, esi quindi il je a 00401552 è quello che ci manda alla
parte giusta di codice
* Reference To: MFC42.Ordinal:1080, Ord:1080h
00401562 Call 00401C2E
00401567 mov ecx, dword ptr [esp+04]
0040156B push ecx
* Reference To: ADVAPI32.RegCloseKey, Ord:0117h
0040156C Call dword ptr [0040528C]
00401572 pop esi
00401573 pop ecx
00401574 ret
voi col softice poppate alla linea 00401550. La chiave è già stata chiamata. Se vedete alcune righe sopra, vedrete una serie di PUSH. Quelli sono i parametri da passare alla funzione regopenkeyexa, parametri tra i quali ci sarà anche il nome della chiave da aprire. Come facciamo a saperlo? Basta controllare la sintassi della funzione in esame:
HKEY hKey, // handle of open key
LPCTSTR lpSubKey, // address of name of subkey to open
DWORD ulOptions, // reserved
REGSAM samDesired, // security access mask
PHKEY phkResult // address of handle of open key
);
il secondo parametro passato contiene il puntatore alla stringa che è il nome della chiave da aprire. Quindi se andiamo nel disassemblato dovremo andare a considerare il penultimo PUSH. Perchè il penultimo e non il secondo? Perchè lo stack è una pila (struttura LIFO last in first out), quindi l'ultimo valore pushato sarà il primo ad essere richiamato. Quindi il PUSH dei parametri di una api avviene al contrario di quello che vedete nella descrizione della sintassi. Comunque, alla riga 0040153E c'è il penultimo push, che è un PUSH 00404094. Se andiamo a visualizzare la locazione 00404094 ci troveremo appunto la stringa AndreaGeddon, che è la sottochiave che RegOpenKeyExA andrà a cercare. Ovviamente lo si vede benissimo anche dal disassemblato. Ooops... quasi dimenticavo! Come facciamo a sapere il ramo principale che va a richiedere? Cioè, come facciamo a sapere che va ad aprire la chiave in HKEY_CURRENT_USER? A questo ci pensa il primo parametro della funzione, cioè HKEY. Questo parametro è del tipo HKEY appunto e può essere uno dei valori dei rami principali. Se andate a vedere la guida alle costanti api che ho messo nel MIO sito (messaggio promozionale) troviamo subito i corrispondenti valori:
HKEY_CURRENT_CONFIG = 80000005
HKEY_CURRENT_USER = 80000001
HKEY_DYN_DATA = 80000006
HKEY_LOCAL_MACHINE = 80000002
HKEY_PERFORMANCE_DATA = 80000004
HKEY_USERS = 80000003
ora nel disassemblato andiamo a vedere l'ultimo PUSH prima della CALL RegOpenKeyExA (l'ultimo push perché nella sintassi il parametro HKEY è il primo), e cosa troviamo? PUSH 80000001 che guarda caso corrisponde proprio a HKCU. Ora sappiamo per certo che la chiave che deve aprire è:
HKEY_CURRENT_USER\AndreaGeddon
andiamola a creare e avremo finito il primo livello.
LIVELLO 2 - UN ACCORGIMENTO IN PIU'
Allo stesso modo affrontiamo il livello 2. Lanciate regmon, premete il pulsante del livello 2 e avrete un listato quasi uguale al precedente, in particolare noterete che la chiave cercata stavolta è
HK_CURRENT_USER\AndreaGeddon\1
seguendo il ragionamento precedente andiamo subito nel regedit e creiamo la chiave AndreaGeddon\1. Torniamo al crackme, ripremiamo il bottone e.... DOH! Non và. Siamo perduti? No! Semplicemente rimettiamo il regmon in ascolto e ripremiamo il pulsante del livello 2: ma cosa abbiamo???
Sesto OpenKey HKCU\AndreaGeddon\1 SUCCESS Sesto OpenKey HKCU\AndreaGeddon\1\2 NOT FOUND
quindi ora l'apertura della chiave 1 va a buon fine (eh già, gliela abbiamo creata poco fa), però poi viene cercata la chiave AndreaGeddon\1\2 e qui non va. Torniamo col regedit e creiamo la sottochiave 2. Ancora errore. Riprovate col regmon, ed ecco il log:
Sesto OpenKey HKCU\AndreaGeddon\1 SUCCESS Sesto OpenKey HKCU\AndreaGeddon\1\2 SUCCESS Sesto OpenKey HKCU\AndreaGeddon\1\2\4 NOT FOUND
trova le prime due, ma poi cerca la chiave AndreaGeddon\1\2\4 e non la trova. Cacchio, torniamo nel regedit e andiamo a creare la sottochiave 4. Torniamo al crackme... tadaaa! Registrato anche il livello 2.
L'approccio col softice è identico a prima, solo un po' più lungo. Come vedete il regmon è comodissimo e molto chiaro. Andiamo avanti.
LIVELLO 3 - COSA CERCHI?
Siamo arrivati al terzo livello! La logica ci suggerisce di ricalcare le orme degli esempi precedenti, quindi rispariamo il RegMon (o fate la procedura col softice, come vi pare), e vediamo pure stavolta il log:
Sesto OpenKey HKCU\AndreaGeddon\WhatIsTheMatrix NOT FOUND
quindi subito subito andiamo al regedit e creiamo la chiave in questione. Ripetiamo il tutto e vediamo di nuovo il log:
Sesto OpenKey HKCU\AndreaGeddon\WhatIsTheMatrix SUCCESS Sesto QueryValueEx HKCU\AndreaGeddon\WhatIsTheMatrix\WelcomeToTheRealWorld NOT FOUND
okei ora avrete pensato: cheppalle basta semplicemente creare la sottochiave WelcomeToTheRealWorld. No! Nein! Il tipo di richiesta stavolta non è Apertura Chiave, ma è Lettura Chiave! Quindi stavolta non dovremo creare una chiave, ma un valore.Quindi nel registro clickate col destro sul ramo WhatIsTheMatrix, scegliete Nuovo, adesso non dovrete scegliere Chiave ma avrete altre tre possibilità: Stringa, Valore Binario, Valore DWORD. E qui il primo dubbio: che tipo di valore devo creare? Andiamoci a vedere la sintassi di RegQueryValueEx:
HKEY hKey, // handle of key to query
LPTSTR lpValueName, // address of name of value to query
LPDWORD lpReserved, // reserved
LPDWORD lpType, // address of buffer for value type
LPBYTE lpData, // address of data buffer
LPDWORD lpcbData // address of data buffer size
);
vedete il 4° valore? Address of buffer for value type. Sarà questo il parametro che ci specifica il tipo di chiave richiesto. Quindi passiamo al softice, settiamo un break su RegQueryValueExA, quando poppa il sice al solito dovete premere F12 per uscire dal modulo advapi e vi ritroverete nel seguente codice:
0040177F lea ecx, dword ptr [esp+10]
00401783 push ecx
00401784 push ebx
00401785 push 00000000
00401787 push 00000000 push tipo della chiave
* Possible StringData Ref from Data Obj ->"WelcomeToTheRealWorld"
00401789 push 00404444 push nome della chiave
0040178E push edx
* Reference To: ADVAPI32.RegQueryValueExA, Ord:0136h
0040178F Call dword ptr [00405294] questa è la call
00401795 test eax, eax
00401797 je 004017AE
00401799 push 00000010
* Possible StringData Ref from Data Obj ->"Mi spiace non sei l'eletto"
0040179B push 00404428
come prima andiamo a vedere tra i push prima della call. In particolare cerchiamo il terzultimo (ricordate il LIFO!), che sta alla riga 00401787 ed è un PUSH 00. Questo vuol dire che il parametro relativo all'identificazione del tipo di dato da richiedere è NULL, quindi possiamo mettere un qualsiasi tipo. Per comodità quindi creeremo un valore Stringa ovviamente con il nome WelcomeToTheRealWorld. Per inciso, il tipo di valore può essere tra i seguenti, con i corrispondenti valori presi dalle api constants:
REG_DWORD = 4
REG_DWORD_LITTLE_ENDIAN = 4
REG_DWORD_BIG_ENDIAN = 5
REG_EXPAND_SZ = 2
REG_LINK = 6
REG_MULTI_SZ = 7
REG_NONE = 0
REG_RESOURCE_LIST = 8
REG_SZ = 1
ora abbiamo la chiave, abbiamo il relativo valore, ma il livello ancora non è registrato (avete notato le msgbox in tema con matrix? che cariiiiiine!!). A questo punto la cosa ovvia che ci ronza per la capa è che il valore WelcomeToTheRealWorld deve soddisfare un qualche requisito (tipo deve essere un codice, una password). Ora si torna al bel vecchio lavoro di tracing. Scrivete un valore a caso nella chiave (doppio click sulla chiave col regedit), io inserisco Morpheus tanto per restare in tema. Riabilitate il bpx regqueryvalueexa, premete il pulsante livello 3, il sice popperà. F12 per tornare al processo del sesto, ed ecco cosa avrete:
00401797 je 004017AE se si, salta
00401799 push 00000010 altrimenti dai il messaggio di errore
* Possible StringData Ref from Data Obj ->"Mi spiace non sei l'eletto"
0040179B push 00404428
* Possible StringData Ref from Data Obj ->"Posso solo indicarti la soglia"
004017A0 push 004043D4
004017A5 mov ecx, esi
* Reference To: MFC42.Ordinal:1080, Ord:1080h
004017A7 Call 00401C2E
004017AC jmp 0040180B
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
004017AE push edi se la chiave è stata letta finiamo qui
004017AF xor edi, edi azzeriamo edi che ci servirà come contatore
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
004017B1 mov al, byte ptr [edi+ebx] mette in AL l'n-esimo byte del valore letto nella chiave
004017B4 mov cl, byte ptr [esp+edi+18] mette in AL l'n-esimo byte letto da una locazione
004017B8 cmp al, cl confrontali
004017BA jne 004017E9 se non sono uguali salta a errore!
004017BC cmp edi, 00000007 controlla se il contatore è arrivato a 7
004017BF jne 004017E1 se non ci è arrivato allora salta
004017C1 push 00000030 se arrivate qui avrete il messaggio di OK!
* Possible StringData Ref from Data Obj ->"System Failure"
004017C3 push 004043C4
* Possible StringData Ref from Data Obj ->"Sei l'eletto!"
004017C8 push 00404378
004017CD mov ecx, esi
dopo la lettura della chiave finiamo dritti dritti alla linea 004017AE. Poco dopo, alle righe 004017B1 e 004017B4 troviamo qualcosa di interessante: la prima mette in AL il carattere puntato dalla locazione EDI+EBX, che se andiamo a visualizzare vedremo contenere la stringa "Morpheus" che è il valore inserito da me nella chiave. La riga successiva mette in BL il carattere puntato dalla locazione ESP+EDI+18, quindi andiamola a visualizzare (d esp+edi+18 in sice) e ci troviamo la stringa "Trinityy"! Che sia il codice che cerchiamo??? Come si vede il ciclo funzia così: prende uno alla volta i char del valore immesso da noi nella stringa, e li confronta uno alla volta con i char della stringa Trinityy. Se i due char confrontati risultano diversi, il prog salta subito a errore. Se i due char sono uguali, prosegue nel ciclo, controlla se il contatore è 07, se non lo è ripete il confronto char-to-char. Se abbiamo avuto sette confronti che sono risultati tutti positivi, allora il programma prosegue e ci dà il messaggio di OK. Quindi il valore della chiave deve essere Trinityy.
LIVELLO 4 - CHIAVE + CODICE + ALGO
Eccoci finalmente all'ultimo livello di questo crackme. Anche qui partiamo subito col regmon, premiamo il tasto Livello 4 e otteniamo nel log:
Sesto OpenKey HKCU\AndreaGeddon\Sergej\Rachmaninov NOT FOUND
creiamo la chiave, rispiamo il crackme e troviamo:
Sesto QueryValueEx HKCU\AndreaGeddon\Sergej\Rachmaninov\QualBuonVento NOT FOUND
okey, sappiamo posizione e nome della chiave. Se usiamo softice settiamo un bpx regqueryvalueexa e arriviamo in:
00401890 push 00000000
* Possible StringData Ref from Data Obj ->"QualBuonVento"
00401892 push 0040461C
00401897 push edx
* Reference To: ADVAPI32.RegQueryValueExA, Ord:0136h
00401898 Call dword ptr [00405294] questa è la call
0040189E test eax, eax
quindi anche stavolta è irrilevante il tipo di valore da creare, perciò creeremo la chiave
HKCU\AndreaGeddon\Sergej\Rachmaninov\QualBuonVento
di tipo Stringa. Anche qui come prima il valore da inserire nella chiave dovrà soddisfare qualche requisito, per sapere quale andiamo a tracciare con il softice. Inseriamo un valore a caso nella chiave, risettate il solito bpx regqueryvalueexa, quando il sice poppa premete F12 ed ecco cosa vi attende:
00401898 Call dword ptr [00405294] si parte da qui
0040189E test eax, eax
004018A0 je 004018B3
004018A2 push 00000010
* Possible StringData Ref from Data Obj ->"È l'ora del te?"
004018A4 push 00404608
* Possible StringData Ref from Data Obj ->"Decisamente il quadro non "
004018A9 push 004045D4
004018AE jmp 00401966
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
004018B3 mov edi, esi se la chiave viene letta vi troverete qui
004018B5 or ecx, FFFFFFFF prepara ecx che sarà usato come contatore
004018B8 xor eax, eax azzera eax
004018BA xor edx, edx azzera edx
004018BC repnz | fa una scansione della stringa puntata da edi
004018BD scasb |
004018BE not ecx |
004018C0 dec ecx |ottiene in ecx il numero di caratteri della stringa
004018C1 je 004018DC se la stringa è lunga zero salta direttamente a errore
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
004018C3 mov al, byte ptr [edx+esi] esi punta alla locazione dove è contenuta la stringa
inserita, edi è il contatore
004018C6 mov edi, esi metti il puntatore alla stringa in edi
004018C8 add al, dl somma il contatore al carattere preso dalla stringa
004018CA or ecx, FFFFFFFF prepara ecx che sarà riusato come contatore
004018CD mov byte ptr [edx+esi], al muovi la somma di char e contatore nel carattere preso
dalla stringa
004018D0 xor eax, eax azzera eax
004018D2 inc edx incrementa il contatore
004018D3 repnz |di nuovo una scansione della stringa
004018D4 scasb |
004018D5 not ecx |di nuovo ottiene il numero di caratteri
004018D7 dec ecx |
004018D8 cmp edx, ecx se il contatore non è uguale al numero dei caratteri...
004018DA jb 004018C3 continua il ciclo
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
chiaro fin qui? Prende il primo char e lo somma a 0, prende il secondo e lo somma a 1, prende
il terzo e lo somma a 3 etc. etc.
004018DC mov edi, esi | dopo che ha finito le somme riporta il puntatore alla
nuova stringa in edi
nuova stringa perché se avevate inserito aaaa a causa delle somme ora la stringa sarà abcd
004018DE or ecx, FFFFFFFF riprepariamo il contatore
004018E1 xor eax, eax | azzeriamo eax e edx
004018E3 xor edx, edx |
004018E5 repnz |
004018E6 scasb | di nuovo conteggio dei caratteri della stringa
004018E7 not ecx | puntata da edi
004018E9 dec ecx | (che barba che noia)
004018EA je 00401902 se sono 0 caratteri salta direttamente via
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
004018EC mov al, byte ptr [edx+esi] metti in AL l'n-esimo char della stringa
004018EF mov edi, esi metti il puntatore alla stringa in edi
004018F1 add bl, al aggiungi a bl il carattere preso (somma a bl tutti
i char della stringa)
004018F3 or ecx, FFFFFFFF indovinate un po'?
004018F6 xor eax, eax azzera eax
004018F8 inc edx incrementa il contatore del ciclo
004018F9 repnz |
004018FA scasb | ormai l'avete capito cos'è questo
004018FB not ecx |
004018FD dec ecx |
004018FE cmp edx, ecx se il contatore non è uguale al numero di char della stringa...
00401900 jb 004018EC ...allora continua il ciclo
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
00401902 cmp bl, D1 ora in al abbiamo la somma di tutti i char della stringa
00401905 jne 0040195A se tale somma è diversa da D1h salta a errore
00401907 push 00000030 altrimenti arrivi qui e hai finito il crackme
* Possible StringData Ref from Data Obj ->"Good work Mr. Cracker"
00401909 push 004045BC
allora, riordiniamo le idee:
1) Il programma prende la stringa e somma ad ogni carattere il contatore
es: aaaa diventerebbe 41h+0, 41h+1, 41h+2, 41h+3 cioè abcd
2) Il programma somma uno ad uno tutti i caratteri della stringa appena ottenuta
es: abcd diventa 41h+42h+43h+44h = 10Ah = 0Ah
3) Tale somma (preso solo il Less significant byte) deve essere uguale a D1h
es: nel nostro caso 0A è diverso da D1, quindi il programma ci manderà a fanc...
Come calcolarci un giusto valore? Visto che non possiamo (facciamo finta che non possiamo) inserire direttamente un carattere col valore D1h, vediamo di spezzarlo in somma di altri caratteri. Per esempio D1h/2 = 68h (68h = "i"). Bene, vediamo se possiamo usare la somma di valori vicini alla "h". In questo caso dobbiamo tener conto anche dell'incremento char per char che subisce la stringa. Per ottenere D1 possiamo sommare 68h e 69h. La loro somma dà D1h, tuttavia non possiamo inserire "hi" nella chiave, altrimenti a causa dell'incremente finiremmo per avere 68h+6Ah = D2h. Quindi non dobbiamo fare altro che decrementare il 69h a 68h, così inseriremo la stringa "hh", il prog la trasformerà in 68h+69h che è quello che vogliamo. Inseriamo "hh" nella chiave et voilà! Il crackme è terminato. Ovviamente potete trovare anche altre combinazioni, questa mi è sembrata la più breve e semplice.
Spero di non aver lasciato dubbi strani nelle vostre testacce.
Byeeez
AndreaGeddon
Note finali
Un saluto a tutta la ML. Ciauuuz ! Un saluto a cod che è partito per la naja (fagliela vedere!). Un saluto a Que che non se la prende anche se scrivo dove non devo anche se lo chiamo Papero (che cuore d'oro) :-PPPPPPPPPPPPPPPPP e non mandarmi i beduini a casa!!!!!!
Disclaimer
Queste informazioni sono solo a scopo puramente didattico. Ricordate di comprare il crackme se volete continuare ad usarlo dopo 15 giorni :-P Ricordate che i poveri sviluppatori di crackme non hanno i soldi per portare fuori le ragazze se voi non pagate il loro lavoro, e senza ragazze non si lavora!!! >:-PPPPPPP