Corso UIC n° 5
(serial fisso, serial generato, keyfile)


10/01/2000

by Ritz

 

 

UIC's Home Page

Published by Quequero


Bellissimo tute Ritz...Se solo avessi consegnato prima!

UIC's form
E-mail: ritz@freemail.it
Ritz, UIN: 41793377, #crack-it, #uic
UIC's form

Difficoltà

( )NewBies ( )Intermedio (X)Avanzato (X)Master

 

Ciao a tutti raga!! Tanto per cominciare vi dico semplicemente una cosa: io stesso ho capito tutto il funzionamento del crackme solo dopo aver scritto l'ultimo byte di questo tute, quindi sicuramente il programmillo di Que come esercizio non è niente male :)).


Corso UIC n° 5
(serial fisso, serial generato, keyfile)
Written by Ritz

Scaricate qui l'allegato

Introduzione

Beh che dire, in questo tute cercherò semplicemente di andare passo passo nel reversing del programma superando uno ad uno i vari "ostacoli" man mano che si presentano.

Tools usati

SoftICE 4.00
W32Dasm 8.93
Hiew 6.16
IceDump 5 (non indispensabile ma molto utile)
TASM 5 (per il keygen)

URL o FTP del programma

http://quequero.cjb.net

Notizie sul programma 

Il programma da reversare presenta varie fasi da superare: innanzi tutto ci sono in giro dei trick anti-Sice facilmente rimovibili; una volta che si riesce ad avviare il programma questo chiede l'inserimento di un serial fisso; dopo di questo si passa all'immissione di un nick e di un serial calcolato in base ad esso, e, infine, alla lettura di un keyfile mooooooltooo ma mooooltoo bastardo in quanto a crittazione.
Lo scopo è naturalmente quello di trovare qual'è il serial fisso, di trovare un serial adatto al proprio nick, un keyfile anch'esso variabile, far apparire la box di registrazione e infine scrivere un keygenerator che generi sia serial che keyfile validi (ma vaaaaa??!?!).

Essay

Raga, armatevi dei tool sopra, di un bel po' di pazienza, e partiamo col reversing!!

Dunque, avete scaricato il prog vero? Beeeneee, avviatelo... okkazzo, appena avviato il prog. appare una box che ci dice "Chi usa Softice alzi la manoooo!!". ma che è, non si può nemmeno usare il Sice in pace adesso? vabbè, visto che il prog non si avvia non abbiamo altre possibilità se non quella di crackare la protezione anti-Sice (a meno di non avviare il pc senza caricare il WinIce.exe, cosa però improbabile visto che senza Sice non possiamo fare un cazzo ;)) ). Avviate quindi il Win32Dasm, aprite l'eseguibile, bene almeno si disassembla regolamente. Avete presente il testo della messagebox cosa diceva? Bene allora cerchiamo nelle String Data References del prog. (solito penultimo pulsante da dx della barra) e cerchiamo qulalcosa di utile... bene bene la stringa della box fortunatamente c'è: doppioclicchiamoci sopra e finiremo in questo punto del codice:

* Jump at Address:
|:00401542(C)
|
:004011EE    push 00000030

* Possible StringData Ref from Data Obj ->"SoftIce detected!!!"
                                 
:004011F0    push 0040362D  

* Possible StringData Ref from Data Obj ->"Chi usa SoftIce alzi la manoooo!!! "
                                        ->":)"
                                 
:004011F5    push 00403641   ;Testo della MessageBox
:004011FA    push 00000000

* Reference To: USER32.MessageBoxA, Ord:0000h
                                 
:004011FC    Call 00401EA3   ;Chiamata alla box

* Reference To: KERNEL32.ExitProcess, Ord:0000h
                                 
:00401201    Call 00401E2B   ;Uscita dal programma

Osservando il codice vediamo che il salto a questo punto di codice si trova a 401542, e che proprio questo punto di codice ci fa uscire dal prog dopo averci mostrato la box. Andando quindi a 401542 troveremo questa parte di codice:

* Reference To: USER32.GetWindowTextA, Ord:0000h

:00401522    Call 00401EC7
:00401527    call 0040167F
:0040152C    call 00401B79
:00401531    call 00401BCE
:00401536    mov ebp, 4243484B
:0040153B    mov ax, 0004
:0040153F    int 03
:00401540    cmp al, 04
:00401542     jne 004011EE
:00401548    mov esi, 00402BFC
:0040154D    mov edi, 004025F0
:00401552    mov ecx, dword ptr [004031FC]
:00401558    repz
:00401559    cmpsb
:0040155A    je 00401DE9

Hum... vediamo qui che prima di questo salto c'è una chiamata a un GetWindowTextA... sembra un po' strana la cosa, non penso che sia quello che ci interessa... cmq qui possiamo vedere un esempio di trick anti SoftIce: in ebp (Base Pointer, puntatore alla base dello stack) viene messo il valore 4243484B, in ax il valore 4, e quindi viene chiamato l'int 03. Ze lo ZeroFlag non si attiva allora il Sice è in memoria, come potete vedere :)). Btw, segnamoci l'offset del je (B42), apriamo Hiew, andiamo a quell'Offset (F4, Decode, F5, B42), premiamo F3 e cambiamo il je in un jne (opcode da 85 a 84), anzi meglio ancora noppiamolo completamente, visto che quel salto non deve mai verificarsi.

ATENZIONE: probabilmente è superfluo dirlo, ma nel caso si noppi l'istruzione non è consigliabile noppare solo il byte 85, ma è meglio farlo con tutta l'istruzione, cioè bisogna cambiare tutta la sequenza 0F84A6FCFFFF in 909090909090, in quanto noppando solo uno dei 6 byte si rischia che gli altri vadano per conto loro (in questo caso facendo così non succede nulla, almeno a me, ma potrebbe benissimo capitare che un prog. crashi o esegua poi operazioni non valide, tanto per citare il caro WinSux): modifichiamo la parte che vogliamo con Hiew, usciamo e riavviamo tutto il prog... niente la box appare ancora. Non ci resta che guardare di nuovo nelle references del WinDasm: richiccliamo sulla strigna della box, e questa volta capitiamo qui:

* Jump at Address:
|:004010E3(C)
|
:00401406    push 00000030

* Possible StringData Ref from Data Obj ->"SoftIce detected!!!"
                            
:00401408    push 0040362D

* Possible StringData Ref from Data Obj ->"Chi usa SoftIce alzi la manoooo!!! "
                                        ->":)"
                             
:0040140D    push 00403641
:00401412    push 00000000

* Reference To: USER32.MessageBoxA, Ord:0000h
                      
:00401414    Call 00401EA3

* Reference To: KERNEL32.ExitProcess, Ord:0000h
                         
:00401419    Call 00401E2B

La scena è esattamente la stessa della precedente, la solita box, la solita uscita dal prog.. Questa volta andiamo un po' a vedere cosa c'è a 4010E3 (dove avviene il salto)...

* Reference To: USER32.GetDlgItem, Ord:0000h

:004010D1    Call 00401E79
:004010D6    mov dword ptr [00402024], eax
:004010DB    mov ah, 43
:004010DD    int 68
:004010DF    cmp ax, F386
:004010E3    jne 00401406
:004010E9    push dword ptr [00402028]

Questa volta il salto avviene dopo una chiamata a GetDlgItem, funzione che serve per riportare l'handle di un qualsiasi controllo in una dialog-box... hum strano anche questo: questa funzione infatti viene eseguita si all'avvio, ma deve essere eseguita solo dopo che la dialox-ox è stata creata, mentre da noi questo nemmeno è avvenuto... vabbè non importa, qui il trick consiste nel muovere 43 in ah, chiamare l'int 68, e vedere se ax = F386 (un magico numeretto che non viene restituito se c'è il Sice in memoria); noppiamo cmq l'istruzione, salviamo e riavviamo... com'era prevedibile anche stavolta il prog mostra la stessa box, ridoppioclicchiamo nelle references (questa giuro è l'ultima volta :)) ), ed eccoci qui:

* Jump at Address:
|:0040106A(C)
|
:00401B3E    push 00000030

* Possible StringData Ref from Data Obj ->"SoftIce detected!!!"

:00401B40    push 0040362D

* Possible StringData Ref from Data Obj ->"Chi usa SoftIce alzi la manoooo!!! "
                                        ->":)"

:00401B45    push 00403641
:00401B4A    push 00000000

* Reference To: USER32.MessageBoxA, Ord:0000h

:00401B4C    Call 00401EA3

* Reference To: KERNEL32.ExitProcess, Ord:0000h

:00401B51    Call 00401E2B

Non cambia assolutamente nulla... per l'ultima volta andate a 4010A6:

//******************** Program Entry Point ********
:00401000    mov dword ptr [004033A9], 00000030
:0040100A    mov dword ptr [004033AD], 00000003
:00401014    mov dword ptr [004033B1], 00401154
:0040101E    mov dword ptr [004033B5], 00000000
:00401028    mov dword ptr [004033B9], 0000001E
:00401032    mov eax, dword ptr [00402018]
:00401037    mov dword ptr [004033BD], eax
:0040103C    call 00401B56
:00401041    push 00000065
:00401043    push dword ptr [00402018]

* Reference To: USER32.LoadIconA, Ord:0000h
                                 

:00401049    Call 00401E97
:0040104E    mov dword ptr [004033C1], eax
:00401053    mov dword ptr [004033D5], eax
:00401058    call 004014D0
:0040105D    mov dword ptr [00402024], eax
:00401062    mov ah, 43
:00401064    int 68
:00401066    cmp ax, F386
:0040106A    jne 00401B3E
:00401070    push 00007F00
:00401075    push 00000000

Finalmente!! Come avrete notato siamo all'inizio del programma, e a parte il LoadIcon non viene fatto praticamente nulla... quindi probabilmente abbiamo trovato il punto giusto, e il trick è lo stesso di prima... noppiamo quindi con Hiew l'istruzione a 40106A, avviamo il tutto, e... parte tutto regolarmente. A questo punto, visto che i riferimenti a quella stringa di testo erano solo 3 e sono stati crackati tutti, possiamo dire che i trick anti-Sice non ci disturberanno + per il resto del reversing (infatti il primo analizzato si sarebbe intromesso chiudendo il prog. durante il controllo del keyfile, il secondo appena avviato il prog., il terzo prima ancora di avviarlo ;)) perfetto... il meno è fatto. :))

Non ci resta ora che immergerci nel reversing vero e proprio. Una volta avviato il prog. apparirà una Dialog-Box con 2 edit-box, 3 pulsanti, una scritta in basso, climatizzatore, ABS, quadruplo airbag.... erm no lasciamo stare... gli effetti della notte di capodanno come potere vedere hanno anche su di me degli strascichi :)). Vabbè dai ora però iniziamo sul serio con la

()()()()()()()()()()()()()()()()()()()()

PARTE 1: SERIAL F ISSO

()()()()()()()()()()()()()()()()()()()()

PREMESSA: riavviate ogni volta il programma prima di analizzare per la seconda volta la situazione, state attenti a non poppare nell'Ice due volte di seguito senza riavviare il crackme, in quanto anche se il 1° serial è sbagliato l'esecuzione continua senza alcun avviso tramite box varie, e quindi si passerebbe direttamente al 2° check pensando di essere sul 1°, quindi attentiiiiiiiii!! Riavviate ogni volta ok?

Ebbene sì, innanzi tutto la prima cosa da fare è quella di trovare il serial fisso da inserire nella prima text-box. Heheh, raga preparatevi bene perchè da adesso il Sice lo useremo un bel po' :). Visto che il prog. deve prendere del testo da noi inserito, entriamo (con CTRL-D) nel debugger, e settiamo un breakpoint su GetWindowTextA (la funz. scelta da Que per leggere il testo... non chiedetemi come ho fatto a capirlo perchè altrimente so' guai :)) con il solito "bpx GetWindowTextA": messo il bp? Bene, ora inserite del testo nella prima casella, premete "Register" ed ecco il Sice che poppa. Premete F11 per uscire dalla funzione, ed eccovi qui:


:0040123A    push 0000000C   ;max lunghezza del testo da prendere
:0040123C    push 00403273   ;Buffer dove viene messo il testo
:00401241    push dword ptr [00402030]   ;Handle della edit-box da cui prenderlo

* Reference To: USER32.GetWindowTextA, Ord:0000h

:00401247    Call 00401EC7   ;Chiamata all'API
:0040124C    call 0040159C   ;Per ora *dimenticate* questa CALL
:00401251    xor ecx, ecx

* Jump at Address:
|:00401261(C)
|

|:00401253    xor dword ptr [ecx+00403273], 000000ED
|:0040125D    inc ecx
| :0040125E    cmp ecx, 0000000C
|-:00401261   jne 00401253

:00401263     xor ecx, ecx

* Jump at Address:
|:00401289(C)
|

|:00401265    xor dword ptr [ecx+00403273], 134F7432
|:0040126F    xor dword ptr [ecx+00403273], 4A710930
| :00401279    xor dword ptr [ecx+00403273], 58D71DE6
|:00401283    add ecx, 00000004
|:00401286    cmp ecx, 0000000C

|-:00401289   jne 00401265

* Reference To: KERNEL32.GetTickCount, Ord:0000h

:0040128B    Call 00401E61
:00401290    xor dword ptr [00403273], eax
:00401296    xor dword ptr [00403277], eax
:0040129C    xor dword ptr [0040327B], eax
:004012A2    xor dword ptr [0040327F], eax
:004012A8    xor dword ptr [00403283], eax
:004012AE    xor dword ptr [00403287], eax
:004012B4    and dword ptr [0040327F], 00627893
:004012BE    and dword ptr [00403273], 00627893
:004012C8    mov esi, 00403273

* Possible StringData Ref from Data Obj ->"J"

:004012CD    mov edi, 0040327F
:004012D2    mov ecx, 0000000C
:004012D7    repz
:004012D8    cmpsb
:004012D9    je 00401300
:004012DB    nop
:004012DC    nop
:004012DD    nop
:004012DE    nop
:004012DF    mov dword ptr [0040329B], 0000F892
:004012E9    jmp 0040130A
:004012EB    nop
:004012EC    nop
:004012ED    nop

....................

:00401300    mov dword ptr [0040329B], 0000F896

....................

Allora, analizziamo un po' quello che ci capita davanti... a 401247 c'è la chiamata all'API, e subito dopo c'è un'altra CALL... in teoria ora a voi verrebbe da pensare di entrarci subito con un bel F8, ma questa CALL ci risulterà utile in seguito: per ora ai fini del serial fisso non serve assolutamente a nulla, e visto che occuperei byte inutili descrivendola ora, la spiegherò quando sarà necessario... :pp. Per ora potete pure cancellarla dai vostri buffer cerebrali :).

