Corso UIC n° 5 |
||
10/01/2000 |
by Ritz |
|
|
Published by Quequero |
|
Bellissimo tute Ritz...Se solo avessi consegnato prima! |
||
| UIC's form |
|
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 :)).
Introduzione |
Tools usati |
URL o FTP del programma |
Notizie sul programma |
Essay |
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
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«V8¾ ì
(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
Æpsrrv©{{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
Æpsrrv©{{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
Æpsrrv©{{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@ !kD)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@
!kD).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@
!kD)-.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@
!kD).)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@
!kD)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@
)kDô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@
)kDô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@
)kDô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@
)kDôQ²¨ôSã,ô_#¨ýW"è...@..PD
....Ñ@.@ .Á
§.©J§.©J§.©JZðIRð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
|
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 |
Home Anonimato Assembly
ContactMe CrackMe
Links
NewBies
News Forum Lezioni
Tools Tutorial
Search