|
Soluzione del crackme 6 |
||
|
Data |
by Artemis |
|
|
2-3-4-5 Marzo 2003 |
Published by Quequero |
|
|
|
Ebbravo artemis, allora... Come ti ho commentato l'algoritmo e' un hash basato su RSA ma e' l'ho creato per collidere un pochetto, l'analisi che tu ne fai e' corretta, a voi resterebbe solo dover bruteforzare lo spazio delle chiavi (32-bit a pezzo) cercando di trovare le condizioni di collisione che nessuno ha cercato... Si anche dopo che in mailinglist postai la forma del seriale che ripeto essere: "Xxxxxxx xx xxxx!" ;p a buon intenditor.... |
Ho risolto il corso... e cosa voglio di più dalla vita? Un pò di metano!!! |
|
«~{Å}~» |
|
«~{Å}~» |
|
Difficoltà |
( )NewBies ( )Intermedio ( )Avanzato (x)Master |
|
E' un semplice (all'apparenza) innocente (poi questa!) crackme che richiede di trovare il seriale e sono concessi tutti i tools esistenti nel mondo del reversing. :) Ah ovviamente se bisogna trovare il seriale, non dobbiamo patcharlo!
|
Introduzione |
|
Tools usati |
|
URL o FTP del programma |
|
Notizie sul programma |
|
Essay |
mov eax, 29832382h
mov 00401000, eax
mov ebx, 29832782h
mov 00401003, ebx <- attenti a quest'ultima
come vedete ebx poi va a sovrascrivere una parte della locazione precedente, che necessita di 4 bytes e se vedete, la distanza tra la prima e la seconda locazione è 3 bytes!
Questi giochetti fortunatamente Què non li ha inseriti. Poi vedendo tanti nop nel codice mi sono preoccupato che non ci fosse SMC, o routines che copiavano codice lì dentro. E l'insicurezza è sparita leggendo in un altro tute un commento di Què che diceva di non avere inserito lui quei nop ma il il compilatore, per non incasinare il processore.
Così dopo questi controlli, niente packer e niente trucchetti descritti sopra, ho inserito delle variabili come key1, key2 etc. al posto delle locazioni di memoria, ho sostituito i salti di alcuni cicli inserendo While (così si leggono meglio) e ho messo tutto nella prima finestra di notepad. Ecco tutta la prima finestra ben commentata (poi lavoreremo solo con la seconda finestra):
<<<<<<<<<< FIRST WINDOW OF NOTEPAD >>>>>>>>>>
Il numero seriale deve essere di 16 caratteri
variabili:
key1 = 004020CC <- i primi 4 caratteri del seriale al contrario, cioè ABCD diventa DCBA
key2 = 004020D0 <- 4 caratteri del seriale a partire dal 5°, messi al contrario
key3 = 004020D4 <- 4 caratteri del seriale a partire dal 9°, messi al contrario
key4 = 004020D8 <- gli ultimi 4 caratteri del seriale, messi al contrario
Ovviamente key1, key2, key3 e key4 sono le parti spezzettate del nostro seriale.
temp1 = 0040145D
start:
call ExitProcess
cmp eax, FFFFFFFF <- confronta se eax è -1, perché la imul di sopra era signed!
otherop:
While (eax!=0) {
cmp temp4, FFFFFFFF
elabora ENDP
algoritmo ENDP
mov ebx, temp4 <- ricordo che temp4 = (key1 + key2 -1) * (key3 + key4)
While (ebx > 255) {
cdq
chiamata2 ENDP
imul eax, eax <- eleva al quadrato la key in eax
esci:
chiamata1 ENDP
* Possible StringData Ref from Data Obj ->"Bravo!"
{...}
ret
check_seriale ENDP
temp2 = 00401461
play1 = 00401465
play2 = 00401469
play3 = 0040146D
play4 = 00401471
temp3 = 00401475
temp4 = 00401479
mov eax, key1
imul eax, 93572678
mov ebx, key2
imul ebx, 26547305
mov ecx, key3
imul ecx, 37569814
mov edx, key4
imul edx, 89653715
add eax, ebx
add eax, ecx
add eax, edx
push eax <- da qui in poi lo stack non viene usato
mov temp1, eax <- temp1 non viene più richiamata da nessuna parte
xor eax, eax <- eax viene azzerato!!! Il codice sopra non serve!
mov eax, key1 <- il calcolo del seriale inizia da qui
add eax, key2
mov temp2, eax <- temp2 = key1 + key2
mov eax, key3
add eax, key4
mov temp3, eax <- temp3 = key3 + key4
mov eax, temp2
dec eax <- occhio eh! E' come se sottraesse 1 a temp2 (vedi sotto)
mov ebx, temp3 <- mette temp3 in ebx
dec temp3 <- non serve, temp3 non verrà più richiamato!
imul eax, ebx <- moltiplica (temp2 - 1) * temp3
mov temp4, eax <- mette tutto in temp4
call elabora
elabora PROC
jg otherop
nop
nop
nop
nop
neg eax <- se è min o uguale a 0, moltiplica per -1
mov ecx, 14
cdq <- trasforma una dword in una qword (quadword)
idiv ecx <- divide eax per 14 (ahaha gioco di parole... divide "per" :)
mov ebx, key1 <- completamente obsoleto da qui...
imul ecx, ebx
mov ecx, key3 (forse Què non voleva usare Sleep per ritardare il calcolo =)
imul ecx, ecx <- ...a qui; perché ogni ciclo sovrascrive sia ebx che ecx
dec eax
rol key1, 05 <- qui la cosa è importante... rotate left di 5 bit della key1
ror key3, 04 <- rotate "right" della key3 di b bit a destra.
}
jg sub_and_check <- solito check del -1, insomma què vuole num >= a 0
nop
nop
nop
nop
neg temp4
sub_and_check:
sub temp4, 0321CCFA <- attenti sottrae 0321CCFA a temp4
cmp temp4, FFFFFFFF <- e verifica se siamo andati sul negativo :)
jg passa_ad_algoritmo
nop
nop
nop
nop
neg temp4
passa_ad_algoritmo:
call algoritmo <- ora inizia l'ultima parte
ret
algoritmo PROC <- Da qui in poi lasciate perdere le variabili play, sono
solo trucchi... appunto "play" giochi.
mov eax, key1 <- modifica "il valore" della key1
call chiamata1
call chiamata2
sub key1, ebx <- e dopo aver elaborato lo sottrale alla key1 stessa
mov eax, key1 <- falso!
mov play1, eax <- falso! Le play non vengono mai usate!
mov eax, key2 <- come sopra, ma usa la key2
call chiamata1
call chiamata2
sub key2, ebx
mov eax, key2 <- falso!
mov play2, eax <- falso!
mov eax, key3 <- come sopra, ma usa la key3
call chiamata1
call chiamata2
sub key3, ebx
mov eax, key3 <- falso!
mov play3, eax <- falso!
mov eax, key4 <- come sopra, ma usa la key4
call chiamata1
call chiamata2
sub key4, ebx
mov eax, key4 <- falso!
mov play4, eax <- falso!
call check_seriale <- inizia il confronto!
ret
chiamata2 PROC
sub ebx, 000000FF <- in pratica sarebbe (ebx mod 255)
}
idiv ebx <- divide eax per il valore ottenuto con il mod
imul eax, temp4 <- e moltiplica il tutto per temp4
mov ebx, eax <- ecco il valore che esce dalla seconda elaborazione
ret
chiamata1 PROC
cmp eax, FFFFFFFF <- solito check!
jg esci
nop
nop
nop
nop
neg eax
ret
check_seriale PROC
Non mi fate spiegare pure qui... verifica se i valori
mov eax, key1 delle key elaborate corrispondono a quei valori!
cmp eax, 0C185C58
jne seriale_errato
nop
nop
nop
nop
mov eax, key2
cmp eax, 55F2600F
jne seriale_errato
nop
nop
nop
nop
mov eax, key3
cmp eax, 35CE68B2
jne seriale_errato
nop
nop
nop
nop
mov eax, key4
cmp eax, 1F3EECFA
jne seriale_errato
nop
nop
nop
nop
<<<<<<<<<< EOF-IRST WINDOW OF NOTEPAD >>>>>>>>>>
Adesso possiamo estrapolare dall'analisi, in formule matematiche quello che fa il
programma nel dettaglio:
<<<<<<<<<< SECOND WINDOW OF NOTEPAD >>>>>>>>>>
temp2 = key1 + key2 - 1
temp3 = key3 + key4
temp4 = temp2 * temp3 ;fino ad elabora
temp4 = eax
if (eax <= 0) { neg eax }
eax = eax / 14h
k = eax * 5
rol key1, k
(il ciclo, per eax volte, deve fare rol 5. Bene 5 * eax e ti dice quanti bit scorre)
k = eax * 4
ror key3, k
if (temp4 <= 0) { neg temp4 } ;obsoleto secondo me
temp4 = temp4 - 0321CCFA
if (temp4 <= 0) { neg temp4 }
eax = key1 * key1 (sarebbe key1 ^ 2)
if (eax <= 0) { neg eax }
ebx = temp4
ebx = ebx - ff fin quando ebx è > ff
quindi ebx = temp4 mod 255
key1 = key1 - ((eax/ebx) * temp4)
eax = key2 * key2 (sarebbe key2 ^ 2)
if (eax <= 0) { neg eax }
ebx = temp4
ebx = ebx - ff fin quando ebx è > ff
quindi ebx = temp4 mod 255
key2 = key2 - ((eax/ebx) * temp4)
eax = key3 * key3 (sarebbe key3 ^ 2)
if (eax <= 0) { neg eax }
ebx = temp4
ebx = ebx - ff fin quando ebx è > ff
quindi ebx = temp4 mod 255
key3 = key3 - ((eax/ebx) * temp4)
eax = key4 * key4 (sarebbe key4 ^ 2)
if (eax <= 0) { neg eax }
ebx = temp4
ebx = ebx - ff fin quando ebx è > ff
quindi ebx = temp4 mod 255
key4 = key4 - ((eax/ebx) * temp4)
key1 == 0C185C58 ?
key2 == 55F2600F ?
key3 == 35CE68B2 ?
key4 == 1F3EECFA ?
<<<<<<<<<< EOF SECOND WINDOW OF NOTEPAD >>>>>>>>>>
Adesso apriamo una terza finestra, ma nella nostra testa!
Ho letto negli altri tutorial che sul forum o in mailing list (non ricordo) si parlava
del corso (non ho potuto seguire nemmeno quello che si diceva) e qualcuno parlava di
collisioni di algoritmo di cifratura.
Non ho fatto nè una ricerca nè so cos'è, ma ho ipotizzato che la mia soluzione di questo
corso è appunto la collisione, ossia trovare una chiave alternativa che rincretinisca
l'algoritmo (potrebbe anche essere la chiave giusta eh!).
Innanzitutto devo fare delle considerazioni su alcune cose:
Quando Què disse nel tutorial che non aveva avuto il tempo per crackare il corso, significa che non ha scelto un seriale per com'è fatto l'algoritmo, ma ha preso un seriale qualsiasi dalla sua testa di Què (eheheh) e glielo ha sparato dentro, ha debuggato i valori finali di un algoritmo preso chissà dove, ha aggiunto i trucchetti ed ha messo il confronto alla fine :)
E poi le istruzioni:
rol eax, 5
ror eax, 4
garantiscono proprio la casualità dei numeri. Perché se fossero state tutte e due "rol" allora si sarebbe ipotizzato una ruotazione diversa di eax bit della key3... ma mettere una a destra e l'altra a manca, vuole proprio qualcosa di casuale. Questo è quello che in 3 giorni di studio dedicate interamente a questo corso (credetemi) mi ha portato a fare. Avevo abbandonato tutto quando nell'intento di trovare info sull'algoritmo ZIP del corso 12 (Què prometto che ci lavoro dopo questo tutorial), mi imbatto in un sito dove spiega la codifica del PGP, quindi fa riferimento anche all'RSA!
Vi riporto le parole (sono in italiano):
Potete leggere il testo qui: http://telemat.det.unifi.it/book/1997/cryptography/cryasy2.htm#rsa
Ebbene quindi si dovrebbe lavorare o con i plain text attack o... con quella famigerata
complessità di calcolo proibitiva... in effetti il metodo che propongo è matematicamente lungo e complesso, ma teoricamente dovrebbe funzionare. Si ma voi direte... quello è l'RSA... che c'entra?
Ve lo faccio vedere subito, ecco quali sono i primi 3 punti (sono 5 in tutto) dell'RSA:
1.Trovare due numeri primi molto grandi P e Q tale che il prodotto o modulo è detto N=PQ;
2.Scegliere E minore di N tale che sia primo con (P-1)(Q-1), il che significa non avere fattori primi in comune. E deve essere dispari. (P-1)(Q-1) non può essere primo perché è pari.
3.Calcolare l'inverso di E, D, tale che DE=1modulo(P-1)(Q-1);
N.B. Il modulo esegue una operazione di divisione intera tra DE e (P-1)(Q-1) con resto 1.
mmmm... non vi torna qualcosa alla mente? Tralasciando i numeri molto grandi e i numeri
primi... temp4 = (key1 + key2 "-1") * (key3 + key4) ???
Modulo di temp4?
Sembra l'RSA leggermente modificato con numeri più piccoli ma con addizioni, sottrazioni etc... e ROL, ROR RAR ZIP etc.!!! Che volevi farci forzare qualcosa di inforzabile? Pure col corso 12... 12 è multiplo di 6, sempre crittografia... vorresti diventare un crittografo??? Mmha... Quecrittografo... non ti ci vedo :P Hihihi si cmq l'algo e' un hash che ho creato sull'impronta dell'RSA e l'ho fatto apposta per avere qualche collisione... NdQue
Comunque al di là di questo forse ho trovato una soluzione a questo corso... iniziamo!
innanzitutto dobbiamo riuscire a neutralizzare (è una figura retorica... già stavano aprendo l'hex editor pronti a noppare!) quei rol e ror... essendo funzioni periodiche, utilizzando un registro a 32bit, il numero neutralizzante è appunto il 32.
Ritorno alle scuole elementari:
MCM tra:
rol 5
ror 4
bit 32
4 = 2^2
5 = 5
32 = 2^5
MCM = 2^5 * 5 = 32 * 5 = 160
Perché questo? Semplice, perché se al momento del ciclo vi è un numero divisibile sia per 4 che per 5 che per 32, allora vediamo le due formule di prima:
k = eax * 5
rol eax, k -> k = 160 * 5 = 800
rol eax, 800 -> 800 / 32 = 25 ehehehe il primo lo abbiamo fregato! :)
eax si fa 25 giretti di bit e poi torna come prima. Vediamo se funge anche col 4?
k = 160 * 4 = 640
rol eax, 640 -> 640 / 32 = 20
wow funge!
ok però c'è un problema, prima dei rol, il temp4 viene diviso per 14h... quindi, temp4 deve avere un numero che divisibile per 14h dia 160 (decimale). Allora:
14h = 20 in decimale
160 * 20 = 3200
temp4 deve essere multiplo di 3200.
3200 = (key1 + key2 - 1) (key3 + key4)
Ok. Ipotizzando che il seriale sia senza simboli, numerico e case sensitive, l'intervallo di valori inseribili e possibili nella textbox sono compresi tra i valori ascii:
48 e 90 (decimali) e sono numeri e lettere maiuscole... poi abbiamo:
da 97 a 122 che sono le lettere minuscole. Vabbè ja inseriamo anche i simboli che stanno al centro, che non sono tanti quindi abbiamo:
tra 48 e 122 che in hex sono: 30 e A7
quindi inserendo i valori tutti caratteri 0, si avrà 30303030, e inserendo tutti i valori z invece A7A7A7A7. Il numero più grande che temp4 potrà assumere è:
temp4 = ((A7A7A7A7 *2)-1) * (A7A7A7A7 *2)
perché faccio questo? Perché voglio trovare un numero compreso nell'intervallo dei caratteri ascii, che se gli sottraiamo -1 e lo eleviamo al quadrato sia divisibile per 3200... semplice algoritmo sfruttando il numero di una sola delle 4 key (una qualsiasi):
A7A7A7A7 -
30303030 =
-----------
77777777
77777777 = 2004318071 in decimale
il numero che devo trovare è la somma di due key "momentaneamente nel calcolo uguali" (dopo chiarisco):
0x30303030 * 2 = 0x60606060
for(i=0x60606060; i< 0x7777777; i++) {
a = (i-1) * i
s = a mod 3200
if s = 0 { inserisci numero in una lista }
}
dovrebbe essere abbastanza veloce e dovremmo ottenere circa un numero per ogni 100 e passa combinazioni.
A questo punto questi numeri sono divisibili sia per 14, per 32, per 4 e per 5 e oltretutto sono compresi in un intervallo ascii alfanumerico (e comprendono anche simboli alcuni :)
At this point (come dice la mia proff d'inglese) ogni numero trovato ha questa filosofia:
(esempio) temp4 = (30303030 + 30303030 - 1) (30303030 + 30303030)
sintetizzando:
j = key1 + key2
temp4 = (j-1) * j
temp4 = j^2 - j
alla fine poi vedremo che se il quadrato di j è:
16, non è detto che la key sia 8 + 8... perché può essere:
1 + 15
15 + 1 (da notare la posizione delle key influisce sul codice)
2 + 14
14 + 2 etc... l'importante è che al momento abbiamo un neutralizzatore della divisione per 14h, e dei ro(l/r).
bene ora passiamo alla parte più rompicoglioni dell'algoritmo:
-------------------------->
temp4 = temp4 - 0321CCFA
-------------------------->
per ogni key la situazione deve essere:
key = key - (key^2/temp4 mod 255) * temp4
if (key = que_code) { giusto } else { vai_a_cagare_tu_e_il_tuo_tute }
bene qui arriviamo ad un equazione dove abbiamo una lista di valori di temp4, quindi per ogni temp4 dobbiamo provare l'equazione:
k = temp4 - 0321CCFA (k è la costante)
a - (a^2/k mod 255) * k = que_code
la sola incognita è che potrebbe essere qualsiasi delle 4 key (a patto
che ad ogni key per cui si fa l'equazione, ci sia il que_code corrispondente).
Non mi dite che non avete capito cos'è il que_code... il que_code è il valore del confronto della parte finale dell'algoritmo:
mov eax, key2
cmp eax, 55F2600F
jne seriale_errato
una volta trovato ad esempio il valore di key1 per quest'equazione, la cosa diventa:
key2 = rad(temp4)+1 - key1
cosa diversa per key3 e 4... una volta trovato key3 la formula diventa:
key4 = rad(temp4) - key3
perché ho messo sopra +1? Perché l'algo del crackme alla somma key1key2 sottrae -1 e poi moltiplica per la somma delle altre due key, quindi temp4 è un quadrato di un numero che è la somma di due key. Il quadrato fa questo:
(key1 + key2 - 1) = (key3 + key4)
key1 + key2 - 1 = j
key3 + key4 = j
temp4 = (key1 + key2 - 1) * (key3 + key4)
quindi temp4 = j * j = j^2
rad(j^2) ci da (key3 + key4)
quindi j = (key3 + key4) formula inversa key4 = j - key3
ok poi se j = (key1 + key2 - 1)
formula inversa:
key2 = j - key1 + 1
Forse questo metodo dovrebbe essere applicato con una variante, perché potrebbe dare disturbo questa istruzione:
temp4 = temp4 - 0321CCFA
dovrebbero essere inseriti in quella lista di prove, anche tutti gli stessi numeri ma con aggiunto il numero 0321CCFA. Allora si che l'algo sarebbe perfetto!
Ah dimenticavo... se dopo trovate le chiavi, esse sono per esempio: ABCD FGHI JKLM NOPQ il seriale sarà: DCBA IHGF MLKJ QPON cioè ogni key al contrario... perché? Studiatevi GetWindowTextA e monitorate i caratteri quando inserite il seriale e passano dalla memoria ai registri- Fiuuuu... finalmente è finito :)
|
Note finali |
Un enorme ringraziamento va a DIO, Gesù, la Madonna, tutti i santi e il cielo in generale (non è una bestemmia idioti! Sono molto religioso!) perché mi accompagnano da quando sono nato e il saluto va anche a tutti i dardi della UIC, e... alla piccola operazione (estrazione di un neo all'addome) che ho subito, che mi ha permesso di stare un bel pò di giorni a casa e quindi mi ha dato modo di scrivere questo tutorial, senza pensare alla scuola!