Dunque, detto questo per rendere meno incasinato il tutto possiamo proseguire.

Vediamo subito dopo la chiamata all'API che ecx viene azzerato, e poi il valore della dword puntata da [ecx+403273] viene xorato con ED, quindi ecx viene incrementato di 1, viene confrontato con il valore C (12 dec) e se non è uguale allora il prog. jumpa di nuovo a 401253 per un nuovo xor... ad esempio se inseriamo come serial fisso la stringa "abcdefgh" abbiamo che prima viene xorato a (infatti la prima volta ecx = 0), poi b (la seconda volta ecx = 1 e quindi il buffer è 1 + 403273 = 403274, che punta proprio alla seconda lettera del nome), e così via, fino alla 12a lettera del nick, quindi ecco già analizzata una prima manipolazione.

Proseguendo col codice vediamo che inizia una seconda manipolazione del buffer così ottenuto, cioè (dopo aver azzerato ecx) il nick viene xorato dword per dword con 3 valori alla volta, ovvero la prima dword del nome (i primi 4 charz) viene xorata prima con 134F7432, poi con 4A710930, infine con 58D71DE6, in tutto le dword manipolate allora sono 4, quindi (4 dword) * (4 char ogni dword) = (12 caratteri). Visti questi primi due cicli, possiamo già presumere allora la lunghezza del nome, che sarà probabilmente (non di sicuro però) di 12 caratteri.

Andiamo ancora avanti... una volta finito il ciclo infatti avviene una chiamata a un'API, GetTickCount.. cosa fa quest'API? Ecco la definizione del C++: "The GetTickCount function retrieves the number of milliseconds that have elapsed since Windows was started." La cosa è semplicissima: dopo questa chiamata in eax (che contiene SEMPRE il valore di ritorno di un'API se l'API ne ha uno) troviamo come valore di ritorno proprio il numero di millisecondi passati dall'avvio di Windows. Cosa possiamo dedurne? Che l'API può essere moooltoo utile per generare valori casuli o pseudo-casuali. Ma come??? Non aveveamo detto che il primo serial era fisso? E allora come può esser genearto a partire da numeri random??

Hehe, certo che il serial fisso, e infatti proseguiamo ancora per vedere il tutto meglio... all'indirizzo 4012D7 c'è una paticolare istruzione, repz, seguita da cmpsb... a che serve? Allora, una volta mosso in esi l'offset di un primo buffer, che serve come 1° termine di confronto, in edi l'offset del buffer del 2° termine di confronto e in ecx un valore (contatore), con queste 2 istruzioni si confrontano byte per byte i due buffer puntati da esi ed edi fino a ecx byte, cioè se ecx = 6 allora i buffer puntati da edi ed esivengono confrontati per 6 byte... se questi 6 byte essi sono uguali lo ZeroFlag viene settato a 1, altrimenti a 0. Bene... dopo qusta breve spiegazione sappiamo che la verifica della stringa inserita da noi avviene proprio qui, e quindi conosciamo i due buffer (il primo, 40326F, contiene il nostro serial manipolato, il secondo, 40327F, contiene quello reale) e il numero di byte di confronto, C, quindi il serial sarà di 12 caratteri (hihihihihihihi :pp).

Adesso torniamo a noi: abbiamo detto che il serial giusto è in 40327F... controlliamo un po' la serie di xor che ci sono dopo la chiamata a GetTickCount: ce ne sono due che ci interessano molto... uno è a 401290, l'altro a 4012A2: qui rispettivamente il valore da noi inserito e il serial valido manipolato vengono xorati col valore di eax... ecco perchè anche se esso è un valore casuale, si può ugualmente utilizzare! Infatti, supponendo di avere due numeri a = 4 e b = 4, xorandoli entrambi con un valore c che vogliamo, otterremo che i risultati ottenuti sanno sempre uguali, naturalmente, e quindi qui vale lo stesso discorso. Dopo la serie di xor inoltre c'è un'addizione (logica) tra la prima dword del primo buffer e un  valore e poi tra la prima dword del secondo buffer e lo  stesso valore: visto il ragionamento appena fatto, quindi, abbiamo che PRIMA dei vari xor coi valori ottenuti da GetTickCount i valori dei due buffer di riferimento devono coincidere per forza. Ora, per trovare il serial corretto, ci sarebbero vari modi... si potrebbe far si che all'indirizzo 40128B i due buffer siano uguali: essendo infatti 40327F fisso, infatti, bisognerebbe far sì che dopo i due cicli tra 401251 e 401289 il buffer 403273 risulti ad esso uguale, e ciò si potrebbe ottenere semplicemente facendo tutti e due i cicli ponendo come valore di partenza proprio il valore di 40327F invece che 403273, e ciò si può facilmente fare inserendo come testo del serial la stringa di 40327F. Ecco il suo valore:

  BUFFER               STRINGA ASCII CORRISPONDENTE (12 byte)

:0040327F                  Jÿ0‚K«Vž8¾ ì

  (da ricordare che la stringa deve essere di 12 byte)

Nota: io la stringa di testo me la sono presa col l'IceDump (che in seguito risulterà molto ma molto utile), cmq per ottenerla basta prendersi i rispettivi valori byte per byte, convertirli in dec e scrivere ALT[valore_dec1], ALT[valore_dec2], ......., ALT[valore_dec12] come testo del serial... o meglio copiate e pastate quelli sopra... fatto? Beenee ora premete "Register" sempre col bpx settato, mi raccomando... ecco il Sice che poppa... senza steppare andate fino a 40128B col cursore del mouse, cliccate su quella riga una volta, scrivere here, premete invio, scrivete "d 40327F" ed eccovi comparire davanti il vostro amatissimo serial!!

Vediamo un po' che è 'sto buffer ottenuto:

  BUFFER               STRINGA ASCII CORRISPONDENTE (12 byte)

:00403273                  Cr4nB&Rr13$ì

A voi dice qualche cosa?  Hum... Cr4nB&Rr13$ì... ma sììì, dai!! Cranberries!! Hehe ecco il mistero della musica irlandese collegato al primo serial!! Aspè... ma Cranberries è di 11 caratteri, non 12, quella "ì" che cazzo ci fa lì?? Proviamo a toglierla: scrivete come serial "Cr4nB&Rr13$"... solito bpx, steppiamo pure fino a 4012D9, azz il Flag Z si attiva!! Mumble mumble... sempre dopo aver riavviato tutto scriviamo come serial "Cr4nB&Rr13$4tciun44tv45byi4b" (vabbè se volete anche + corto :)) ), premiamo Register, usciamo dalla funzione dell'Ice e scriviamo "d 402373"... ahhhhh ma allora ditelo ehhhh?? Hehe come potete vedere il prog. prende solo i primi 11 caratteri del serial, in quanto l'unico 12° byte che una volta manipolato dà come risultato EC (il 12° byte del buffer 40327F), può essere solamente 00, quindi il prog lo inserisce da sè alla 12a posizione dopo aver messo come primi 11 byte gli 11 caratteri inziali della nostra stringa. Semplice no?? Abbiamo trovato il serial fisso.

OK finalmente abbiamo finito questa parte... ora passiamo pure alla seconda parte del reversing... però con una piccola nota: raga da qui sarò + sintetico perchè se per la prima parte, che era molto facile ho consumato tutto questo spazio, quando arrivo al keyfile mi viene un'enciclopedia... quindi attenti eh?!? ;)) Veniamo alla

()()()()()()()()()()()()()()()()()()()()

PARTE 2: SERIAL GENERATO

()()()()()()()()()()()()()()()()()()()()

ARIPREMESSA: una volta passato il 1° check potete pure fare a meno di riavviare ogni volta per reversare il 2°, basta che vi ricordiate ogni volta che avviate il prog. di passare una volta il primo, anche inserendo un serial fisso a caso e premendo "Register", perchè solo dopo aver premuto il pulsante la 1a volta si può arrivare a questo punto. Ok adesso continuiamo :)).

Bene raga!! Allora, una volta arrivati al repz cmpsb tra i due buffer relativi alla password c'è una cosa interessante da notare: si passa in ogni caso al 2° check, ma se il serial non è corretto nel buffer 40329B viene spostato il valore F892, mentre se è corretto viene spostato il valore F896... e ciò ci sarà molto utile per il seguito. Ora cmq passiamo al reversing del 2° check.

Dunque dunque, una volta passato il cmp uscite dall'Ice con CTRL+D... vedrete la casella in altro che si cancella (con la funzione SetWindowTextA) e la situazione si tranquillizza, in pratica ora il prog non fa nulla finche non premiamo di nuovo il pulsante "Register". Questa volta però provando a mettere il solito bpx con l'Ice vi accorgerete che il debugger poppa 2 volte... hehe è naturale quindi che stavolta i valori presi sono 2, e quindi siamo di fronte alla generazione del nostro serial... eccovi di seguito tutta la routine di questo check con sotto i vari commenti (metto il codice sviluppando tutte le CALL, come si presenterebbe cioè in real-mode col debugger, così si può leggere linearmente senza preoccuparsi troppo dei jump vari ed è pure + facile da scrivere :)) ).

* Jump at Address:
|:0040120D(C)
|
:00401323    push 00000014
:00401325    push 00403249
:0040132A    push dword ptr [00402030]

* Reference To: USER32.GetWindowTextA, Ord:0000h

:00401330    Call 00401EC7
:00401335    mov dword ptr [00403241], eax
:0040133A    cmp eax, 00000006
:0040133D    jl 0040141E

 

* Jump at Address:
|:0040133D(C)
|
:0040141E    pushad
:0040141F    push 00000010

* Possible StringData Ref from Data Obj ->"Attenzione!!!"
                   
:00401421    push 004034E8

* Possible StringData Ref from Data Obj ->"Attenzione, il numero inserito "
                                        ->"deve"
                    
:00401426    push 004034F6
:0040142B    push 00000000

* Reference To: USER32.MessageBoxA, Ord:0000h
                       
:0040142D    Call 00401EA3
:00401432    popad
:00401433    jmp 00401108

 

* Reference To: KERNEL32.GetTickCount, Ord:0000h

:00401343    Call 00401E61
:00401348    mov dword ptr [0040323D], eax
:0040134D    xor ecx, ecx
:0040134F    xor ebx, ebx
:00401351    mov edx, dword ptr [0040324A]
:00401357    mov eax, dword ptr [00403249]
:0040135C    imul eax, edx
:0040135F    mov dword ptr [00403249], eax
:00401364    xor ecx, ecx
:00401366    add ecx, 00000004
:00401369    dec dword ptr [00403241]

* Jump at Address:
|:00401388(C)
|
:0040136F    inc ecx
:00401370    mov al, byte ptr [ecx+00403249]
:00401376    add al, byte ptr [ecx+0040324A]
:0040137C    mov byte ptr [ecx+00403249], al
:00401382    cmp ecx, dword ptr [00403241]
:00401388    jl 0040136F
:0040138A    mov eax, dword ptr [00403249]
:0040138F    mov ebx, dword ptr [0040324D]
:00401395    imul eax, ebx
:00401398    mov dword ptr [00403249], eax
:0040139D    inc dword ptr [00403241]
:004013A3    xor ecx, ecx
:004013A5    mov ecx, dword ptr [00403241]

* Jump at Address:
|:004013BF(C)
|
:004013AB    mov eax, dword ptr [ecx+00403249]
:004013B1    xor eax, 04CF580F
:004013B6    mov dword ptr [ecx+00403249], eax
:004013BC    dec ecx
:004013BD    test ecx, ecx
:004013BF    jne 004013AB
:004013C1    call 00401438

 

* Referenced by a CALL at Address:
|:004013C1  
|
:00401438    mov ecx, dword ptr [00403241]

* Jump at Address:
|:00401466(C)
|
:0040143E    mov al, byte ptr [ecx+00403249]

* Jump at Addresses:
|:0040146E(U), :00401476(U)
|
:00401444    cmp al, 30
:00401446    jl 00401468
:00401448    nop
:00401449    nop
:0040144A    nop
:0040144B    nop
:0040144C    cmp al, 39
:0040144E    jg 00401470
:00401450    nop
:00401451    nop
:00401452    nop
:00401453    nop
:00401454    mov byte ptr [ecx+00403249], al
:0040145A    dec ecx
:0040145B    test ecx, ecx
:0040145D    cmp ecx, 00000002
:00401460    je 00401478
:00401462    nop
:00401463    nop
:00401464    nop
:00401465    nop
:00401466    jne 0040143E

* Jump at Addresses:
|:00401446(C), :0040146C(C)
|
:00401468    add al, cl
:0040146A    cmp al, 30
:0040146C    jl 00401468
:0040146E    jmp 00401444

* Jump at Addresses:
|:0040144E(C), :00401474(C)
|
:00401470    sub al, cl
:00401472    cmp al, 39
:00401474    jg 00401470
:00401476    jmp 00401444

* Jump at Addresses:
|:00401460(C), :00401497(C)
|
:00401478 8A8149324000            mov al, byte ptr [ecx+00403249]

* Jump at Addresses:
|:004014A4(U), :004014AC(U)
|
:0040147E    cmp al, 30
:00401480    jl 0040149E
:00401482    nop
:00401483    nop
:00401484    nop
:00401485    nop
:00401486    cmp al, 39
:00401488    jg 004014A6
:0040148A    nop
:0040148B    nop
:0040148C    nop
:0040148D    nop
:0040148E    mov byte ptr [ecx+00403249], al
:00401494    dec ecx
:00401495    test ecx, ecx
:00401497    jne 00401478
:00401499    jmp 004013C6

* Jump at Addresses:
|:00401480(C), :004014A2(C)
|
:0040149E    add al, 04
:004014A0    cmp al, 30
:004014A2    jl 0040149E
:004014A4    jmp 0040147E

* Jump at Addresses:
|:00401488(C), :004014AA(C)
|
:004014A6    sub al, 05
:004014A8    cmp al, 39
:004014AA    jg 004014A6
:004014AC    jmp 0040147E

 

* Jump at Address:
|:00401499(U)
|
:004013C6    xor eax, eax
:004013C8    call 004013EF

 

* Referenced by a CALL at Address:
|:004013C8  
|

* Reference To: KERNEL32.GetTickCount, Ord:0000h

:004013EF    Call 00401E61
:004013F4    mov dword ptr [00403235], eax
:004013F9    mul dword ptr [00403239]
:004013FF    inc eax
:00401400    mov dword ptr [00403235], eax
:00401405    ret

 

:004013CD    call 004014AE

 

* Referenced by a CALL at Address:
|:004013CD  
|
:004014AE    xor ecx, ecx
:004014B0    xor eax, eax

