Official CookieCrk Trial CrackMe


31/08/2000

by "blAAd!"

 

 

UIC's Home Page

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
E-mail: [email protected]
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??


Official CookieCrk Trial CrackMe
Soluzione del Official CookieCrk Trial CrackMe
Written by blAAd!

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

S-Ice
WDasm 8.93
Hex Work-Shop
Nasm 0.98
Hiew

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)
Anti-SICE protection
2)
Keyfile-based Registration
3)
Name/Code Registration
4)
Nag Screen

Possiamo 'patchare':

1)
Anti-SICE protection
2)
Kill the Nag


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
<------ Contiene la stringa "T[(YWJAD"
:00401511 mov ecx, 00000008
:00401516 call 00401595
<------ Converte la stringa sopra in "\\.\SICE"
:0040151B push 00000000
:0040151D push 00000003
:0040151F push 00000000
:00401521 push 00000000
:00401523 push 00000000
:00401525 push 00000000
:00401527 push 004024C7
<------ Contiene la stringa "T[(YWJAD"
:0040152C Call 0040169E
<------ CreateFileA
:00401531 cmp eax, FFFFFFFF
<------ Se SICE non è presente non chiude il programma
:00401534 je 00401541
:00401536 push eax
:00401537 Call 0040167A
<------ CloseHandle
:0040153C jmp 00401090

Jump at Address:
|:00401534
|
:00401541 mov edi, 004024C7
<------ Contiene la stringa "T[(YWJAD"
:00401546 mov ecx, 00000008
:0040154B call 00401595
<------ Ricripta "\\.\SICE" in "T[(YWJAD"
:00401550 mov edi, 004024D0
<------ Contiene la stringa "UT)ZKPJAD"
:00401555 mov ecx, 00000009
:0040155A call 00401595
<------ Converte la stringa in "\\.\NTICE"
:0040155F push 00000000
:00401561 push 00000003
:00401563 push 00000000
:00401565 push 00000000
:00401567 push 00000000
:00401569 push 00000000
:0040156B push 004024D0
<------ Contiene la stringa "UT)ZKPJAD"
:00401570 Call 0040169E
<------ CreateFileA
:00401575 cmp eax, FFFFFFFF
<------ Se non è presente continua
:00401578 je 00401585
:0040157A push eax
:0040157B Call 0040167A
<------ CloseHandle
:00401580 jmp 00401090

Jump at Address:
|:00401578
|
:00401585 mov edi, 004024D0
<------ Contiene la stringa "UT)ZKPJAD"
:0040158A mov ecx, 00000009
:0040158F call 00401595
:00401594 ret


CALL at Addresses:
|:00401516 , :0040154B , :0040155A , :0040158F
|
:00401595 xor byte ptr [edi], cl
<------ Semplice routine di de/codifica delle stringhe sopra
:00401597 inc edi
:00401598 loop 00401595
:0040159A ret

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
<------ ShowWindow
:004011C6 E8A7020000 call 00401472
<------ Routine che imposta la bitmap col logo
:004011CB FF3504204000 push dword ptr [00402004]
:004011D1 E83A050000 Call 00401710
<------ UpdateWindow
:004011D6 68D0070000 push 000007D0
<------ 2000 millisecondi di attesa
:004011DB E8B8040000 Call 00401698
<------ Sleep
:004011E0 FE0514204000 inc byte ptr [00402014]
:004011E6 FF3504204000 push dword ptr [00402004]
:004011EC Call 004016AA
<------ DestroyWindow
:004011F1 ret

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
<------ Imposta finestra
:004010DE call 004011B9
<------ Mostra finestra, bitmap, ecc...
.
.
.

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
<------ Nome
:00401233 push 000003E8
:00401238 push [ebp+08]
:0040123B Call 004016DA
<------ GetDlgItemTextA
:00401240 cmp eax, 00000000
:00401243 je 004012B0
<------ Se la stringa è vuota esce
:00401245 push 00000100
:0040124A push 004022AB
<------ Codice
:0040124F push 000003E9
:00401254 push [ebp+08]
:00401257 Call 004016DA
<------ GetDlgItemTextA
:0040125C cmp eax, 00000000
:0040125F je 004012B0
<------ Se la stringa è vuota esce
:00401261 mov dword ptr [004023AC], eax
:00401266 call 0040150C
<------ Controllo Anti-SICE
:0040126B mov ecx, dword ptr [004023AC]
:00401271 cmp ecx, 0000000A
<------ Il codice deve essere lungo max 10 caratteri
:00401274 jle 0040127B
:00401276 mov ecx, 0000000A

