A:link { TEXT-DECORATION: underline } A:visited { TEXT-DECORATION: underline } A:active { COLOR: red; TEXT-DECORATION: underline } A:hover { COLOR: #8080ff; TEXT-DECORATION: underline }
ZaiRoN's crackme Serial Fishing | ||
Data |
by Spider |
|
01/03/2001 |
Published by Quequero |
|
Qual è l'unico libro che comincia nel mezzo? |
Qualche mio eventuale commento sul tutorial :))) |
La Divina Commedia!... |
.... |
|
.... |
Difficoltà |
(X)NewBies ( )Intermedio ( )Avanzato ( )Master |
Un bel crackme nome/serial by ZaiRoN. Scaricate qui
il sorgente del KeyGenerator.
Introduzione |
- NO patching
- NO brute forcing
- keygen it!
Bene... vediamo cosa possiamo fare! :-)
Tools usati |
URL o FTP del programma |
Essay |
:0040115E xor ecx, ecx ;azzera
ecx (usato come contatore)
:00401160 xor eax, eax ;azzera eax
* Jump at Address:
|:00401178(U)
|
:00401162 cmp byte ptr [ecx+esi], 30h ;se l'ASCII del char
è minore di 30h...
:00401166 jb 0040119E
;...serial errato
:00401168 cmp byte ptr [ecx+esi], 3Ah ;se non è minore di
3Ah...
:0040116C jnb 0040117A
;...salta a 0040117A
:0040116E sub byte ptr [ecx+esi], 30h ;sottrae 30h
:00401172 inc ecx
;incrementa ecx per passare al prossimo char
* Jump at Address:
|:0040119C(U)
|
:00401173 cmp ecx, 00000009
;se abbiamo già controllato 9 caratteri
:00401176 je 004011A3
;salta al "ret"
:00401178 jmp 00401162
;altrimenti ripete il ciclo
* Jump at Address:
|:0040116C(C)
|
:0040117A cmp ecx, 00000002
;se il carattere non numerico è il terzo
:0040117D je 0040118B
;salta a 40118B
:0040117F cmp ecx, 00000005
;se è il sesto
:00401182 je 0040118B
;salta a 40118B
:00401184 cmp ecx, 00000008
;se è il nono
:00401187 je 0040118B
;salta a 40118B
:00401189 jmp 0040119E
;altrimenti... serial errato
* Jump at Addresses:
|:0040117D(C), :00401182(C), :00401187(C)
|
:0040118B cmp byte ptr [ecx+esi], 41h ;se il carattere è
minore di 'A' (41h)...
:0040118F jb 0040119E
;...serial errato
:00401191 cmp byte ptr [ecx+esi], 45h ;se il carattere è
maggiore di 'E' (45h)...
:00401195 ja 0040119E
;...serial errato
:00401197 sub byte ptr [ecx+esi], 37h ;sottrae 37h al
carattere
:0040119B inc ecx
;incrementa ecx
:0040119C jmp 00401173
;salta a 00401173
* Jump at Addresses:
|:00401166(C), :00401189(U), :0040118F(C), :00401195(C)
|
:0040119E mov eax, 00000001
;eax viene messo ad 1 quando il serial è errato
* Jump at Address:
|:00401176(C)
|
:004011A3 ret
Questa procedura lavora solo sui primi 9 caratteri del serial. Sono considerati caratteri validi soltanto i caratteri numerici (da '0' a '9', ossia da 30h a 39h), eccetto per il terzo, il sesto e il nono carattere che oltre a valori numerici possono avere i valori 'A' (41h), 'B' (42h), 'C' (43h), 'D' (44h), 'E' (45h). Nel caso di valori numerici viene sottratto 30h, quindi il valore finale sarà un numero compreso tra 0 e 9; nel caso di valori letterali viene invece sottratto 37h, e il valore finale sarà un numero compreso tra 10 e 14 (in pratica se ne considera il valore esadecimale. Ad esempio 0Ah esadecimale equivale a 10 decimale). Chiaro?
Bene, immettiamo un nuovo seriale, stando attenti a rispettare le condizioni imposte dalla procedura appena vista. Io ho usato il serial '123123123'. Dopo la call di poco fa troviamo un "test eax, eax" e un "jne" che, nel caso eax fosse stato messo ad 1, considera il seriale errato senza bisogno di ulteriori controlli.
Subito dopo avremo davanti una procedura che esegue una serie di calcoli sui caratteri del serial (opportunamente modificato dalla precedente procedura) e confronta il risultato finale con i caratteri del nome inserito. Vengono presi 3 caratteri del serial per volta e il ciclo è ripetuto tre volte. In ogni ripetizione del ciclo il risultato dei calcoli viene confrontato con un carattere del nome inserito (il primo carattere per il primo ciclo, il secondo per il secondo ciclo e il terzo carattere per il terzo ciclo [ma và...]). Per semplificare i calcoli, assegniamo delle lettere ai caratteri del serial coinvolti nel calcolo: a per il primo carattere, b per il secondo e c per il terzo.
:004010B7 xor edi, edi
;azzera edi \___ edi ed edx vengono usati
entrambi
:004010B9 mov edx, 00000000 ;azzera edx
/ come contatori, ma per scopi diversi
:004010BE push edx
* Jump at Address:
|:0040110D(U)
|
:004010BF movzx ebx, byte ptr
[edi+0040301B] ;ebx = b
:004010C6 movzx ecx, byte ptr [edi+0040301A]
;ecx = a
:004010CD mov esi, ecx
;esi = a
:004010CF imul eax, ebx, 3
;eax = 3b
:004010D2 add esi, eax
;esi = a+3b
:004010D4 mov eax, ebx
;eax = b
:004010D6 mul ebx
;eax = b2
:004010D8 add esi, eax
;esi = a+3b+b2
:004010DA mov eax, ecx
;eax = a
:004010DC mul ecx
;eax = a2
:004010DE add esi, eax
;esi = a+3b+a2+b2
:004010E0 imul ebx, ecx
;ebx = ab
:004010E3 imul ebx, 2
;ebx = 2ab
:004010E6 add esi, ebx
;esi = a+3b+a2+b2+2ab
:004010E8 mov eax, esi
;eax = a+3b+a2+b2+2ab
:004010EA mov edx, 2
:004010EF div dl
;eax = (a+3b+a2+b2+2ab)/2
:004010F1 imul eax, 0Eh
;eax = (a+3b+a2+b2+2ab)*7
:004010F4 add al, byte ptr [edi+0040301C]
;eax = (a+3b+a2+b2+2ab)*7+c
:004010FA pop edx
:004010FB cmp al, byte ptr [edx+00403007]
;confronta con un char del nome
:00401101 jnz short SerialErrato
;se sono diversi... serial errato :)
:00401103 add edi, 3
;passa ai 3 char successivi del serial
:00401106 cmp edi, 9
;se il ciclo è stato eseguito 3 volte...
:00401109 jz short 0040110F
;...salta a 0040110F
:0040110B inc edx
;incrementa edx
:0040110C push edx
:0040110D jmp short 004010BF
Bene... o forse male: ci troviamo di fronte
ad un'equazione a 3 incognite. Dobbiamo infatti trovare 3 valori a, b e c tali
che (a+3b+a2+b2+2ab)*7+c
= 83 (83 è il valore decimale di 'S'), e poi lo stesso con 112 ('p') e con 105
('i'). Le equazioni a 3 incognite hanno infinite soluzioni, ma... un momento! a,
b e c hanno un range molto limitato: a e b hanno valori compresi tra 0 e 9,
mentre c ha un valore compreso tra 0 e 13, come abbiamo visto prima. Pertanto le
combinazioni sono poche, potremmo anche andare a tentativi per trovare i valori
delle incognite, ma... meglio far fare tutto al nostro caro PC... Codiamo un
piccolo bruteforcer per trovare la giusta combinazione. Ecco il source (scritto in
VC++):
#include <windows.h> int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { char name[] = "Spi"; //ci bastano i primi 3 caratteri char serial[10]; unsigned int a; unsigned int b; unsigned int c; unsigned int count; for (count = 0;count < 9;count = count + 3) { for (a = 0; a < 10; a++) { for (b = 0; b < 10; b++) { for (c = 0; c < 14; c++) { if (((a+3*b+b*b+a*a+a*b*2)*7+c) == name[count/3]) { serial[count + 0] = a + 48; serial[count + 1] = b + 48; if (c < 10) { serial[count + 2] = c + 48; } else { serial[count + 2] = c + 48 + 7; } } } } } } for (count = 0; count < 10; count++) { serial[17-count] = serial[count]; } serial[9] = 0; MessageBox(NULL,serial,"I've found it!",MB_ICONINFORMATION); return 0; }
Bene. Compiliamo, eseguiamo... DING! Ecco la
nostra bella MessageBox che ci comunica di aver trovato il serial! Nel mio caso
è 02D120217. Abbiamo quindi trovato i primi 9 caratteri del nostro seriale :-)
Osserviamo adesso il codice immediatamente successivo alla procedura di poco fa:
*Jump at Address:
|:00401109(C)
|
:0040110F push 0000001E
:00401111 push 0040301A
:00401116 push 00000BBC
:0040111B push dword ptr [00403031]
* Reference To: GetDlgItemTextA
|
:00401121 Call 004014E4
:00401126 cmp eax, 00000012
:00401129 ja 00401149
Il crackme richiama un'altra volta GetDlgItemTextA per prelevare il seriale, dato che quello prelevato prima era stato modificato per il check. Confronta poi la lunghezza del serial con 12h (18 decimale), e se è maggiore salta alla solita locazione di wrong serial. La lunghezza del seriale è quindi presumibilmente di 18 caratteri.
Dopo questo codice, ha inizio una lunghissima procedura che non riporto a causa delle dimensioni. Inizialmente non avevo capito a cosa servisse; solo steppandola e risteppandola più volte ho intuito la sua funzione. In realtà è semplicissimo: controlla che i secondi 9 caratteri (dal decimo in poi) siano esattamente l'inverso dei primi 9. Pertanto se i primi 9 caratteri erano 02D120217, il serial completo sarà 02D120217712021D20. Inseriamo il serial, premiamo ok e... "Good work!".
Spider
Note finali |
Saluti a ZaiRoN che ha fatto il crackme, e poi ovviamente un saluto va a tutti gli
studenti e frequentatori di UIC, Ringz3r0, Itassembly, #crack-it e #asm.
Disclaimer |
I crackme vanno COMPRATI e non rubati. Dopo
aver trovato il serial dovete inviare all'autore i soldi necessari (ZaiRoN, poi
dividiamo, ok? :-P).
Noi reversiamo al solo scopo informativo e di miglioramento del linguaggio Assembly.