* Jump at Address:
|:004014CD(C)
|
:004014B2    inc ecx
:004014B3    mov al, byte ptr [ecx+00403249]
:004014B9    mov bl, byte ptr [00403235]
:004014BF    xor al, bl
:004014C1    mov byte ptr [ecx+00403249], al
:004014C7    cmp ecx, dword ptr [00403241]
:004014CD    jl 004014B2
:004014CF    ret

 

:004013D2    push 00000014
:004013D4    push 0040325D
:004013D9    push dword ptr [00402034]

* Reference To: USER32.GetWindowTextA, Ord:0000h
                     
:004013DF    Call 00401EC7
:004013E4    call 0040157A

 

* Referenced by a CALL at Address:
|:004013E4  
|
:0040157A    xor ecx, ecx
:0040157C    xor eax, eax

* Jump at Address:
|:00401599(C)
|
:0040157E    inc ecx
:0040157F    mov al, byte ptr [ecx+0040325C]
:00401585    mov bl, byte ptr [00403235]
:0040158B    xor al, bl
:0040158D    mov byte ptr [ecx+0040325C], al
:00401593    cmp ecx, dword ptr [00403241]
:00401599    jl 0040157E
:0040159B    ret

 

:004013E9    call 004015EF

 

* Referenced by a CALL at Address:
|:004013E9  
|
:004015EF    push dword ptr [00402034]

* Reference To: USER32.GetWindowTextLengthA, Ord:0000h

:004015F5    Call 00401EB5
:004015FA    cmp eax, 0000000F
:004015FD    jne 00401108
:00401603    mov esi, 0040324A
:00401608    mov edi, 0040325D
:0040160D    mov ecx, dword ptr [00403241]
:00401613    repz
:00401614    cmpsb
:00401615    je 004014F4
:0040161B    mov dword ptr [0040329F], 000091C2
:00401625    jmp 004014FE

 

Allora, vediamo un po' di commentare tutte queste routine. Dunque, all'indirizzo 401330 c'è la 1a chiamata a GetWindowTextA, che si prende il nome (1a text-box) da noi inserito e lo mette in 403249. Dopodichè muove eax, il valore di ritorno dell'API, in un buffer (il valore di ritorno di quest'API è il numero di caratteri del testo inserito), quindi confronta eax stesso con 6, e se il valore è minore salta a una box che ci avvisa che dobbiamo inserire nomi (o numeri) > 6 charz, facendo poi tornare l'esecuzione in attesa di un comando (in questo caso è possibile re-inserire nome e serial anche senza riavviare, in quanto a 401192 se andate a guardare c'è un salto che agisce a seconda che si sia già passati attraverso il 1° check, ma questo non lo spiego, sia perchè altrimenti viene una lezione di asm, sia perchè col reversing non centra un cazzo).

Subito dopo c'è una chiamata a GetTickCount (spiegata sopra), ma ciò ora non ci interessa, in quanto il valore di ritorno di eax viene messo in un buffer utilizzato + avanti e poi eax viene sovrascritto.

Allora, abbiamo visto che il nome non deve essere - lungo di 6 char... vabbè regoliamoci di conseguenza... proseguiamo col check: io come nick, essendo "Ritz" troppo corto, ho usato "RitzTheBlitz" (non chiedetemi che cazzo vuol dire perchè non lo so nemmeno io ;)) ). Innanzi tutto vediamo che sia ecx che bx vengono azzerati, quindi quindi in edx viene caricata la dword puntata da 40324A, cioè il 2°, 3°, 4° e 5° carattere del nome. Dopo questo in eax vengono caricati i primi 4 caratteri ancora del nome (puntato da 403249), eax ed edx vengono moltiplicati con imul, cioè tenendo conto del segno (risultato in eax) e il prodotto viene messo in 403249, quindi occupando eax una dword (naturalmente :PP) i primi 4 char del nome (corrispondenti alla dword a partire da 403249) sono stati ben modificati. Viene allora ri-azzerato ecx, dove si mette il valore 4, e la dword puntata da 403241 (la lunghezza della stringa inserita) viene decrementata, quindi ecx viene incrementato ed ha inizio un ciclo che dura (n°char-5) volte (col mio nick infatti il ciclo viene eseguito in tutto 7 volte), il quale modifica tutti i caratteri compresi tra il char non modificato e l'ultimo char, estremi ESCLUSI. Ad esempio, nel caso del mio nick, dopo la prima manipolazione mi ritrovo come nick manipolato xxxxTheBlitz, mentre dopo tutto il secondo ciclo trovo come nick manipolato xxxxTyyyyyyz, capit? Infatti se notate bene la manipolazione parte da ecx + 403249 con ecx = 5 (5° char) e finisce con ecx + 403249 con ecx = (n° char-1). Beeeneee fin qui tutto ok... Dopo il ciclo si cambia manipolazione: in eax e ebx vengono caricati rispettivamente i primi 4 char e i secondi 4 char del nome manipolato (eax cioè contiene i primi 4 byte ed ebx il 4°, 5°, 6° e 7°). Eax e ebx vengono moltiplicati, eax viene messo in 403249 (quindi i primi 4 char del nome manipolato vengono riscambiati), la dword che contiene il numero di charz inseriti viene aumentata di 1 (quindi visto che prima era stata dcrementata di 1 ora torna allo stato originale), ecx viene azzerato e in esso viene spostata proprio la dword che contiene il numero di char inseriti (classico contatore) e inizia un altro stramaledetto ciclo, ogni dword del nome inserito a partire dall'ultimo carattere fino a scendere al primo viene xorata con 04CF580F, quindi qui non si tratta di una manipolazione carattere per carattere, bensì dword per dword, quindi ogni carattere viene manipolato + volte. Alla fine di tale ciclo il nome è completamente irriconoscibile.

Finito anche questo maledetto loop ne inizia uno moooltooo + complicato, chiamato dalla CALL presente all'indirizzo 4013C1... dunque, qui non ha senso far tutto passagigo per passaggio, però si può capire cosa accade: abbiamo prima un ciclo, poi un altro ad esso simile... cosa fanno? Dunque... alla fine del primo dei 2 cicli, cioè a 401460, con un "d 403249" vediamo che è sucessa una cosa particolare: dal terzo carattere compreso in poi fino al carattere dopo l'ultimo del nostro nick i valori ASCII corrispondenti si sono tutti trasformati in cifre... hum com'è 'sto discorso? Semplice, in queta prima routine dal 3° in poi ogni byte (quindi ogni char) viene confrontato prima con 30h ("0" ASCII), se è se è minore passa atraverso una routine che lo "maggirizza" aggiungendoci il valore di cl fino a farlo diventare + grande di 30; dopodichè lo stesso byte viene confrontato con 39h ("9" ASCII) e, se è + grande, passa attraverso una routine che lo "minorizza" fino a farlo diventare + piccolo, quindi il byte viene rimesso al suo posto all'indirizzo 401454 e si passa al carattere successivo (che poi sarebbe quello precedente, quello cioè + a sinistra). Conclusione: questa routine fa sì che ogni byte del nome manipolato abbia come corrispondente valore ASCII un numero compreso tra 0 e 9, estremi inclusi, ovvero che ogni byte del nome (anzi, + precisamente dal 2° char del nome fino a quello subito dopo l'utimo) abbia valore compreso tra 30h e 39h. una volta finita la routine e arrivati al 3° char del nome, si passa a quella dopo, che è del tutto simile, solo che stavolta per minorizzare e magigorizzare non vengono utilizzati valori di un registro, bensì valori fissi (04 e 05), come si può vedere in 40149E e 40146A. Una volta che la routine è finita, si rijumpa a 4013C6 con un semplice numero nel buffer 403249, anzi, meglio, nel buffer 40324A, cioè in 403249 + 1, in quanto il primo byte non viene toccato.

Adesso arriva una parte interessante: eax viene azzerato e... CALL 4013EF... guardiamo un po' cosa c'è... cazzo c'è una chiamata a GetTickCount... già vista prima... che ci dice da quanto tempo WinPorko è avviato... hum... osserviamola un po'... si nota facilmente che la CALL in questione non ci interessa un cazzo, in quanto il valore di ritorno di eax viene spostato in dei buffer che a  noi alla prossima CALL interesserà un po' :)). Le manipolazioni sono una cazzata: eax in 4032435, 403239 moltiplicato, eax incrementato di 1 e messo in 403235.

Proseguiamo ancora. Ce n'è un'altra a 4013CD: CALL 4014AE. Andiamo un po' a vede'... all'indirizzo 4014AE ecx ed eax vengono azzerati, ecx aumentato (ricordando che prima era 0 ora sarà 1) e vengono fatte alcune manipolazioni, precisamente ogni char (che ora è numerico) viene messo in al, in bl viene messo il byte precedentemente messo in 403235 (quindi un valore random, visto il modo in cui è stato generato), al xorato con bl, il risultato messo al posto del char preso all'inizio. Il tutto finchè ecx = C, cioè per 12 byte, o 12 caratteri, come preferite ;)). Finito anche questo ciclo torniamo dalla CALL e steppiamo ancora: cosa vedo!! un GetWindowTextA!! Quindi? Semplice, quindi in questo momento viene preso il serial della seconda text-box (quella in basso). La stringa viene messsa in 40325D e subito dopo c'è una chiamata... tracciamola col solito F8... osserviamo la scena che ci si presenta davanti a 40157A... è la stessa IDENTICA della CALL tracciata subito prima, solo che stavolta il buffer è quello del serial preso!! Raga, iniziate a macinare qualcosa eh? :)). Beeeneee spero di sì :)). Uscite pure dalla CALL dove siete entrati con F12.

Eccovi che a 4013E9 c'è subito un'altra CALL... entriamoci con F8... vediamo che l'handle della 2a text-box viene pushato e c'è una chiamata all'API GetWindowTextLengthA... indovinate un po' cosa ritorna? Ma vaaaaaa!! Bravi, rotorna proprio il numero di charz inseriti nella text-box. Infatti vediamo che c'è un cmp tra tale valore ed Fh, cioè 15 dec... se non sono uguali il prog manda tutto quanto a puttane senza nemmeno confrontare i valori inseriti... quindi adesso sappiamo precisamente quanto lungo deve essere il nosstro serial: 15 caratteri. Bene... osseriviamo ancora un po' di cose: c'è un altro repz cmpsb!! Quindi adesso è il momento in cui c'è il check vero e proprio, e precisamente il prog confronta i buffer 40324A (il nome manipolato a partire dal 2° byte) e 40325D (il serial manipolato) per un numero di byte pari a quello puntato in 403241, cioè proprio il numero di char del nome inserito.

RICAPITOLAZIONE: noi sappiamo che il serial deve essere di 15 char, ma il prog controlla solo tanti byte quanti corrispondenti alla lunghezza del nome, quindi ad esempio nel mio caso, col nick "RitzTheBlitz" dovrò inserire 15 char come serial, ma il prog controllerà solo i primi 12, corrispodenti alla lunghezza della stringa inserita come nome.

Raga, abbiamo praticamente finito questa parte, si manca però una piccola riflessione che ha carattere + generale.

Immaginiamo un prog. qualsiasi che chiede un nome e un serial e li manipola entrambi in un dato modo. Noi dobbiamo trovare il serial corrispondente al nostro nick... Dunque dunque, ammettendo di inserire name e serial corretti, abbiamo che il nome deve venir manipolato due volte: prima in un certo modo per ricavarne il serial corrispondente da confronare (chiamiamola routine A) e poi in un altro modo per nascondere al reverser il risultato trovato (routine B). Allora, nella routine A non può esere presente alcun numero random, poichè per uno stesso nick deve valere sempre e in qualsiasi "situazione" (chiamiamola così) lo stesso serial, ovvero non è pensabile che il serial cambi a seconda del PC su cui ci si trova o del tempo passato dall'ultimo avvio di Win. Nella routine B, invece, dato che il serial è già stato generato, si possono usare tutti i valori random che si preferisce, ad una condizione. Infatti, anche il serial da noi inserito deve essere preso dal prog., che poi, sempre per nasconderlo, lo manipola e lo critta a seconda della fantasia del coder (chiamiamo questa routine di manipolazione C). Ed ecco qui spiegata la condizione posta in precedenza: se B e C sono la stessa identica routine (naturalmente ognuna riferita al proprio buffer), allora possono utilizzare anche qualsiasi numero random al loro intero, basta che quelli usati in B siano gli stessi di quelli usato in C, in modo da crittare allo stesso modo i valori trovati.

SCHEMINO :) :

Step 1- GetWindowTextA col nome ---> routine A (per generare il serial) ---> routine B (per mascherare il serial generato)

Step 2- GetWindowTextA col serial ---> routine C (per mascherare il serial)

Step 3- Confronto tra risultato di B e risultato di C

Step 4- Salto positivo o negativo a seconda dello Zero Flag (attivato o meno)

B=C!!!

In questo caso tale ragionamento è perfettamente applicabile, basta solamene trovare il punto da cui Step 1 e Step 2 hanno il codice uguale (in altre parole il punto di Step 1 in cui inizia B :)) ) e quindi sapere che subito PRIMA che tale codice venga eseguio in memoria deve trovarsi il nostro serial bello in chiaro. :)))

Che fare? beh, che dire, il 2° GetWindowTextA ha 2 CALL, di cui la 2a viene usata solo per confrontare i 2 buffer, e quindi la prima (quella all'indirizzo 4013E4) sarà l'unica da cercare. ma guarda un po' tu!!! L'avevamo già notato che questa era uguale a quella all'indirizzo 4013CD!! Che coincidenza!! Quindi, nel nostro caso,

Step 1- GetWindowTextA col nome ---> routine A (da 401335 a 4013C8 con tutte le CALL in mezzo incluse) ---> routine B (4013CD)

Step 2- GetWindowTextA col serial ---> routine C (4013E4)

Step 3- Confronto (4013E9)

Noi cmq sappiamo che la CALL a 4013C8 serve solo per prendere dei valori random, e non modifica nulla nei nostri buffer, quindi la routina A la possiamo far finire a 4013C1 (quest'ultimo compreso, naturalmente). Beh, che dire, dopo aver eseguito tutta la CALL a 4013C1 il memoria troveremo il serial corretto, quindi non ci resta che posizionarci a 4013C6 e fare un bel "d 40324A": vedremo apparire la sequenza numerica esatta, che per il mio nick è "701085298638" con l'aggiunta di 3 cifre a caso per poter arrivare a 15 (che coincidenza, il serial giusta appare subito dopo la routine per trasformare la stringa manipolata in sequenza numerica ;)) ). Quindi,

Nick: RitzTheBlitz

Serial: 701085298638xyz