Jump at Address:
|:00401274
|
:0040127B mov esi, 004022AB
<------ esi -> codice
:00401280 mov edi, 0040225A
<------ edi -> codice
:00401285 call 004012C9
<------ Converte il seriale nel suo valore hex
:0040128A call 004012F7
<------ Routine di codifica
:0040128F test eax, eax
:00401291 je 0040159B
<------ Se il codice è errato esce
:00401297 sub dword ptr [004023AC], 0000000A
:0040129E cmp dword ptr [004023AC], 00000000
:004012A5 jne 0040159B
<------ La stringa del codice deve essere lunga 10 caratteri altrimenti esce
:004012AB jmp 004015B4
<------ Visualizza messaggio di seriale corretto

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
<------ ecx = 0
:004012F9 xor eax, DEADDEAD
<------ eax punta al seriale in hex
:004012FE ror eax, 07
<------ Semplici operazioni che agiscono su eax
:00401301 dec eax
:00401302 rol eax, 03

Jump at Address:
|:0040131E
|
:00401305 mov ebx, dword ptr [edi]
<------ edi -> nome
:00401307 not ebx
<------ ebx contiene i caratteri del nome a 4 a 4
:00401309 xor bh, bl
<------ Seguono semplici operazioni su ebx
:0040130B rol ebx, 03
:0040130E inc ebx
:0040130F ror ebx, 07
:00401312 add ebx, dword ptr [edi]
:00401314 add edi, 00000004
<------ edi punta ai successivi 4 caratteri
:00401317 add ecx, ebx
<------ Viene aggiornato ecx
:00401319 cmp byte ptr [edi], 00
<------ Controlla se siamo a fine nome
:0040131C je 00401320
:0040131E jmp 00401305
<------ Altrimenti continua a ciclare

Jump at Address:
|:0040131C
|
:00401320 add ebx, ecx
:00401322 add eax, ebx
<------ eax = eax + ebx + ecx
:00401324 sub eax, 12121212
<------ Questa sottrazione deve dare eax = 0
:00401329 je 0040132F
:0040132B xor eax, eax
:0040132D jmp 00401334
<------ Altrimenti il codice è errato

Jump at Address:
|:00401329
|
:0040132F mov eax, 00000001

Jump at Address:
|:0040132D
|
:00401334 ret

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
<------ Nome del file 'crackme.key'
:00401361 Call 0040169E
<------ CreateFileA
:00401366 cmp eax, FFFFFFFF
:00401369 je 00401471
<------ Se il file non esiste esce
:0040136F mov dword ptr [00402008], eax
:00401374 push 00000000
:00401376 push 004024B7
:0040137B push dword ptr [004024B7]
<------ Lunghezza del file
:00401381 push 004023B8
<------ Dove sarà allocato il file
:00401386 push dword ptr [00402008]
:0040138C Call 004016A4
<------ ReadFile
:00401391 cmp eax, 00000000
:00401394 je 00401466
<------ Se il file è vuoto esce
:0040139A cmp dword ptr [004024B7], 00000000
:004013A1 je 00401466
<------ Se i primi 4 bytes del file sono nulli esce
...
...
...
...
:00401466 push dword ptr [00402008]
:0040146C Call 0040167A
<------ CloseHandle

Jump at Address:
|:00401369
|
:00401471 ret
<------ Esce

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 memoria
:004013AC mov edi, dword ptr [eax]
<------ Preleva i primi 4 bytes del file
:004013AE shr edi, 05
<------ Codifica i 4 bytes con breve serie di istruzioni
:004013B1 xor edi, 05E30A78
:004013B7 imul edi, dword ptr [eax]
:004013BA shl edi, 03
:004013BD add eax, 00000008
<------ Intanto porta eax a puntare 8 bytes dopo
:004013C0 xor edi, E5C23A08
:004013C6 jne 00401466
<------ Esce

