Official CookieCrk Trial CrackMe |
|
|
31/08/2000 |
by "blAAd!" |
|
|
Published by Quequero |
|
cRaCk'Em AlL bUt DoN't StEaL!! |
Bravo blaad, ti sei impegnato ed hai fatto davvero un ottimo tutorial menomale che ogni tanto si vede anche qualcuno che si impegna a studiare gli algoritmi...Ed a molti fischieranno le orecchie :))) |
cRaCk'Em AlL bUt DoN't StEaL!! |
UIC's form |
|
UIC's form |
Difficoltà |
(X)NewBies (X)Intermedio ( )Avanzato ( )Master |
Anche questa volta si tratta di un crackme. Però è + complesso del precedente in quanto, trattandosi di un trial, presenta 4 schemi di protezione (anche se tipici del genere). Non sò se il Trial sia scaduto (non fate i furbi, eh?!?). Comunque oltre ad analizzare il programma, costruiremo un KEYGEN ed un KEYFILEMAKER, per le relative prove, right??
Introduzione |
Le costruzioni della KEYGEN e del KEYFILEMAKER saranno fatte utilizzando il NASM 0.98, un *free* asm disponibile in rete. I tools usati sono per il resto i soliti. -=rAW POWEr=-
Tools usati |
URL o FTP del programma |
http://www.crackpl.site.pl/smola
Notizie sul programma |
Cos'altro dire?!? Semplicemente che cercherò di essere il più chiaro possibile. Se il tut comunque non dovesse piacervi allora... scrivetevelo da voi. Scherzo. Iniziamo allora...
Essay |
Prima di procedere, leggiamo il regolamento, e quali sono le protezioni del Trial:
1)
Cominceremo dalla fine, e cioè con le 2 patch indicate sopra, e poi proseguiremo con i
restanti punti indicati.
( ( ( ( (
U N O : Anti-SICE protection ) ) ) ) )Just a moment... Right, c'mon!!
A cosa serve ciò?? Provate a riempire le text-bar per il nome ed il seriale. Non appena
premete 'Ok', il trial terminerà improvvisamente... mumble, mumble?!? e allora?? Provate
a far partire il programma utilizzando FrogIce(cosa?!? non l'avete??). Il programma
nemmeno partirà! Questa protezione ci impedisce di accedere al Name/Code registration.
Tipico Anti-SICE è quello tramite la chiamata a CreateFileA. Rivai con CookieCrk.
Riempite ancora le text-bar e scrivete da SICE 'bpx CreateFileA' + enter. Poi una volta in
Window$ premete 'Ok'. Bingo!! Ci troveremo(dopo aver premuto 'F12') in:
CALL at Address:
|:00401266
|
:0040150C mov edi, 004024C7
Avete veramente già capito tutto?? Il blocco sopra fa 2 cose. Uno: rileva la presenza di S-Ice tramite la funzione CreateFileA. Ciò ci suggerisce di trasformare il je in xxxx:00401534 in jne. Due: controlla se stiamo facendo partire il programma da FrogIce con lo stesso metodo di Uno. Quest'ultimo punto però, non è molto importante. Oltre a cambiare je con jne, possiamo(ed è meglio) noppare la chiamata in xxxx:00401266. Così eliminiamo ogni tipo di controllo. Notate la routine in xxxx:00401595, che serve a criptare le stringhe "\\.\SICE" e "\\.\NTICE", 'nascondendo' la routine da un veloce controllo con qualche hexeditor. Nient'altro.
( ( ( ( (
D U E : Kill the Nag ) ) ) ) )Ya, we'll bang the Nag. Ok, basta deliri. Avrete già capito cosa dobbiamo fare ora, ed avrete sicuramente notato il logo CookieCrk, non appena facciamo partire il programma. La grafica è contenuta all'interno di una finestra. Questo ci suggerisce di dare la caccia, proprio a quest'ultima. Come fare?? Semplice. Sicuramente avrete notato che dopo 2 secondi(non ho usato il cronometro, se guardate il codice sotto capirete perchè), la finestra si chiude. Una classica chiamata a S.O. di Window$, che mostra una finestra, è ShowWindow, ma quella è sconsigliata, perchè è spesso utilizzata dal S.O. Usate allora, proprio la chiamata a DestroyWindow. Cioè, prima di far partire il trial, da SICE scrivete 'bpx DestroyWindow' + enter, e tornate a Window$. Fate ripartire il crcme, ed immediatamente ci troveremo in:
CALL at Addresses:
|:00401089 , :004010DE
|
:004011B9 push 00000005
:004011BB push dword ptr [00402004]
:004011C1 E844050000 Call 0040170A
Dopo il ret ci troveremo in:
:004010CF mov eax, dword ptr [ebp+08]
:004010D2 mov dword ptr [00402000], eax
:004010D7 mov edi, eax
:004010D9 call 004015CD
Viene subito in mente di noppare la call a xxxx:004010de. Se fate così però, non appena farete ripartire il programma, sarà visualizzato un messaggio di errore. Why?? Semplicemente perchè subito prima, è presente una chiamata che serve ad impostare la finestra, handle vari, ecc. Se questo tipo di richieste non vengono risolte, il S.O. genera un messaggio d'errore. Quindi dovremo noppare anche xxxx:004010d9. Sorpresa!!! Se avete fatto ripartire il programma anche dopo questo nopping, probabilmente vedrete ancora il logo, questa volta non più nella finestra, ma come immagine sovraimposta al desktop in alto a sinistra. E quindi?? Se tornate al blocco xxxx:004011b9, noterete agli indirizzi di chiamata evidenziati da WDasm, oltre a xxxx:004010de, anche xxxx:00401089. Basterà andare a quell'indirizzo quindi, e noppare anche quella chiamata(e anche quella sopra per lo stesso motivo). Nient'altro. Are u horny babe??
( ( ( ( (
T R E : Name/Code Registration ) ) ) ) )Ora che abbiamo terminato le patches, proseguiamo con i punti restanti, ed iniziamo con
l'analisi delle istruzioni riguardanti la registrazione Name/Code, e la costruzione della
KEYGEN relativa. Right, let's go:
Ora che nel punto UNO, abbiamo risolto il problema della protezione Anti-SICE, sarà
facile entrare nella parte di codice che ci interessa. Riempiamo le Text-Bar relative al
nome e al codice. Entriamo in SICE e scriviamo 'bpx hmemcpy' + enter. Poi premiamo 'Ok'.
Una volta entrati in SICE(ed aver premuto varie volte 'F12'), ci troveremo davanti alle
istruzioni:
:0040122C push 00000050
:0040122E push 0040225A
Sul blocco di istruzioni sopra, non c'è molto da dire. Non viene fatto altro, che prelevare nome e codice dalle rispettive Text-Bar. A ciò segue il controllo Anti-SICE(già patchato), la conversione in hex del seriale, ed il controllo del codice. Bisogna solo fare attenzione, al fatto che il programma simula di accettare codici minori di 10 caratteri. In realtà li codifica, ma alla fine, se son meno di 10 caratteri di partenza(xxxx:00401297), visualizza lo stesso il messaggio di errore. Quindi il seriale deve essere di 10 caratteri. Quello che per noi è veramente importante, è la chiamata all'indirizzo xxxx:0040128a, vediamo allora il codice che la riguarda:
CALL at Address:
|:0040128A
|
:004012F7 xor ecx, ecx
Già i commenti dovrebbero essere sufficienti a capire di cosa si tratta. Comunque
riassumiamo: eax in partenza contiene l'hex del seriale. Con una serie di semplici
operazioni, viene modificato il suo contenuto. Vengono in seguito prelevati dal nome, i
caratteri a 4 a 4. Questi, sono poi posti in ebx, a cui seguono una serie di operazioni,
al termine delle quali, si salva il contenuto di ebx, sommandolo ad ecx. Terminata la
stringa, c'è una somma tra i registri eax, ebx ed ecx. Al tutto è sottratta una costante
(012121212h), ed il valore che dovrà risultare in eax, affinchè si tratti di un seriale
corretto, è 0.
Possiamo quindi passare all'impostazione della KEYGEN. Come si può vedere direttamente
dal programma scritto sotto, la prima cosa che si deve fare, è, a seguito dell'input del
nome, la codifica di quest'ultimo. Questa parte è quindi una semplice operazione di Cut
and Paste, con qualche leggera modifica(problemi di compilazione), dal codice originale. A
ciò dovrà far seguito la conversione di eax nel seriale corretto. Per quest'ultimo
basterà impostare eax uguale a 012121212h. Dopo gli deve essere sottratto il valore della
somma tra ecx ed ebx, ed infine basterà invertire le operazioni fatte all'inizio nel
codice originale, sempre su eax, ed il gioco sarà fatto. Un'ultima nota al programma
della KEYGEN. Alla fine è stata inserita una routine che converte il valore di eax, nel
suo rispettivo decimale, e la relativa stampa su video. Niente altro. KEYGEN:
Start:
mov ah,09
mov dx,Intro
int 21h ; mostra intro msg
mov ax,0
mov ah,0ah
mov dx,Namemem
int 21h ; input del nome
mov edi,Namemem+2
xor eax,eax
mov al,[edi-1]
mov cl,0
mov [edi+eax],cl ; mette 00 al posto di 0d, al termine della stringa
Ciclo: ; breve routine prelevata dal codice originale stile Cut & Paste
mov ebx, [edi]
not ebx
xor bh, bl
rol ebx, 03
inc ebx
ror ebx, 07
add ebx, [edi]
add edi, 00000004
add ecx, ebx
mov eax,[edi]
cmp eax,0
jne Ciclo
Decode: ; routine che inverte il valore in eax, per risalire al valore corretto
add ebx, ecx
xor eax, eax
mov eax,12121212h
sub eax,ebx
ror eax,3; notate le trasformazioni delle istruzioni (es.: ror -> rol)
inc eax ; ed anche la loro inversione 'cronologica'
rol eax,7
xor eax,0deaddeadh
ConvHexDec: ; inizio semplice routine conversione HEX->DEC
xor esi,esi
mov si,Serial+10 ; si -> alla zona dove viene immagazzinato il seriale
mov ecx,0ah
cicla:
xor edx,edx
div ecx ; divide eax per 10 e salva il resto su edx
add dl,30h
cmp dl,3ah ; controlla se la cifra e' compresa tra '0' e '9' e quindi stampa
jl stampa
add dl,7
stampa:
dec esi
mov [esi],dl
or eax,eax
jnz cicla
mov ah,9
mov dx,Return
int 21h ; stampa del corretto seriale
mov ah,4ch
int 21h ; ritorno a DOS
org 100h
Intro db 'Keygen for Trial MemberShip of Cookie by blAAd!',13,10,'Insert Name: $'
Return db 13,10,'Code: '
Serial db '0000000000',13,10,36
Namemem db 18h
times 40 db 0
( ( ( ( (
Q U A T T R O : Keyfile-based Registration ) ) ) ) )Questa è forse la parte più difficile del Trial. Affronteremo l'analisi della parte
di codice interessata, ed in più creeremo un KEYFILEMAKER in asm.
Per entrare nel blocco di programma voluto, da SICE scriviamo 'bpx CreateFileA' + Enter e
poi Ctrl-D per tornare a Window$. Facciamo partire il Trial. Ci troveremo di nuovo in
SICE. Premiamo 'x' + Enter, perchè il primo break è relativo al caricamento del
programma. Ora se premiamo 'F12' ci dovremmo trovare nel blocco di istruzioni giusto:
:0040134A push 00000000
:0040134C push 00000080
:00401351 push 00000003
:00401353 push 00000000
:00401355 push 00000003
:00401357 push 80000000
:0040135C push 004024BB
Nel blocco sopra, il programma cerca(o meglio, tenta di aprire)un file di nome 'crackme.key', attraverso la chiamata a CreateFileA(il file dovrà essere incluso nella stessa directory del trial). Quindi abbiamo ottenuto una prima importante informazione. Nel dissassemblato sopra, sono inoltre indicati gli indirizzi da cui vengono prelevate la lunghezza del nostro ipotetico file, e la zona di memoria in cui viene eventualmente rilocato, prima della chiamata a ReadFile. Sono svolti inoltre, i controlli tipici, nel caso il file non esistesse, fosse vuoto, o i suoi primi 4 bytes nulli. A tutto ciò, segue immediatamente la prima fase di crypting:
:004013A7 mov eax, 004023B8
<------ eax punta all'inizio del file in memoriaQuesta parte di codice è particolarmente importante, perchè rappresenta la codifica di un 'chunk', che dovrà essere comune a tutti i file di registrazione. Come è chiaro dai commenti, vengono letti i primi 4 bytes, di 'crackme.key'. Poi vengono decodificati, e il jne finale, ci indica che il valore in edi, dopo lo xor, deve essere 0. Se proviamo ad invertire il senso delle istruzioni, partendo dallo xor in xxxx:004013c0, ci troveremo ad un punto morto. in xxxx:004013b7, c'è una moltiplicazione, che coinvolge il valore prima della codifica. Quindi non possiamo risalire al giusto valore, a meno di non conoscere già il valore! Come fare?!? Semplice, ricorrendo alla forza bruta... Cioè reimpostiamo la routine sopra, facendola diventare una sorta di programma 'brute forcing', in questa maniera:
xor eax,eax
Start:
inc eax
mov edi,eax
shr edi,5
xor edi,05e30a78h
imul edi,eax
shl edi,3
xor edi,0e5c23a08h
jne Start
Questa breve routine è praticamente identica a quella contenuta nel Trial. Solo che eax non è più un puntatore, ma un contatore. Avrà valore iniziale 0, e finchè edi non conterrà il valore corretto, eax verrà ciclicamente incrementato. Alla fine di questo blocco, aggiungete la routine ConvHexDec usata per la KEYGEN, così dopo un pò, il programma in esecuzione vi stamperà il valore cercato. Non vi và?!? Va bene, ve lo dico io il valore....570351079(21FEDDE7). Questi sono quindi i nostri 4 bytes da porre all'inizio di ogni file. Ovviamente ne dovrete invertire la disposizione....21,FE,DD,E7-->E7,DD,FE,21(ad ogni prelevazione tramite registro, mamma Intel ha pensato bene, di far invertire i dati). Right, continuiamo:
:004013CC mov edx, eax
:004013CE add edx, 00000060
A cosa serve ciò?? Vengono prelevati i dati del nostro file a partire dal nono byte. Quindi, volendo impostare un 'fake' file, dovremmo obbligatoriamente mettere 8 bytes iniziali, di cui 4 sono noti, e dal 5 all'8 ad esempio, degli 0(per costruire il file vi consiglio HexWorkShop). Dal nono byte invece, una stringa col nostro nome. Sarà proprio questa stringa ora, ad essere utilizzata per creare due valori, in edx ed edx+4, tramite i vari xor e add. Procediamo con l'analisi del codice:
:004013E3 push esi
:004013E4 add dword ptr [edx], esi
Nel blocco sopra, avviene il controllo dei bytes 5-8. Questi vengono cryptati tramite uno xor col valore cl, che contiene a sua volta il primo byte di edx. Ciò che segue dopo loopnz, sono una serie di semplici operazioni, per controllare se il valore ottenuto in precedenza per edx+4, è corretto. Non ci sono per ora altri commenti da fare. Procediamo perciò con l'ultima parte del codice:
:00401409 mov edi, 004023B8
:0040140E add edi, 00000008
In teoria, giunti a questo punto del programma, la nostra creazione del file, dopo i
vari crypting sopra, sarebbe conclusa. Se però scriviamo una frase in semplice ASCII, a
partire dal nono byte(presupponendo corretti i primi 8), sulla Title-Bar del Trial,
comparirà il messaggio di registrazione avvenuta, a cui seguiranno degli strani simboli.
Questi non sono altro che una codifica della nostra stringa. La codifica fortunatamente,
è alquanto semplice. Nel blocco sopra, è stata infarcita da inutili istruzioni, ma essa
non fa altro che prelevare il valore ASCII ad esempio del carattere 'A', cioè 65, e
stampare il valore 0-65, cioè BF. Quindi per una corretta stampa, basterà fare
l'operazione inversa...
Passiamo allora a scrivere il nostro KEYFILEMAKER, impostando il reverse dei blocchi
sopra, in maniera ordinata. La prima parte ad essere creata, sarà proprio quella
riguardante il crypt del nome da stampare sulla Title-Bar. Perciò il nostro programma,
dopo aver ricevuto in ingresso la stringa da voler stampare, la crypterà come descritto
in precedenza. Ad esso seguirà poi la determinazione dei valori edx ed edx+4. Qui si è
proceduto, con un semplice Cut and Paste, ricopiando praticamente la routine originale, ed
apportando ad essa delle leggere modifiche. I valori edx ed edx+4 saranno salvati nella
piccola zona di memoria chiamata DataXor. Ora segue la determinazione di ciò che deve
essere inserito nei bytes 5-8. Per far ciò osserviamo il blocco originale che và
dall'indirizzo xxxx:004013e3 - xxxx:00401407. La seconda parte, a partire da
xxxx:004013f9, controlla se il valore contenuto nei bytes 5-8 è corretto. Mentre il
blocco prima di istruzioni, criptava questi dati. Allora basterà ottenere il valore
corretto ma criptato prima, e poi convertirlo nella corretta forma, ma non criptata.
Infine nel programma, attraverso l'uso del int 21h, si registra tutto il contenuto del
range di memoria chiamato File(cioè aprendo, salvando e chiudendo il file). Notate i
primi 4 bytes della zona File:sono quelli ottenuti col 'brute forcing'. Nient'altro.
Finalmente ecco il listato:
xor ecx, ecx
xor esi, esi
Start:
mov ah,09
mov dx,Intro
int 21h ; mostra intro msg
mov ah,0ah
mov dx,Namemem
int 21h ; preleva il nome da criptare
mov bl,0
mov eax,Namemem+2 ; nome salvato dal terzo byte (il byte 2 contiene la lunghezza)
mov esi,File+8 ; esi punta al nono byte del nostro file
CodeName: ; routine di conversione della stringa
mov cl,[eax]
sub [esi],cl
inc eax
inc esi
cmp [eax],bl
jne CodeName
dec esi
mov [esi],bl
xor ecx,ecx
xor esi,esi
mov edx,DataXor ; edx punta all'area dove si costruiranno i valori edx ed edx+4
mov eax,File
add eax,8
mov cl, [eax]
Ciclo1: ; routine che crea edx ed edx+4
inc eax
add [edx+04], ecx
xor [edx], cl
inc esi
mov cl,[eax]
cmp cl,0
jne Ciclo1
push esi
add [edx], esi
sub eax, esi
sub eax,4
push eax
mov esi,4
pop edi
mov eax, [edx+4]
pop ecx ; blocco di istruzioni per calcolare i bytes 5-8
shl eax,cl ; notare l'inversione dei blocchi
add eax, 039061982h ; notare le operazioni di calcolo inverse
mov cl,[edx]
mov edx,File+4
mov [edx],eax
Ciclo2:
xor [edx],cl ; blocco decriptato da salvare
inc edx
dec esi
loopnz Ciclo2
mov edx,File+4
mov eax,[edx]
mov ah,3ch
xor ecx,ecx
mov dx,nFile
int 21h ; apertura in scrittura del file 'crackme.key'
push ax
mov bx,ax
xor ax,ax
mov ah,40h
mov cx,08h
mov di,Namemem+1
add cl,[di]
mov dx,File
int 21h ; scrittura dei dati sul file
mov ah,3eh
pop bx
int 21h
mov ah,4ch
int 21h ; chiusura del file
org 100h
Intro db 'KeyFileMaker for Trial MemberShip of Cookie by blAAd!',13,10,'Insert Name: $'
nFile db 'crackme.key','$',0
File db 231,221,254,33
times 32 db 0
DataXor times 10 db 0
Namemem db 18h
times 32 db 0
|
Hey?? non vi sarete mica addormentati?! Non era poi così lungo... Spero al solito di non aver fatto troppi errori. Se avete segnalazioni da fare, please contact me. Nient'altro. Bye!!
Disclaimer |