Bene, sembrerebbe che anche questa parte possa considerarsi conclusa, ma sfortunatamente non è così, in quanto non abbiamo considerato una particolare situazione che si viene a creare coi nomi di 6 charz... che effettivamente sono un pochetto bastardi... :). Allora, perchè direte voi i nomi di 6 caratteri non sono come gli altri? Beh, in teoria anch'essi dovrebbero esser manipolati allo stesso modo degli altri, e così avviene, ma sfortunatamente accade, se notate bene, che ogni volta che provate a osservare il serial, ve ne appaiono in tutto due, cioè precisamente uno per le volte dispari che fate il check e uno per le volte pari. E non è tutto!! Se provate a mettere un nick + lungo di 6 char e poi uno di 6 charz, vi accorgerete che il serial per tale nome di 6 char cambia "ritmicamente" allo stesso modo, ma entrambi i 2 serial di prima cambiano!!

A cos'è dovuto questo fatto?

Beh... la risposta è da cercare dopo il primo ciclo di manipolazione del nome, e precisamente all'indirizo 40138A. Esaminiamo la situazione per un nome di 6 caratteri: in questo punto vengono caricati in eax i primi 4 caratteri, e fin qui tutto ok... subito dopo in ebx vengono caricati i caratteri 5, 6, 7, 8. Dunque, il 5° c'è, il 6° pure, il 7° non ci sarebbe, però essendo il nome di 6 char il 7° deve essere un byte NULL, ovvero un byte di terminazione stringa. Ma l'8°? Cosa accade all'8° carattere, visto che la stringa è già completamente finita?? Beh, l'8° byte sarà preso ugualmente, solo che non sarà qualche cosa di "fisso", in quanto il buffer che lo contiene (precisamente 403250) subisce nel corso di vari cicli altre operazioni di modifica senza poter essere sovrascritto da un char da noi inserito: proviamo infatti ad inserire un breakpoint dal Sice in modo che ci avvisi quanto tale buffer viene scritto con un "bpm 403250 w", e vedremo che il Sice poppa in 4013BC, ciò significa che nell'istruzione precedente il buffer in questione è stato appunto sovrascritto. Di conseguenza, in un eventuale 2° check del serial, al posto del byte 00 presente in 403250 prima della manipolazioni verrà preso quel byte "sporco", se così vogliamo chiamarlo, in quanto non sovrascritto dopo i vari cicli eseguiti. Se poi facciamo anche un 3° check del serial, vedremo che quello corrispondente al nostro nick sarà di nuovo quello iniziale, in quanto stavolta il valore presente in quel buffer, risultato di uno xoring, viene rixorato con se stesso, e quindi darà come risultato 00, ovvero proprio il valore iniziale del byte presente a 403250... non so se mi sono spiegato bene :).

Perchè allora però il serial cambia ancora in un altro modo ancora se prima inseriamo nomi + lunghi e poi ne rimettiamo altri di 6 char?? Beh, semplice, perchè con i nomi > 6 char il buffer 403250 viene sovrascritto varie altre volte (precisamente all'indirizzo 401382, 40145A e 4014C7), e di conseguenza, una volta che si ritornerà ai 6 char, il byte ottenuto dopo queste nuove manipolazione verrà ogni volta xorato con un dato valore sempre fisso, andando quindi a creare una serie di 2 risultati alternati diversi da quelli precedenti (es R xor S = T xor S = R xor S = T xor S = R ecc...).

Beh, che dire, finalmente anche questo "aspetto" (chiamiamolo così :)) ) un po' scassapalle è stato risolto... ora possiamo sul serio passare alla

()()()()()()()()()()()()()()()()()()()()

PARTE 3: KEYFILE

()()()()()()()()()()()()()()()()()()()()

Raga, vi consiglio di prendervi almeno 2 ore di pausa se non avete già smesso di leggere il tute, in quanto avrete bisgono di un cervello moooooooltoooooo fresco.

ULTIMA PREMESSA: Raga, qui bisogna analizzare un casino di routine di crittaizione (grazie Queeee!!!!!!!! :)) ), quindi sarò molto + sintetico che in precedenza... se ad esempio vedo una cosa tipo mov eax, dword ptr [12345678], non starò lì a spiegarla minuziosamente :) Detto questo, inizia il martirio!!! Anzi no, mi prendo pure io un po' di pausa :)).

zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz

Ok ho finito la pausa, ricominciamo.

NOTICILLA: Gli esempi in seguito riportati riguardo al keyfile sono riferiti al mio caso, cioè al keyfile creato coi miei parametri...

Bene bene... siete arrivati anche fin qui eh? Non ci resta che continuare. Ora voi avete appena passato il check del serial, e vedete subito che jumperete in un paio di posti a seconda che il serial sia giusto o meno. Per la precisione, se è corretto andrete a 4014F4, altrimenti 10 byte + avanti, a 4014FE (queta piccola differenza assieme a delle altre serve a qualcosa hihihihi ;) ). Allora ora siete a 4014FE. Eccovi il listato di seguito:

* Jump at Address:
|:00401615(C)
|
:004014F4    mov dword ptr [0040329F], 000091B2   ;Serial esatto

* Jump at Address:
|:00401625(U)   ;Serial sbagliato
|
:004014FE    push 00000014
:00401500    push eax   ;Scazzato
:00401501    push dword ptr [00402030]

* Reference To: USER32.GetWindowTextA, Ord:0000h
                     
:00401507    Call 00401EC7
:0040150C    mov dword ptr [00403241], eax   ;eax = 0
:00401511    mov eax, 00402BFC
:00401516    add eax, 00000014
:00401519    push 00000014
:0040151B    push eax   ;eax = 402C10
:0040151C    push dword ptr [00402034]   ;Handle 2a text-box

* Reference To: USER32.GetWindowTextA, Ord:0000h
                         
:00401522    Call 00401EC7
:00401527    call 0040167F
:0040152C    call 00401B79
:00401531    call 00401BCE
:00401536    mov ebp, 4243484B
:0040153B    mov ax, 0004
:0040153F    int 03
:00401540    cmp al, 04
:00401542    je 004011EE
:00401548    mov esi, 00402BFC
:0040154D    mov edi, 004025F0
:00401552    mov ecx, dword ptr [004031FC]
:00401558    repz
:00401559    cmpsb
:0040155A    je 00401DE9

Che succede qui? Vengono pushati 3 parametri, ma il 2° è sbagliato, poichè eax = F (valore di ritorno del GetWindowtextLengthA), e non può essere pushato un buffer del genere, quindi la chiamata successiva restituirà eax = 0 (ciò avviene quando c'è stato qualche errore nel chiamare l'API). Guardiamo, è così... eax (che ha valore esattamente 00 00 00 00 :) ) allora viene spostato in un buffer (403241), quindi in eax viene messo il valore 402BFC (da adesso fino alla fine del tute ripeterete mentalmente queste cifre talmente tante volte da aver la nausea, come cmq ho fatto anch'io ;) ). Ad esso viene aggiunto il valore 14, quindi eax = 402C10. Ecco che ancora vegono pushati eax (quindi il buffer 402C10), l'handle della 2a box e viene chiamata GetWindowTextA, che si prende il serial inserito.

Ora... si potrebbe iniziare a traccia la CALL a 40167F, però prima osserviamo cosa c'è dentro a 401B79:

* Referenced by a CALL at Address:
|:0040152C  
|
:00401B79    push 00000002
:00401B7B    push 00402050   ;File info

* Possible StringData Ref from Data Obj ->"CryKey.key"
                    
:00401B80    push 0040322A   ;Nome file

* Reference To: KERNEL32.OpenFile, Ord:0000h
                   
:00401B85    Call 00401E43
:00401B8A    mov dword ptr [00402048], eax
:00401B8F    cmp eax, FFFFFFFF
:00401B92    je 00401560
:00401B98    push 00000000
:00401B9A    push 00000000
:00401B9C    push dword ptr [004032A7]   ;Number of bytes
:00401BA2    push dword ptr [00402048]   ;Handle del file

* Reference To: KERNEL32.SetFilePointer, Ord:0000h
                          
:00401BA8    Call 00401E3D
:00401BAD    push 00000000
:00401BAF    push 00402320
:00401BB4    push dword ptr [004031FC]   ;Numero di byte da leggere
:00401BBA    push 004025F0   ;Buffer che riceve i dati letti
:00401BBF    push dword ptr [00402048]   ;Handle del file da leggere

* Reference To: KERNEL32.ReadFile, Ord:0000h
                                 
:00401BC5    Call 00401E31
:00401BCA    ret

Dunque dunque... in queta routine viene chiamata prima di tutto l'API OpenFile, dopo che è stato pushato il nome del file da aprire (presente nel buffer 40322A), quindi basta vedere il testo disassemblato o fare un "d 40322A" per vedere che il file aperto, che è il keyfile, si chiama CryKey.key (il quale, visto che non sono specificati percorsi particolari nella stringa, si deve trovare nella stessa dir del crackme). Moltobbeneeee ora sappiamo almeno come chiamarlo :). Il valore di ritorno dell'API OpenFile non deve essere -1, altrimenti significa che la chiamata è fallita e il file non è stato aperto. Proviamo a steppare con F10 fino a 401B8A... eax = FFFFFFFF, cioè proprio -1. Uai?? Semplice, perchè il file noi non l'abbiamo ancora creato :) e per ora non ci serve nemmeno crearlo. Btw, dopo la chiamata il contenuto di eax (cioè l'handle del file) viene spostato inun buffer, 402048, e se eax = -1 allora tutto va ad cazzum di nuovo (il prog salta a una chiamata a GetSystemTime, che riporta poi un valore deficiente ed esce dalla CALL). Se invece il file esiste, vengono pushati 4 parametri (come vuole la sintassi del caso) e viene chiamata l'API SetFilePointer, che serve per poi poter chiamare a sua volta l'API ReadFile. Ecco quini che vengono subito dopo pushati altri 5 parametri, e booooommm ecco che il file CryKey viene letto, e precisamente il numero di byte puntato dalla dword 4031FC, che poi sarebbero 2BCh, cioè 700d, vengono messi nel buffer 4025F0 (altro buffer che vi farà venire la nausea, anche se meno di 402BFC :PP). Fatto anche questo, si esce dalla CALL e si prosegue col codice.

Subito dopo, a 401531, infatti, c'è un'altra CALL. Se entriamo vediamo che è un casino, nel senso che manipola proprio il buffer dei byte letti in una maniera semplicemente mostruosa, è un susseguirsi continuno di cicli che poi tornano a 401536 per fare il cmp finale tra 402BFC (che contiene il keyfile corretto) e 4025F0 (che contiene il nostro keyfile).

Abbiamo allora capito un po' di cose: il keyfiel si chiama CryKey.key e la parte letta è di 700 byte, quindi noi dovremo crere proprio un file di tali dimensioni e con questo nome.

Adesso però ci vuole un po' di zen ;)). Infatti, così come per la generazione del serial, anche per quella del keyfile deve valere lo stesso discorso, cioè che c'è una prima routine che si divide in A (che genera il serial) e B (che lo critta) e la seconda routine composta da C = B (che critta il serial immeso da noi)... lo stesso vale per un keyfile: noi conosciamo la seconda routine, che è quella composta dalla CALL a 401531, critta il buffer contenente i 700 bytes del nostro keyfile anche con valori random, come vedremo, mentre la prima routine, che è proprio la bestia chiamata a 401527, si può dividere in A e B, dove B è uguale a C. Ecco, quindi, che basterà trovare dentro tale routine strapiena di jump il punto in cui inizia B e da lì prendere giù il keyfile valido, non so se mi sono spiegato...

Capito tutti? Bene... allora se volete stampatevi tutta la CALL chiamata a 401527 e guardiamo un po' dove inizia il punto in comune con quella chiamata a 401531... vediamo un po'... ecco!!!!! Trovatooooo!!!! Esattamente all'indirizzo 40190B comincia la parte ESATTAMENTE identica, e quando questa è finita, il prog esce dalla CALL stessa. Quindi? Quindi il buffer di 700 byte che troveremo all'indirizzo 40190B sarà proprio la nostra serie di byte di cui deve essere costituito il keyfile!!!! Ora però resta un dubbio... il keyfile da cosa è generato? Beh... per capirlo basta con l'Ice entrare nella CALL a 401527 e vedere che il buffer ognivolta modificato è 402BFC, che contiene 20 byte NULL seguiti dal nostro serial inserito seguit ancora da tutti byte NULL. E qui Quequero è stato un po' bastardo, in quanto non poteva far sì che il keyfile fosse generato in base al nick invece che in base al serial, visto che per uno stesso nick esistono vari serial e quindi vcari keyfile? Hehe bisognerà stare attenti a considerare bene questo fattore in seguito nel keygen.

Bene, ora bisogna semplicemente andare fino a 40190B, e per farlo basta che dal Sice una volta che siete nel codice del prog. andiate col cursore (non con la barra che cammina, altrimenti state 3 ore a steppare visti tutti i cicli che ci sono) in 40190B, ci clicchiate una volta e scriviate "here" in modo da ritrovarsi direttamente lì, o anche che ci facciate doppio clic sopra in modo da metterci un bp e po uscire, insomma vedete voi come cazzo fare... al massimo se non trovate altre soluzioni steppate :)).