Questa 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
<------ edx punta 68 bytes più avanti, dall'origine del file
:004013D1 xor ecx, ecx
<------ ecx = 0
:004013D3 xor esi, esi
<------ edx = 0

Jump at Address:
|:004013E1
|
:004013D5 mov cl, byte ptr [eax]
<------ Preleva ogni singolo byte del file a partire dal nono
:004013D7 inc eax
:004013D8 add dword ptr [edx+04], ecx
<------ edx+4 contiene un dato importante per il crypting
:004013DB xor byte ptr [edx], cl
<------ edx un altro dato importante per il crypting
:004013DD inc esi
:004013DE cmp byte ptr [eax], 00
<------ Continua a ciclare fino alla fine del file
:004013E1 jne 004013D5

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
<------ Al valore in edx somma la lunghezza della stringa
:004013E6 mov cl, byte ptr [edx]
<------ Preleva il primo byte di edx
:004013E8 sub eax, esi
:004013EA sub eax, 00000004
<------ eax punta ora al quinto byte del file
:004013ED push eax
:004013EE mov esi, 00000004
:004013F3 xor byte ptr [eax], cl
<------ Inizio mini-ciclo
:004013F5 inc eax
:004013F6 dec esi
:004013F7 loopnz 004013F3
<------ Cicla dal quinto all'ottavo byte
:004013F9 pop edi
:004013FA mov eax, dword ptr [edx+04]
<------ Inizio controllo sul valore in edx+4
:004013FD pop ecx
:004013FE shl eax, cl
<------ Breve serie di operazioni su eax
:00401400 add eax, 39061982
:00401405 sub eax, dword ptr [edi]
:00401407 jne 00401466
<------ Se il valore non è corretto esce

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
<------ Punta al nono byte del file
:00401411 mov ebx, edi
:00401413 add ebx, 00000070
<------ ebx punta 78 byte in avanti dall'origine del file
:00401416 push ebx
:00401417 push ecx

Jump at Address:
|:00401426
|
:00401418 mov word ptr [ebx], 0100
<------ Completamente inutile
:0040141D mov cl, byte ptr [edi]
<------ cl contiene ogni singolo carattere della stringa
:0040141F sub byte ptr [ebx], cl
<------ [ebx] = [ebx] - cl
:00401421 inc ebx
:00401422 inc edi
:00401423 cmp byte ptr [edi], 00
<------ Continua a ciclare fino alla fine della stringa
:00401426 jne 00401418
:00401428 dec byte ptr [ebx]
:0040142A pop ecx
:0040142B inc ecx
:0040142C pop ebx
:0040142D mov edi, 004023B8
:00401432 dec edi
:00401433 mov dword ptr [edi], 67657220
<------ Qui inizia la stringa 'CrackMe registered to:'
:00401439 mov [edi+04], 65747369
:00401440 mov [edi+08], 20646572
:00401447 mov [edi+0C], 203A6F74
:0040144E add edi, 00000010
:00401451 mov esi, ebx
:00401453 repz
:00401454 movsb
<------ Copia la stringa col nostro nome
:00401455 push 004023B0
<------ Contiene la stringa "CrackMe"
:0040145A push 00000000
:0040145C push 0000000C
:0040145E push [ebp+08]
:00401461 Call 00401704
<------ SendMessageA

Jump at Addresses:
|:00401394, :004013A1, :004013C6, :00401407
|
:00401466 push dword ptr [00402008]
:0040146C Call 0040167A
<------ CloseHandle

Jump at Address:
|:00401369
|
:00401471 ret
<------ Esce

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


tHe EnD!?

-eLeNg-


Note finali

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

Questo tutorial è a solo scopo informativo. Ne io, ne i possessori del sito, siamo responsabili di un eventuale abuso di ciò che è stato trattato, per scopi di pirateria e violazione di copyright. In qualsiasi caso rubare è sbagliato, e i vari tutorial presenti sul sito dovrebbero aiutare a comprendere l'impegno profuso da parte dei programmatori, per la creazione d'ogni singolo programma.