Siete a 40190B? Bene. Avete appena inserito un serial valido? Bene. Avete l'IceDump? Maleeeee... hehehe qui questo tool aiuta moltissimo. Infatti non avendolo uno si dovrebbe scrivere a mano i 700 byte presenti in 402BFC e poi convertirli pure in caratteri ASCII :) ma per fortuna l'IceDump ci viene in aiuto. Scaricateci possibilmente la versione 5, che funziona con tutte le versioni del SoftIce fino alla 4.00 (che poi è l'ultima). Come usarlo? Beh è molto semplice, in pratica il prog consiste in una patch da eseguire nella dir del Sice. Eseguite la patch corrispondente alla vostra versione dell'Ice, riavviate il PC e riposizionatevi su 40190B. Adesso scrivete "pagein d 402BFC 2BC c:\lostessopercorsodelcrackme\CryKey". Cos'avete fatto? Vi siete creati il keyfile :). L'IceDump infatti serve, tra le altre cose, a scrivere il contenuto di un buffer in un file ASCII, e col comando sopra avete proprio creato il file CryKey.key nella dir c:\lostessopercorsodelcrackme riempiendolo di 2BCh (700) byte presi dal buffer 402BFC. Ora infatti fate una cosa del genere: avviate il crackme, inserite la pass iniziale (esatta o meno non ha importaza), inserite il vostro nick con il vostro serial (non servirebbe che siano esatti, cmq meglio che mettiate quelli esatti), prendetevi come ho appena spiegato il keyfile, una volta preso premete F12 per uscire dalla CALL, steppate con F10 fino ad arrivare a 40155A e... lo ZeroFlag si attiva!!! Evvvvvvaaaiii!! Bene raga, abbiamo trovato il keyfile valido per QUEL serial inserito (è proprio in questo momento che se non avessimo disabilitato tutti i controlli anti-Sice quello che c'è ora a 401542 ci farebbe uscire dal prog :) ).

A questo punto sembra quasi che tutto sia finito... ma invece da bravi studenti ora dobiamo analizzare tutte le routine che portano alla generazione del keyfile valido a partire dal serial inserito, quindi da 40167F a 401909, aggiornando di volta in volta il keyfile che sta per essere creato. Eccovi tutto di seguito esposto (metto commenti più brevi possibili perchè basta sapere un po' di asm per capire le varie istruzioni). Se non vi interessa nulla della generazione e se sapete decentemente l'asm, saltate pure alla fine.

SITUAZIONE INIZIALE:

* Referenced by a CALL at Address:
|:00401527  
|
:0040167F    mov ecx, 00000023

VALORE BUFFER

                    701085298638xyz                

Qui non c'è nulla da spiegare, questo è il semplice buffer che si presenta dopo la CALL GetWindowTextA a 401522.

 

1° CICLO:

:0040167F    mov ecx, 00000023
:00401684    mov bl, 23
:00401686    mov eax, 00402BFC

* Jump at Address:
|:00401692(C)
|

:0040168B    xor byte ptr [eax+ecx-01], bl
:0040168F    dec ecx
:00401690    test ecx, ecx
:00401692    jne 0040168B

VALORE BUFFER

####################............[ZY

Qui il buffer ha la stessa dimensione ma valori differenti, in quanto dal 35° byte il giù ogni byte è xorato con 23h.

 

2° CICLO

:00401694    mov ecx, 00402BFC
:00401699    mov al, byte ptr [ecx]
:0040169B    mov ah, byte ptr [ecx+14]
:0040169E    add al, ah
:004016A0    mov edx, dword ptr [00403241]   ;403241 = 00000000 (vedi 401507)
:004016A6    mov bl, byte ptr [ecx+edx]
:004016A9    mov bh, byte ptr [ecx+23]
:004016AC    add bl, bh
:004016AE    xor al, bl
:004016B0    xor ecx, ecx
:004016B2    mov ebx, 00402BFC

* Jump at Address:
|:004016C0(C)
|
:004016B7    xor byte ptr [ebx+ecx], al
:004016BA    inc al
:004016BC    inc ecx
:004016BD    cmp ecx, 00000023
:004016C0    jl 004016B7

VALRE BUFFER

7654;:98?>=<... ....<:887;?5+$"(ooo

Qui byte per byte avvengono varie manipolazioni che portano a uno xor finale.

 

3° CICLO

:004016C2    mov al, byte ptr [ebx+05]
:004016C5    add al, 0F
:004016C7    xor ecx, ecx
:004016C9    mov ecx, 00000023

* Jump at Address:
|:004016D4(C)
|
:004016CE    xor byte ptr [ebx+ecx], al
:004016D1    dec ecx
:004016D2    test ecx, ecx
:004016D4    jne 004016CE

VALORE BUFFER

7|}rspqvwtuJKHINOLMusqq~rv|bmka&&&I

Qui il 5° byte viene preso come riferimento di varie altre manipolazioni: ci viene aggiunto 0F e poi viene xorato byte per byte con il buffer (a partire da 402BFD).

 

4° CICLO

:004016D6    mov edi, 00402BFC
:004016DB    mov al, byte ptr [edi+04]
:004016DE    mov ecx, 00000023
:004016E3    mov edx, 00000046

* Jump at Address:
|:004016F4(C)
|
:004016E8    mov bl, byte ptr [edi+ecx]
:004016EB    xor bl, al
:004016ED    mov byte ptr [edi+edx], bl
:004016F0    dec edx
:004016F1    dec ecx
:004016F2    test ecx, ecx
:004016F4    jne 004016E8

VALORE BUFFER

7|}rspqvwtuJKHINOLMusqq~rv|bmka&&&I.. .......89:;<=>?..... ......TTT;

Qui vengono aggiunti 34 byte al file che sono poi manipolati.

 

5° CICLO

:004016F6    mov eax, 00402BFC
:004016FB    mov ecx, 000002BC
:00401700    mov ebx, dword ptr [00403241]
:00401706    add ebx, 0000000F

* Jump at Address:
|:0040170F(C)
|
:00401709    xor byte ptr [eax+ecx], bl
:0040170C    dec ecx
:0040170D    test ecx, ecx
:0040170F    jne 00401709

VALRE BUFFER

7psr}|~yx{zEDGFA@CBz|~~q}ysmbdn)))F.. .... .76543210............[[[4........................................................................
.................................................................................................
.................................................................................................
.................................................................................................
.................................................................................................
.................................................................................................
........................................................................

Qui il file diventa di 700 byte tramite un semplice xor che dal 700° byte in giù xora i vari valori.

 

6° CICLO

:00401711    mov ebx, 000000F1

* Jump at Address:
|:0040171D(C)
|
:00401716    xor byte ptr [eax+ecx], F1
:0040171A    dec ebx
:0040171B    test ebx, ebx
:0040171D    jne 00401716

VALORE BUFFER

Æpsr}|~yx{zEDGFA@CBz|~~q}ysmbdn)))F.. .... .76543210............[[[4........................................................................
.................................................................................................
.................................................................................................
.................................................................................................
.................................................................................................
.................................................................................................
........................................................................

Il 1° byte viene xorato un casino di volte :).

 

7° CICLO

:00401724    mov eax, 00402BFC
:00401729    mov ebx, 0100D10F

* Jump at Address:
|:00401736(C)
|
:0040172E    xor dword ptr [eax+ecx], ebx
:00401731    sub ecx, 00000004
:00401734    test ecx, ecx
:00401736    jne 0040172E

VALORE BUFFER

Æpsrr­v©{{J•GGN‘CCu­~~¬yrb³do&ø)GÐ ..Ü..Ø.69ä42=à0 .Ý.. Ú...Ç.ZTŠ4. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ..

Xoring a gruppi di 4 byte.

 

8° CICLO:

:00401738    mov eax, 00402BFC
:0040173D    mov edx, eax
:0040173F    add edx, 00000100
:00401745    mov ecx, 00000014

* Jump at Address:
|:00401757(C)
|
:0040174A    mov bl, byte ptr [eax+ecx]
:0040174D    xor bl, byte ptr [eax+ecx+0C]
:00401751    mov byte ptr [edx+ecx], bl
:00401754    dec ecx
:00401755    test ecx, ecx
:00401757    jne 0040174A

VALORE BUFFER

Æpsrr­v©{{J•GGN‘CCu­~~¬yrb³do&ø)GÐ ..Ü..Ø.69ä42=à0 .Ý.. Ú...Ç.ZTŠ4. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. å45<<<<....49>5,"',SÞ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ..

Xoring e manipolazione dei 20 byte in rosso.

 

9° CICLO

:00401759    xor ecx, ecx
:0040175B    mov eax, 00402BFC

* Jump at Address:
|:00401771(C)
|
:00401760    mov bl, byte ptr [ecx+004032AF]
:00401766    mov byte ptr [eax+ecx+0000028A], bl
:0040176D    inc ecx
:0040176E    cmp ecx, 00000015
:00401771    jne 00401760

VALORE BUFFER

Æpsrr­v©{{J•GGN‘CCu­~~¬yrb³do&ø)GÐ ..Ü..Ø.69ä42=à0 .Ý.. Ú...Ç.ZTŠ4. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. å45<<<<....49>5,"',SÞ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. ÞHeadache By Quequero . Þ.. Þ.. Þ.. Þ.. Þ.. Þ.. Þ..

Eh sì, vengono inseriti 21 nuovi byte di una stringa quantomeno criptica :)) contenuta nel buffer 4032AF al posto di altri a partire dalla posizione 28A.

 

10° CICLO

:00401773    xor ecx, ecx
:00401775    mov eax, 00402BFC

*Jump at Address:
|:0040178A(C)
|
:0040177A    and dword ptr [eax+ecx], 27934438
:00401781    add ecx, 00000004
:00401784    cmp ecx, 000002BC
:0040178A    jne 0040177A

VALORE BUFFER

 @."0..'0 .#..... ..0..'8.."   ' @...@ . D . @ &8D."8@.. D . @...D... .. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.%8..$ ...0 .%( .$.D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D % D.#(D .8 .% @.%0D . D.. D.. D.. D.. D.. D.. D..

Che bello, qui ogni byte viene cambiato tramite operazioni di somme logiche dword per dword.

 

11° CICLO

:0040178C    mov eax, 00402BFC
:00401791    xor edx, edx
:00401793    mov cl, byte ptr [eax]

* Jump at Address:
|:0040179F(C)
|
:00401795    rol dword ptr [eax+edx], cl
:00401798    inc edx
:00401799    cmp edx, 000002BC
:0040179F    jne 00401795

VALORE BUFFER

 @."0..'0 .#..... ..0..'8.."   ' @...@ . D . @ &8D."8@.. D . @...D... .. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.%8..$ ...0 .%( .$.D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D.. D % D.#(D .8 .% @.%0D . D.. D.. D.. D.. D.. D.. D..

Varie operazione di rol dword per dword.

 

12° CICLO

:004017A1    mov eax, 00402BFC
:004017A6    xor ecx, ecx
:004017A8    mov edx, dword ptr [00402BF4]

* Jump at Address:
|:004017BA(C)
|
:004017AE    xor dword ptr [eax+ecx], edx
:004017B1    add ecx, 00000004
:004017B4    cmp ecx, 000002BC
:004017BA    jne 004017AE

VALORE BUFFER

E.¢­..§­..£•..‡•..ƒ­..§¥..¢½. §½E.‡•E †A ‚E ¦¥A.¢¥E.A ‚E.†…A.‚..†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†
A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†
A.†A.¥¥..¤..„..¥µ..¤A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A
.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.
†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†
A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†A.†
A.†A.†A ¥½A.£µA ‚¥..¥½E.¥­A †A.†A.†A.†A.†A.†A.†A.†

PUNTO IMPORTANTE!!! Qui stranamente la mente malata di Quequero (dai Que scheerzoooo :)) ) ha messo un valore pseudorandom nella routine chiamata da noi "A" che poi viene usato per vari calcoli, in pratica ciò significa da PC a PC (e anche nello stesso PC, in alcuni casi come vedremo) il keyfile non è sempre lo stesso a parità di serial, e dovremo tener conto di ciò nel keygen.

 

13° CICLO

:004017BC    xor ecx, ecx
:004017BE    mov edx, 00402BFC

* Jump at Address:
|:004017D5(C)
|
:004017C3    mov eax, dword ptr [edx+ecx]
:004017C6    shr eax, 02
:004017C9    mov dword ptr [edx+ecx], eax
:004017CC    add ecx, 00000004
:004017CF    cmp ecx, 000002BC
:004017D5    jne 004017C3

VALORI BUFFER

gÑ„(kÀÄ)kÁÄ(eÀÀ!eÁÀ k€Ä)i@„(o.À)oQÀ!e.€!g.€ g.€)i.„(i.D g.€ gQ€!a.„ c.„!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!g
Ѐ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!g.D)i .)g@ !kD)mÁ )cЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!
gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!g
Ѐ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gÐ
€!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!g.@)oPÀ(m.€ iAD)oQD)k.€!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!

Uahahahahahahahaha!! Qui ogni dword del buffer viene manipolata con uno shift a sinistra.

 

14° CICLO:

:004017D7    mov eax, 00402BFC
:004017DC    mov ebx, dword ptr [eax+05]
:004017DF    add eax, 00000110
:004017E4    xor ecx, ecx

* Jump at Address:
|:004017F2(C)
|
:004017E6    xor dword ptr [eax+ecx], ebx
:004017E9    add ecx, 00000004
:004017EC    cmp ecx, 00000290
:004017F2    jne 004017E6

VALORI BUFFER

gÑ„(kÀÄ)kÁÄ(eÀÀ!eÁÀ k€Ä)i@„(o.À)oQÀ!e.€!g.€ g.€)i.„(i.D g.€ gQ€!a.„ c.„!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!g
Ѐ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!g.D)i .)g@ !kD)­.B£.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J
§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§
.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.
©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§ÔiB¯”éC­Ô©K©…mB¯•mB«Ô©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J

Per la serie "Manìpolati tu che mi manìpolo anch'io", vi presentiamo ora un classico esempio di crittazione dword per dword che parte dal byte 110h (272d) e arriva alla fine e utilizza  il classico metodo dello xoring, sempre molto di moda.

 

15° CICLO

:004017F4    xor ecx, ecx
:004017F6    mov eax, 00402BFC
:004017FB    mov edx, 00402BFC
:00401800    add edx, 000000C0

* Jump at Address:
|:00401818(C)
|
:00401806    mov ebx, dword ptr [eax+ecx]
:00401809    xor ebx, D468B23A
:0040180F    mov dword ptr [edx+ecx], ebx
:00401812    add ecx, 00000004
:00401815    cmp ecx, 00000040
:00401818    jne 00401806

VALORI BUFFER

gÑ„(kÀÄ)kÁÄ(eÀÀ!eÁÀ k€Ä)i@„(o.À)oQÀ!e.€!g.€ g.€)i.„(i.D g.€ gQ€!a.„ c.„!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!g
Ѐ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!]cìüQr¬ýQs¬ü_r¨õ_s¨ôQ2¬ýSòìüU³¨ýUã¨õ_£èõ]¢èô]£èýS¢ìüS£,ô]¢èô]ãèõg.D)i .)g@ !kD)-.B£.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J
§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§
.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.
©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§ÔiB¯”éC­Ô©K©…mB¯•mB«Ô©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J

Crittazione con semplice xoring fino al per 64 byte partendo dal 192°.

 

16° CICLO

:0040181A    xor ecx, ecx
:0040181C    mov eax, 00402BFC
:00401821    mov ebx, 00402BFC
:00401826    mov edx, 00402BFC
:0040182B    add ebx, 00000050
:0040182E    add edx, 000000A0

* Jump at Address:
|:00401843(C)
|
:00401834    mov edi, dword ptr [eax+ecx]
:00401837    xor edi, dword ptr [edx+ecx]
:0040183A    mov dword ptr [ebx+ecx], edi
:0040183D    add ecx, 00000004
:00401840    cmp ecx, 00000040
:00401843    jne 00401834

VALORI BUFFER

gÑ„(kÀÄ)kÁÄ(eÀÀ!eÁÀ k€Ä)i@„(o.À)oQÀ!e.€!g.€ g.€)i.„(i.D g.€ gQ€!a.„ c.„!gЀ!gЀ! .. ..D...D ..@ ..@..PD... .Ñ@.22,Ý4c,Ü6c,Ü8c(Ü6c,Ü8#èÝ4âlÜ2â(ÜgЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!]cìüQr¬ýQs¬ü_r¨õ_s¨ôQ2¬ýSòìüU³¨ýUã¨õ_£èõ]¢èô]£èýS¢ìüS£,ô]¢èô]ãèõg.D)i .)g@ !kD)­.)B£.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J
§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§
.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.
©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§ÔiB¯”éC­Ô©K©…mB¯•mB«Ô©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J

Xoring misto... :)

 

17° CICLO

:00401845    xor ecx, ecx
:00401847    mov eax, 00402BFC
:0040184C    mov ebx, 00402BFC
:00401851    mov edx, 00402BFC
:00401856    add edx, 00000080
:0040185C    add ebx, 00000110

* Jump at Address:
|:00401873(C)
|
:00401862    mov edi, dword ptr [eax+ecx]
:00401865    mov esi, dword ptr [edx+ecx]
:00401868    xor edi, esi
:0040186A    mov dword ptr [ebx+ecx], edi
:0040186D    add ecx, 00000004
:00401870    cmp ecx, 00000028
:00401873    jne 00401862

VALORI BUFFER

gÑ„(kÀÄ)kÁÄ(eÀÀ!eÁÀ k€Ä)i@„(o.À)oQÀ!e.€!g.€ g.€)i.„(i.D g.€ gQ€!a.„ c.„!gЀ!gЀ! .. ..D...D ..@ ..@..PD... .Ñ@.22,Ý4c,Ü6c,Ü8c(Ü6c,Ü8#èÝ4âlÜ2â(ÜgЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!]cìüQr¬ýQs¬ü_
r¨õ_s¨ôQ2¬ýSòìüU³¨ýUã¨õ_£èõ]¢èô]£èýS¢ìüS£,ô]¢èô]ãèõg.D)i .)g@ !kD)Q²¨ôSã,ô_#¨ôW"èý..@..PD... .Ñ@..@ .Á§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§
.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.
©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©
J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§ÔiB¯”éC­Ô©K©…mB¯•mB«Ô©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J

Xoring dal 272° byte per 40 byte.

 

18° CICLO

:00401875    xor ecx, ecx
:00401877    mov eax, 00402BFC
:0040187C    mov ebx, 00402BFC
:00401881    add ebx, 00000098

* Jump at Address:
|:00401898(C)
|
:00401887    rol dword ptr [eax+ecx], 13
:0040188B    rol dword ptr [ebx+ecx], 08
:0040188F    add ecx, 00000004
:00401892    cmp ecx, 00000098
:00401898    jne 00401887

VALORI BUFFER

&D9‹&NY.&FY...)...).$NY."DI. Ny...y‹ .)‹ .9ƒ L9‹ DIƒ .I‹ .9ƒ..9‹ . ƒ .....9ƒ..9ƒ H . B`€ J`ˆ
 ..€
.ˆ"B`€$Hp€.B@ˆaé–‘cá¦.cá¶.CáÆ.cá¶.AïÆ.gã¦.Gá–...9ƒ..9ƒ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀü]c
ìýQr¬üQs¬õ_r¨ô_s¨ýQ2¬üSòìýU³¨õUã¨õ_£èô]¢èý]£èüS¢ìôS£,ô]¢èõ]ãè)g.D)i .!g@ )kDôQ²¨ôSã,ô_#¨ýW"è...@..PD ....Ñ@.@ .Á  §.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§
.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.
©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©
J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§ÔiB¯”éC­Ô©K©…mB¯•mB«Ô©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J

Xoring vario per circa metà file.

 

19° CICLO

:0040189A    mov eax, 00402BFC
:0040189F    mov ebx, 00402BFC
:004018A4    add ebx, 00000130
:004018AA    xor edi, edi
:004018AC    xor ecx, ecx
:004018AE    add edi, 00000130

* Jump at Address:
|:004018C6(C)
|
:004018B4    mov edx, dword ptr [ebx+edi]
:004018B7    xor edx, dword ptr [eax+ecx]
:004018BA    add ecx, 00000004
:004018BD    sub edi, 00000004
:004018C0    cmp ecx, 00000130
:004018C6    jne 004018B4

VAOLRI BUFFER

&D9‹&NY.&FY...)...).$NY."DI. Ny...y‹ .)‹ .9ƒ L9‹ DIƒ .I‹ .9ƒ..9‹ . ƒ .....9ƒ..9ƒ H . B`€ J`ˆ
 ..€
.ˆ"B`€$Hp€.B@ˆaé–‘cá¦.cá¶.CáÆ.cá¶.AïÆ.gã¦.Gá–...9ƒ..9ƒ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀü]c
ìýQr¬üQs¬õ_r¨ô_s¨ýQ2¬üSòìýU³¨õUã¨õ_£èô]¢èý]£èüS¢ìôS£,ô]¢èõ]ãè)g.D)i .!g@ )kDôQ²¨ôSã,ô_#¨ýW"è...@..PD ....Ñ@.@ .Á  §.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§
.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.
©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©
J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§ÔiB¯”éC­Ô©K©…mB¯•mB«Ô©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J

Non succede un cazzo.

 

20° CICLO

:004018C8    mov eax, 00402BFC
:004018CD    mov ebx, 00402BFC
:004018D2    add ebx, 00000140
:004018D8    xor ecx, ecx

* Jump at Address:
|:004018EF(C)
|
:004018DA    mov edx, dword ptr [eax+ecx]
:004018DD    xor edx, dword ptr [ebx+ecx]
:004018E0    mov dword ptr [ecx+004032C5], edx
:004018E6    add ecx, 00000004
:004018E9    cmp ecx, 00000140
:004018EF    jne 004018DA

VALORI BUFFER

&D9‹&NY.&FY...)...).$NY."DI. Ny...y‹ .)‹ .9ƒ L9‹ DIƒ .I‹ .9ƒ..9‹ . ƒ .....9ƒ..9ƒ H . B`€ J`ˆ  ..€ .ˆ"B`€$Hp€.B@ˆaé–‘cá¦.cá¶.CáÆ.cá¶.AïÆ.gã¦.Gá...9ƒ..9ƒ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀü]c
ìýQr¬üQs¬õ_r¨ô_s¨ýQ2¬üSòìýU³¨õUã¨õ_£èô]¢èý]£èüS¢ìôS£,ô]¢èõ]ãè)g.D)i .!g@ )kDôQ²¨ôSã,ô_#¨ýW"è...@..PD ....Ñ@.@ .Á §.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§
.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.
©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©
J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J§ÔiB¯”éC­Ô©K©…mB¯•mB«Ô©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J

Non succede un cazzo. Serve per la routine B.

 

21° CICLO

:004018F1    mov eax, 00402BFC
:004018F6    add eax, 00000140

* Jump at Address:
|:00401909(C)
|
:004018FB    mov edx, dword ptr [ecx+004032C5]
:00401901    mov dword ptr [eax+ecx], edx
:00401904    sub ecx, 00000004
:00401907    test ecx, ecx
:00401909    jne 004018FB

VALORI BUFFER

&D9‹&NY.&FY...)...).$NY."DI. Ny...y‹ .)‹ .9ƒ L9‹ DIƒ .I‹ .9ƒ..9‹ . ƒ .....9ƒ..9ƒ H . B`€ J`ˆ ..€ .ˆ"B`€$Hp€.B@ˆaé–‘cá¦.cá¶.CáÆ.cá¶.AïÆ.gã¦.Gá–...9ƒ..9ƒ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀ!gЀü]c
ìýQr¬üQs¬õ_r¨ô_s¨ýQ2¬üSòìýU³¨õUã¨õ_£èô]¢èý]£èüS¢ìôS£,ô]¢èõ]ãè)g.D)i .!g@ )kDôQ²¨ôSã,ô_#¨ýW"è...@..PD ....Ñ@.@ .Á  §.©J§.©J§.©JZðIRðA¡.€I¡.€AƒZðI…PàI§ZÐA¥.ÐÁ§.€Á§.É§XÁ‡Pàɇ.àÁ§.É¥.Á‡. ɇ.°A¡.É¡.É‡\©B‡VÉʇ
^ɧ.¹Ê§.¹Â…VÉʃ\ÙÊ¡VéÂÆý?ÛÄõ.SÄõ.SäõoSÄõ.SæûoSÀ÷.[àõ?[¡.É¡.É†syʆsyʆsyʆsyʆsyʆsyʆsyʆsyʆs
yʆsyÊ[IʦZEÛæ[EÚæRKÛâSKÚâZE›æ[G[¦ZA.âRAJâRK
¢SI.¢ZI¢[G.¦SGfSI.¢RIJ¢Žs¹.Ž}©N†séJŽ(.SE.âSGJfSKŠâZC‹¢¦.¸¯.ù.®.9N¯.x
¯•éJ¥Õ©J            §.©J§ÔiB¯”éC­Ô©K©…mB¯•mB«Ô©J§.©J§.©J§.©J§.©J§.©J§.©J§.©J

Dal 320° byte ci sono varie manipolazione fino al 640° byte.

FINE ROUTINE "A".

KEYFILE CREATO.

Bene, ora ho spiegato a GRANDI linee anche la generazione del keyfiel a aprtire dal serial... in teoria potrei adesso spiegare allo stesso modo anche la sua crittazione, ma a questo punto dovreste conoscere almeno un po' di asm :) e quindi non farò come qui passo passo acnhe perchè la crittazione avviene attraverso vari valori radom / pseudorandom, quindi non ha senso mettere tutto passo passo, nonostante che anche nella routine appena vista ce ne fosse uno.

Da 40190B quindi, parte la crittazione del keyfile visto sopra. Eccovi tutti i vari cicli (non preoccupatevi, stavolta sono solo 12 :)).

:0040190B    mov eax, 00402BFC
:00401910    xor ecx, ecx
:00401912    mov ebx, dword ptr [00402BF0]
:00401918    mov edi, dword ptr [00402010]
:0040191E    mov esi, dword ptr [00402014]
:00401924    xor dword ptr [eax+ecx], ebx
:00401927    xor dword ptr [eax+ecx], esi
:0040192A    xor dword ptr [eax+ecx], edi
:0040192D    imul esi, edi
:00401930    ror esi, 02
:00401933    xor dword ptr [eax+ecx], esi
:00401936    xor ecx, ecx
:00401938    mov eax, 00402BFC

* Jump at Address:
|:0040194C(C)
|
:0040193D    mov edx, dword ptr [eax+ecx]
:00401940    mov dword ptr [ecx+004032C5], edx
:00401946    add ecx, 00000004
:00401949    cmp ecx, 00000028
:0040194C    jne 0040193D
:0040194E    mov eax, 00402BFC
:00401953    mov bx, word ptr [0040200E]
:0040195A    mov dx, word ptr [00402006]
:00401961    mov cx, word ptr [0040200C]
:00401968    xor bx, cx
:0040196B    xor cx, dx
:0040196E    xor cx, bx
:00401971    imul cx, bx
:00401975    add cx, dx
:00401978    mov dx, cx
:0040197B    xor ecx, ecx

* Jump at Address:
|:00401991(C)
|
:0040197D    mov bx, word ptr [eax+ecx]
:00401981    xor bx, dx
:00401984    mov word ptr [eax+ecx], bx
:00401988    add ecx, 00000004
:0040198B    cmp ecx, 00000400
:00401991    jne 0040197D
:00401993    mov eax, 00402BFC
:00401998    add eax, 00000002
:0040199B    mov bx, word ptr [00402004]
:004019A2    mov dx, word ptr [00402008]
:004019A9    mov cx, word ptr [0040200C]
:004019B0    xor cx, dx
:004019B3    imul cx, bx
:004019B7    xor cx, bx
:004019BA    mov bx, cx
:004019BD    mov dx, bx
:004019C0    xor ecx, ecx

* Jump at Address:
|:004019D6(C)
|
:004019C2    mov bx, word ptr [eax+ecx]
:004019C6    xor bx, dx
:004019C9    mov word ptr [eax+ecx], bx
:004019CD    add ecx, 00000004
:004019D0    cmp ecx, 00000404
:004019D6    jne 004019C2
:004019D8    mov eax, dword ptr [00402BF4]

* Jump at Address:
|:004019E8(C)
|
:004019DD    xor dword ptr [ecx+004032C5], eax
:004019E3    sub ecx, 00000004
:004019E6    test ecx, ecx
:004019E8    jne 004019DD
:004019EA    mov eax, 00402BFC
:004019EF    add eax, 00000093

* Jump at Address:
|:00401A03(C)
|
:004019F4    mov ebx, dword ptr [ecx+004032C5]
:004019FA    mov dword ptr [eax+ecx], ebx
:004019FD    add ecx, 00000004
:00401A00    cmp ecx, 00000028
:00401A03    jne 004019F4
:00401A05    mov edx, dword ptr [00402BF4]
:00401A0B    imul edx, 00000096
:00401A11    mov eax, 00402BFC
:00401A16    mov ecx, 000002BC
:00401A1B    xchg edx, ecx

* Jump at Address:
|:00401A25(C)
|
:00401A1D    ror dword ptr [eax+edx], cl
:00401A20    sub edx, 00000004
:00401A23    test edx, edx
:00401A25    jne 00401A1D
:00401A27    mov eax, 00402BFC
:00401A2C    xor ecx, ecx

* Jump at Address:
|:00401A49(C)
|
:00401A2E    mov ebx, dword ptr [ecx+00402BFC]
:00401A34    xor ebx, dword ptr [00402010]
:00401A3A    mov dword ptr [ecx+00402BFC], ebx
:00401A40    add ecx, 00000004
:00401A43    cmp ecx, 000002BC
:00401A49    jne 00401A2E
:00401A4B    xor ecx, ecx
:00401A4D    mov eax, 00402BFC
:00401A52    mov ebx, 00402BFC
:00401A57    add ebx, 00000200

* Jump at Address:
|:00401A6F(C)
|
:00401A5D    mov edx, dword ptr [eax+ecx]
:00401A60    xor edx, dword ptr [ebx+ecx]
:00401A63    mov dword ptr [ecx+004032C5], edx
:00401A69    add ecx, 00000004
:00401A6C    cmp ecx, 00000040
:00401A6F    jne 00401A5D
:00401A71    mov eax, 00402BFC
:00401A76    xor ecx, ecx

* Jump at Address:
|:00401A87(C)
|
:00401A78    mov edx, dword ptr [ecx+004032C5]
:00401A7E    mov dword ptr [eax+ecx], edx
:00401A81    add ecx, 00000004
:00401A84    cmp ecx, 00000040
:00401A87    jne 00401A78
:00401A89    xor ecx, ecx
:00401A8B    mov eax, 00402BFC
:00401A90    mov ebx, 00402BFC
:00401A95    add ebx, 0000015C

* Jump at Address:
|:00401AB0(C)
|
:00401A9B    mov edx, dword ptr [eax+ecx]
:00401A9E    xor edx, dword ptr [ebx+ecx]
:00401AA1    mov dword ptr [ecx+004032C5], edx
:00401AA7    add ecx, 00000004
:00401AAA    cmp ecx, 0000015C
:00401AB0    jne 00401A9B
:00401AB2    xor ecx, ecx
:00401AB4    mov eax, dword ptr [00402010]
:00401AB9    mov ebx, dword ptr [00402014]
:00401ABF    mov cx, word ptr [0040200E]
:00401AC6    xor dx, ax
:00401AC9    xor dx, bx
:00401ACC    xor ecx, ecx
:00401ACE    mov eax, 00402BFC

* Jump at Address:
|:00401AE7(C)
|
:00401AD3    mov bx, word ptr [eax+ecx]
:00401AD7    xor bx, dx
:00401ADA    mov word ptr [eax+ecx], bx
:00401ADE    add ecx, 00000003
:00401AE1    cmp ecx, 00000165
:00401AE7    jne 00401AD3
:00401AE9    xor ecx, ecx
:00401AEB    mov eax, dword ptr [00402014]
:00401AF0    mov eax, dword ptr [00403235]
:00401AF5    mov ebx, dword ptr [00402010]
:00401AFB    mov cx, word ptr [0040200C]
:00401B02    xor dx, ax
:00401B05    xor dx, cx
:00401B08    xor ecx, ecx
:00401B0A    mov eax, 00402BFC

* Jump at Address:
|:00401B23(C)
|
:00401B0F    mov bx, word ptr [eax+ecx]
:00401B13    xor bx, dx
:00401B16    mov word ptr [eax+ecx], bx
:00401B1A    add ecx, 00000005
:00401B1D    cmp ecx, 000002BC
:00401B23    jne 00401B0F
:00401B25    ret

Bene... le manipolazioni ho già detto non sto qui a descriverle passo passo perchè cnon avrebbe senso, bensì spiegherò come vengono presi i valori random usati per la crittazione, cioè precisamente quelli nei buffer 402BF0, 402010, 402014, 4032C5, 402BF4, 40200E, 402006, 40200C, 402004, 402008, 403235. Cazzo però quanti sono!! Qui Quequero si è proprio sbirrarrito eh?

Vabbè, tanto vale iniziare subito. Partiamo dal 1° che troviamo: 402BF0. A rigore per vedere dove questo buffer viene in qualche modo scritto si dovrebbe mettere un bp dai Sice, ma è + semplice per ora guardare il testo disassemblato cercando tale stringa... infatti osservando bene notiamo che tale buffer viene scritto solo in un punto del codice, precisamente qui:

* Referenced by a CALL at Address:
|:00401058  
|
:004014D0    push 00402010

* Reference To: USER32.GetCursorPos, Ord:0000h
                                 
:004014D5    Call 00401E67
:004014DA    mov eax, dword ptr [00402010]
:004014DF    mov ebx, dword ptr [00402014]
:004014E5    inc eax
:004014E6    inc ebx
:004014E7    add eax, ebx
:004014E9    imul eax, ebx
:004014EC    xor eax, ebx
:004014EE    mov dword ptr [00402BF0], eax
:004014F3    ret

Innanzi tutto sappiamo che la chiamata avviene a 401058, e se andate a vedere lì vi accorgerete che siamo proprio nel punto il cui il prog viene eseguito, prima che venga disegnata la finsestra e prima ancora del 1° trick anti-Sice. Analizziamo ora la chiamata all'API GetCursorPos. Eccone la definizione: "The GetCursorPos function retrieves the screen coordinates of the cursor's current position." Beh non sembra difficile... piccola nota: quest'API non dà valori di ritorno, e il push che la precede serve a dire dove mettere le coordinate. Precisamente, una viene messa in 402010, l'altra una dword + avanti, in 401014. Fatto ciò, i byte delle 2 coordinate vengono messi in rispettivamente in eax ed ebx, i valori di tali registri vengono incrementati di 1, su du essi vengono fatte delle semplici operazioni di manipolazione e il risultato finale viene messo in 402BF0. Ecco quindi che abbiamo determinato il contenuto di 402BF0, 402010 e 402014 (tutti e tre non subiranno + alcuna manipolazione prima di essere usati per la crittazione del keyfile).

Passiamo adesso al prossimio... cioè 4032C5. Beh, se guardiamo l'ultima sua modifica prima che esso venga utilizzato all'indirizzo 4019F4 vediamo che esso è un buffer che non assume particolari valori random, bensì viene modificato e manipolato dalla routine stessa.

Ora abbiamo 402BF4, che diventa già + interessante :)). Vi ricordate la CALL a 40124C riguardo al serial fisso, quella che vi avevo detto di dimenticare? Bene, è proprio quella la responsabile della maniolazione di questo buffer. Proviamo infatti a vedere cosa c'è al suo interno... ecco cosa ci troveremo davanti.

* Referenced by a CALL at Address:
|:0040124C
  
|
:0040159C    push 00000002   ;Parametro di condivisione in lettura
:0040159E    push 00402050
  

* Possible StringData Ref from Data Obj ->"c:\autoexec.bat"
                                             ^
:004015A3    push 00403204   ;Nome file------|

* Reference To: KERNEL32.OpenFile, Ord:0000h

:004015A8    Call 00401E43   ;Chiamata all'API OpenFile
:004015AD    mov dword ptr [00402BF4], eax
:004015B2    push 00000000
:004015B4    push dword ptr [00402BF4]   ;Handle del file

* Reference To: KERNEL32.GetFileSize, Ord:0000h

:004015BA    Call 00401E4F    ;Chiamata a GetFileSize
:004015BF    mov dword ptr [00402BF4], eax
:004015C4    push 00000000
:004015C6    push dword ptr [00402BF8]

* Reference To: KERNEL32.GetFileSize, Ord:0000h

:004015CC    Call 00401E4F
:004015D1    mov dword ptr [00402BF8], eax
:004015D6    mov ebx, dword ptr [00402BF4]
:004015DC    mov ecx, dword ptr [00402BF8]
:004015E2    xor ecx, ebx
:004015E4    xchg ecx, ebx
:004015E6    rol ebx, cl
:004015E8    mov dword ptr [00402BF4], ebx
:004015EE    ret   ;Ritorno dalla CALL


Beh, la situazione è molto semplice: a 4015A8 viene chiamata l'API OpenFile con i vari parametri da pushare. Come si può notare con un "d 403204" dal Sice o dallo stesso file disassemblato, il file aperto è l'autoexec.bat. La strigna ASCII ottenuta con il comando sopra è esattamente "c:\autoexec.bat.c:\windows\system.ini.CryKey.key" (il byte NULL subito dopo il .bat, qui visualizzato come un punto, indica la fine del nome file). Una volta aperto con condivisione in lettura, il contenuto di eax, cioè l'handle del file, viene spostato in un buffer, 402BF4. Dopo di questo, viene pushato proprio l'handle dell'autoexec.bat e viene chiamata l'API GetFileSize, la cui funzione è quella di riportare il valore della grandezza (naturalmente in byte) di un file in eax. Ecco quindi che ora che all'indirizzo 4015BF in eax avremo proprio la grandezza del nostro autoexec.bat (per controllare basta scriversi il valore di eax, andare a vedere quello del file, convertire quest'ultimo in hex e notare che i due valori coincidono. Tale valore viene poi spostato in un buffer, 402BF4.

Fatto ciò viene richiamata di buovo l'API GetFileSize ma con un altro handle, e precisamente quello nella dword all'indirizzo 402BF8, come si vede facendo "d 402BF8" sempre dall'Ice. Hum... l'handle naturalmente non coincide con quello precedente: questo infatti è 08, l'altro era 0C, quindi evidentemente si tratta di un altro file. Affinchè però si possa chiamare un GetFileSize bisogna avere l'handle del file di riferimento, e questo si può ottenere aprendo inl qualche modo il file stesso. Da ciò deduciamo molto semplicemente che ad un certo punto del prog. un altro file viene aperto, e il suo handle viene salvato apunto in 402BF8... ora noi sappiamo che l'apertura dell'autoexec.bat avviene dopo la pressione del pulsante "Register" per il check del serial fisso, ma essend oche a questo punto l'handle del file esiste già, l'unica spiegazione è che ad un certo punto del prog venga aperto un altro file... ma quando? Beh per scoprirlo basta semplicemente uscire dal prog., settare un bpx su OpenFile, riavviare tutto e... boooommm!! Il Sice ricompare. Solito F11 ed eccoci qui:

* Referenced by a CALL at Address:
|:0040103C  

|
:00401B56    push 00000002
:00401B58    push 00402050

* Possible StringData Ref from Data Obj ->"c:\windows\system.ini"

:00401B5D    push 00403214   ;buffer dove è scritto il nome del file

* Reference To: KERNEL32.OpenFile, Ord:0000h

:00401B62    Call 00401E43
:00401B67    mov dword ptr [00402BF8], eax 
:00401B6C    push 00000000

* Reference To: KERNEL32.GetModuleHandleA, Ord:0000h

:00401B6E    Call 00401E37
:00401B73    mov dword ptr [00402018], eax
:00401B78    ret


Bingo!! Come potete vedere, il buffer 403214 contine il nome del file "c:\windows\system.ini", e infatti 403204 (buffer autoexec.bat) + F (lunghezza della stringa c:\autoexec.bat, 15 charz, 15 dec = F hex) + 1 byte NULL = 403214, cioè proprio il buffer che contiene "c:\windows\system.ini"... vabbè il ragionamento serviva solo per notare che i due buffer erano praticamente attaccati, anche se non centra molto col reversing :)). Vediamo che allora eax (l'handle di ritorno) viene spostato proprio in 402BF8, cioè il buffer che inseguito verrà pushato per l'API GetFileSize, e infatti eax contiene proprio il valore 08, che poi sarà l'handle pushato per il GetFileSize successivo.

Tornando a noi, ora sappiamo quali sono i 2 file di cui si prendono le rispettive grandezze. Bene, ora è semplicissimo anche capire che una volta chiamata l'API GetFileSize per i due file, i valori di ritorno, spostati in 2 buffer, vengono manipolati per qualche riga di codice e poi il risultato della manipolazione viene messo proprio in 402BF4. Anche in questo caso abbiamo capito cosa contiene questo buffer :). Avanti il prossimo!!

Ora manca solo 403235. Beh, che dire, l'abbiamo già trovata :)). Infatti questo buffer viene modificato solo in 401400, cioè durante il check del serial generato. Eccovi ricopiata di nuovo la CALL relativa.

* Referenced by a CALL at Address:
|:004013C8
  

|

* Reference To: KERNEL32.GetTickCount, Ord:0000h

:004013EF    Call 00401E61
:004013F4    mov dword ptr [00403235], eax   ;eax viene messo in un buffer
:004013F9    mul dword ptr [00403239]  
:004013FF    inc eax   ;eax incrementato di 1
:00401400    mov dword ptr [00403235], eax   ;e messo nel buffer che a noi interessa
:00401405    ret

Precisamente si arriva qui dall'ultima CALL subito prima che venga letto il serial. Solita piccola manipolazione, solito valore spostato nel buffer :).

()()()()()()()()()()()()()()()()()()()()

PARTE 4: TRICK ANTI-BOX

()()()()()()()()()()()()()()()()()()()()

Raga, che dire? Avete inserito il seial iniziale corretto? Avete inserito un serial corretto? Avete messo nella stessa dir del crackme un keyfile valido? Avete premuto register?

Ma allora perchè cazzo non appare nessuna box di registrazioooooneeeeeee!!!!!!!

Dunque, abbiamo visto che il programma esegue ogni volta tutti e 3 i check anche se qualcosa è sbagliato, e non ci avvisa direttamente se il check ha avuto esito positivo o meno, però almeno alla fine è quantomeno lecito supporre che almeno una box di congratulazioni appaia. Beh, per provare a vedere basta continuare a vedere cosa sucede dopo il check del keyfile.. Eccovi un po' di codice :)) :

* Reference To: USER32.GetWindowTextA, Ord:0000h

:00401522    Call 00401EC7
:00401527    call 0040167F
:0040152C    call 00401B79
:00401531    call 00401BCE
:00401536    mov ebp, 4243484B
:0040153B    mov ax, 0004
:0040153F    int 03
:00401540    cmp al, 04
:00401542    je 004011EE
:00401548    mov esi, 00402BFC
:0040154D    mov edi, 004025F0
:00401552    mov ecx, dword ptr [004031FC]
:00401558    repz
:00401559    cmpsb
:0040155A    je 00401DE9

* Jump at Address:
|:00401B92(C)
|
:00401560    mov dword ptr [004032A3], 000057A3
:0040156A    jmp 00401DF3

Come possiamo vedere, dopo il check il prog salta in 2 posti diversi, situati a pochi byte di distanza, a seconda che il keyfile sia valido o meno. Beh, guardiamo DOVE salta...

* Jump at Address:
|:0040155A(C)
|
:00401DE9    mov dword ptr [004032A3], 000057B3

* Jump at Address:
|:0040156A(U)
|
:00401DF3    xor eax, eax
:00401DF5    mov eax, dword ptr [0040329B]
:00401DFA    mov ebx, dword ptr [0040329F]
:00401E00    add eax, ebx
:00401E02    mov ebx, dword ptr [004032A3]
:00401E08    add eax, ebx
:00401E0A    mov ebx, dword ptr [00403431]
:00401E10    add eax, ebx
:00401E12    mov ecx, 5723814A
:00401E17    xor eax, ecx
:00401E19    rol eax, cl
:00401E1B    cmp eax, 8982D55C
:00401E20    jne 00401108
:00401E26    call 00401B26

Umma umma... vediamo una serie di manipolazioni  e poi un cmp che se dà esito positivo esegue una CALL, altrimenti manda tutto ad cazzum di nuovo. Io guarderei cosa c'è dentro la CALL... guardiamo un po'...

* Referenced by a CALL at Address:
|:00401E26  
|
:00401B26    push 00000020

* Possible StringData Ref from Data Obj ->"Congratulazioni!!!"
                  
:00401B28    push 00403555

* Possible StringData Ref from Data Obj ->"Bravissimo finalmente hai crackato "
                     
:00401B2D    push 0040357D
:00401B32    push 00000000

* Reference To: USER32.MessageBoxA, Ord:0000h
               
:00401B34    Call 00401EA3

* Reference To: KERNEL32.ExitProcess, Ord:0000h
                   
:00401B39    Call 00401E2B

Sogno o son desto??? E' la box di congratulazioni che ci dice che siamo stati del bravi reverser :)) !!! Aspè aspè... noi però abbiamo inserito pass, serial e keyfile esatti, e perchè allora non appare?!?! Steppando con Sice a 401E20 infatti, vediamo che il jump dà esito negativo... come può essere??? Beh, basta esaminare bene quel pezzo di codice che sta tra 401DF3 e 401E26, poichè sono proprio tali manipolazioni che determinano l'esecuzione o meno del salto.

:00401DF3    xor eax, eax
:00401DF5    mov eax, dword ptr [0040329B]
:00401DFA    mov ebx, dword ptr [0040329F]
:00401E00    add eax, ebx
:00401E02    mov ebx, dword ptr [004032A3]
:00401E08    add eax, ebx
:00401E0A    mov ebx, dword ptr [00403431]
:00401E10    add eax, ebx
:00401E12    mov ecx, 5723814A
:00401E17    xor eax, ecx
:00401E19    rol eax, cl
:00401E1B    cmp eax, 8982D55C
:00401E20    jne 00401108
:00401E26    call 00401B26

Osserviamo la situazione col Sice, ma SOLO avendo inserito pass, serial e keyfile validi. Allora, vediamo che eax viene preparato, quindi in esso viene messo il valore F896, in ebx il valore 91B2, c'è uan somma logica tra eax ed ebx che restituisce 18A48 in eax, poi in ebx viene messo il valore 57B3, c'è ancora un'altra somma logica che ritorna in eax 1E1FB, ebx viene azzerato, altra somma logica che però non modifica il valore di eax, in quanto ebx = 0, eax viene xorato con 5723814A, c'è un rol tra eax e cl (se ecx = aabbccddee cl = ee) e il valore finale di eax è 8982C55C, che differisce in una cifra da 8982D55C. Che fare? Beh, la box dobbiamo farla apparire senza modificare codice :) e con tutte le richiese passate, quindi deve esserci qualche condizioe in cui uno dei buffer qui utilizzati assuma altri valori per cui eax alla fine diventi 8982D55C. Da esaminare ne abbiamo 4: 40329B, 40329F, 4032A3, 403431. Partiamo dal 1°.

:004012D9    je 00401300
:004012DF    mov dword ptr [0040329B], 0000F892
:004012E9    jmp 0040130A

...................

:00401300    mov dword ptr [0040329B], 0000F896

Questo è l'unico punto dove tale buffer viene modificato... cioè precisamente al check della pass iniziale: se è corretta in esso viene messo il valore F896, altrimenti F892... però noi dobbiamo far si che la box appaia uanto tutto è stato inserito correttamente, quindi dobbiamo lasciare che il prog metta F896 in questo buffer. Proseguiamo col prossimo.

:00401613    repz
:00401614    cmpsb
:00401615    je 004014F4
:0040161B    mov dword ptr [0040329F], 000091C2
:00401625    jmp 004014FE

...................

* Jump at Address:
|:00401615(C)
|
:004014F4    mov dword ptr [0040329F], 000091B2

Qui siamo al check del serial... se è corretto in 40329F viene messo il valore 91B2, altrimenti 91C2... non ci sono altre possibilità... niente continuiamo...

:00401558    repz
:00401559    cmpsb

:0040155A    je 00401DE9

* Jump at Address:
|:00401B92(C)
|
:00401560    mov dword ptr [004032A3], 000057A3
:0040156A    jmp 00401DF3


...................

* Jump at Address:
|:0040155A(C)
|
:00401DE9    mov dword ptr [004032A3], 000057B3

Qui invece siamo al 3° check, quello del keyfile... identica cosa anche qui... se il file è valido, allora in 4032A3 viene messo il valore 57B3, altrimenti il valore 57A3. Non ci resta che guardare l'ultimo buffer rimasto...

* Possible StringData Ref from Data Obj ->"CrackMe 5 About Box"
                    
:004011BA    push 0040344E

* Possible StringData Ref from Data Obj ->"CrackMe 5 coded by Quequero for "
                                        ->"UIC"
                     
:004011BF    push 00403462
:004011C4    push 00000000

* Reference To: USER32.MessageBoxA, Ord:0000h
                        
:004011C6    Call 00401EA3
:004011CB    inc dword ptr [00403431]   ;dword incrementata di 1

Qui invece la cosa si fa interessante... vediamo che c'è la chiamata alla messagebox del pulsante "About" e subito sotto la dword a 403431 viene incrementata di 1; ciò significa che ogni volta che premiano il pulsante "About" (non essendoci altri riferimenti alle stringhe del testo della box) la dword puntata dal buffer in questione viene incrementata di 1, e che quindi senza mai premere tale pulsante essa rimane a 00 00 00 00, come basta facilmente vedere con un "d 403431". Bene, questo è l'unico punto in cui posiamo agire.

Facciamo un po' di conti: all'indirizzo 401E1B eax deve aver valore 8982C55C per far comparire la box. Essendo cl non modificabile, allora nel calcolo a 401E19 l'unico parametro che può variare è eax, il quale di conseguenza per poter assumere a 401E1B il valore 8982D55C in 401E19 deve essere uguale a 8982C55C ror cl, quindi 8982C55C ror 4A (l'operazione fatta al contrario), ossia 572260B5. Di conseguenza, sempre continuando a fare le operazioni al contrario, in 401E17 deve assumere il valore 1E1FF, che poi è lo stesso valore assunto a 401E12. Però noi possiamo notare che a quell'indirizzo eax in realtà eax ha valore 1E1FB. Il valore 1E1FB però viene assunto con ebx = 0, e il valore di ebx non è forse quello della dword puntata da 403431? E la dword 403431 non è quella dword che viene incrementata di 1 ogni volta che premiamo il tasto "About"? Certo!! ora tutto dovrebbe essere chiaro: sappiamo che ebx a 401E10 deve essere uguale a 4 per far assumere a eax il valore necessario a far attivare lo ZeroFalg dopo il compare, in quanto esso viene sommato al valore assunto da eax, che in questo caso è 1E1FB. Infatti, 1E1FB + 4 = 1E1FF, 1E1FF xor 5723814A = 57226065, 50226065 rol 4A = 8982D55C!! Semplice no? :)). Ecco svelato il trucchetto adottato da Quequero: prima del check del serial basta premere in qualsiasi momento 4 volte il tasto "About" in modo che quel 403431 assuma il valore corretto che poi permetterà alla box di congratulazioni di comparire.

Ora voi direte: "E gli altri 3 buffer". Beh, gli altri 3 buffer potevano assumere solo un altro valore oltre a quello da loro assunto, il che poteva verificarsi solo nel caso si sbagliasse qualche check.

Tutto ciò cosa ci dice? Beh, semplice, ci dice che la box si può far apparire anche mettendo tutti valori fasulli, a patto di premere il pulsante "About" quel po' di volte necessario a dare ad eax il valore 1E1FF all'indirizzo 401E12 :). Naturalmente però è necessario inserire un serial di 15 char ad avere un file chiamato "CryKey.key" nella stessa dir del crackme, altrimenti l'esecuzione manda tutto a quel paese senza nemmeno passare per questo punto :)).

Perfetto.. anche questa parte è treminata. Adesso sappiamo come far apparire la box, come ottenere pass, serial e keyfile validi, non ci resta che passare alla

()()()()()()()()()()()()()()()()()()()()

PARTE 5: KEYGENERATOR

()()()()()()()()()()()()()()()()()()()()

Bene raga... adesso che abbiamo capito tutto, non ci resta che fare il KeyGen (è l'ultima parte del tute, non vi preoccupare ;) )!! Hehe pensavate di aver finito eh?! :) Beh in questa parte non mi dilungherò + tanto, in quanto assieme all'eseguibile nell'allegato vi metto anche i sorgenti commentati, quindi basta guardare lì.

Prima di tutto però bisogna scegliere il linguaggio... mah io direi di scriverlo in VB, scommetto che Que è d'accordo, vero Que? :)) Naturalmente scherzo :), cmq i linguaggi in cui si potrebbe farlo direi che potrebbero essere 3: C, Pascal, Assembler. Beh, io sinceramente ho scelto l'asm per alcuni motivi: si possono incollarci tutte le routine mettendole solo un po' a posto, e poi è un utile esercizio per imparare il linguaggio :).

Beh, qui non avrebbe senso stare a spiegare le varie routine di "preparazione", poichè quelle basta vederle nei sorgenti, bensì spiegherò solo quelle che servono a generare serial e keyfile. Andiamo coon ordine. La prima cosa da fare è creare un generatore di serial. Intanto dovremo usare un metodo per prendere il testo inserito, e questo si può fare tranquillamente con GetWindowTextA o GetDlgItemTextA, non cambia nulla (per le sintassi vi rimando al sogente :)) ). Una volta messo il testo in un buffer, bisogna manipolarlo fino ad arrivare a generare il serial, e questo abbiamo visto che accade subito dopo il ritorno dalla CALL all'indirizzo 4013C1, quindi sappiamo già che ciò che dovremo fare sarà manipolare il nome allo stesso modo come fa il crackme fino all'indirizzo 4013C6, quindi reindirizzare il buffer verso una chiamata che lo posiziona in unz text-box del keygen. Beh, non resta che fare una cosa: prendere il testo disassemblato del crackme da 401330 a 4013C6 e metterlo un po' a posto, ovvero toglierci gli opcode, gli indirizzi e dare ai buffer un nome (che non può essere numerico). Ad esempio, se il buffer che prende il testo del nosto keygen lo chiamiamo "Nome", allora tutti i buffer 403249 dovranno essere sostituiti con "Nome", i buffer 40324A con "Nome + 1", ecc... Anche i jump dovranno avere dei "nomi" e non dei numeri. Ultima cosa: la CALL finale (che poi è l'unica presente) non serve metterla come CALL, bensì copiarne il contenuto (sempre mettendo a posto le varie cose tipo opcode, jump, ecc...) al seguito del codice che c'è nel punto in cui esa viene chiamata. Ad esempio, invece che mettere

mov eax, 98
mov ecx, dword ptr [Buffer]
call xyz

xyz proc:
mov eax, 78
xor ecx, ecx
xyz endp

sarà + semplice fare

mov eax, 98
mov ecx, dword ptr [Buffer]
call xyz
mov eax, 78
xor ecx, ecx

Beh, poi per quanto riguarda il keyfile la cosa non cambia di molto, a parte qualche piccolo accorgimento: bisognerà stare attenti che venga generato a partire dal serial, non dal nome, e visto che un serial valido ha 15 caratteri bisognerà far si o che il prog riempi da solo i byte mancanti del serial, o che lo faccia colui che usa il prog :). Io ho fatto proprio così: il prog genera un serial valido per un dato nick, ma a quel serial bisogna aggiungere cifre a caso in modo da far diventare la stringa di 15 charz, in quanto a seconda dei byte che si mettono per riempire lo spazio necessario si generano keyfile diversi. Come per il generatore di serial, anche qui bisognerà utilizzare la routine chiamata dalla CALL all'indirizzo 401527 per generare il keyfile fino all'indirizzo 401909 compreso, stando attenti a utilizzare come buffer non lo stesso del serial, ma uno che parte 20 byte prima (con 20 byte NULL), in quanto 402BFC del crackme ha proprio 20 byte NULL prima del serial.

Per quanto riguarda i buffer non ci sono particolari difficoltà (non esistono valori random) a parte un paio di cose: il buffer 4032AF deve essere sostituito da uno che contenga la stringa "Headache by Quequero" e bisogna prestar particolare attenzione a 402BF4, poichè quello ha come valore il risultato di manipolazioni sulla lunghezza dell'utoexec.bat e del system.ini, quindi bisognerà scrivere una routine che manipoli le due lunghezze allo stesso modo e che restituisca il valore finale nel buffer corrispondente a 402BF4, da usare poi nella generazione del keyfile.

Per quanto riguarda l'aspetto esteriore del programmillo, beh qui potete sbizzarrirvi... io ho usato parti di codice di un template di RudeBoy che aveva a sua volta una parte di codice di Iczelion (già che ci sono allora saluto e ringrazio entrambi :) ), quindi vedete un po' voi!! :pp

Raga, mi sa finalmente che ho finito sto tute. Spero che vi sia stato utile sia per capire le varie protezioni del crackme, sia per imparare l'asm. Sono sicuro che, una volta riusciti a reversare tutto questo maledetto crackme, vedrete anche voi il reversing sotto un altro aspetto, avendo anche imparato un bel po' di cose nuove.

Ora però non voglio star qui a occupare altri byte inutili, visto che ne ho già presi un bel po'. Non mi resta che dire...

so' stanco, so' stufo ;) ...

Ciauzzzzzzz a tutti,


                                                                                                              Ritz

Note finali

Ed eccoci arrivati alla parte dei saluti... dopo un tute così lungo probabilmente non li leggerete nemmeno, cmq ci tengo a farli :).

Allora, saluto intanto Quequero, che mi deve dire quanto tempo ci ha messo a fare 'sto crackme... dì la verità Que ;), poi saluto...

Tutti gli amici della UIC, di #crack-it e di #uic e tutti i ringzer0, e in particolare kill3xx (che finalmente ho visto in IRC :) ), [aLT255], TiN_MaN, BlackDruiD (per le sue magie... hehe tnx Black ;) ), cod, Yado, ZeroByte, sPEzio (rivisto dopo un sacco di tempo), +MaLa (v.s ;) ), ^courier (v.s. di nuovo), xOANINO, WhiteFly, inx, GR!SU, [SaNdMaN], Johnny, BoBo, Nobody88, neural_noise, d4emon, Baneold, baron_sam, insomma tutti quanti :).

Tutti quelli con cui ho scambiato opinioni e consigli per questo corso nella ml, leggi Int19 (soprattutto per il discorso dei famigerati 6 charz ;) ), AndreaGeddon e Syscalo.

Tutti quelli che non ho potuto incontrare al meeting di mercoledì su #uic.

Disclaimer

Vorrei ricordare che il software va comprato e  non rubato, quindi se scaricate questo crackme dovete dare a Quequero un compenso :))!! Dovete inoltre registrare il vostro prodotto dopo il periodo di valutazione. Non mi ritengo responsabile per eventuali danni causati al vostro computer determinati dall'uso improprio di questo tutorial. Questo documento è stato scritto per invogliare il consumatore a registrare legalmente i propri programmi, e non a fargli fare uso dei tantissimi file crack presenti in rete, infatti tale documento aiuta a comprendere lo sforzo immane che ogni singolo programmatore ha dovuto portare avanti per fornire ai rispettivi consumatori i migliori prodotti possibili.
Noi reversiamo al solo scopo informativo e di miglioramento del linguaggio Assembly.
 

 
UIC's page of reverse engineering, scegli dove andare:

Home   Anonimato   Assembly    ContactMe  CrackMe   Links   
NewBies   News   Forum   Lezioni   
Tools   Tutorial   Search

UIC