Zoom Icon

Corso UIC Avanzato 06 Olga

From UIC Archive

Corso UIC Newbies 06 Olga

Contents


Corso UIC Avanzato 06 Olga
Author: Olga
Email: Email
Website: Home page
Date: ?/?/2000 (dd/mm/yyyy)
Level: Damn hard, a lot of experience and luck are required
Language: Italian Flag Italian.gif
Comments:



Tools


Link e Riferimenti

Questo è il Corsi UIC Avanzati n°06 disponibile alla pagina Corsi per Studenti


Introduzione

Scaricate qui il programma (234kb)
Scaricate qui i sorgenti (3.6kb)


Essay

Prima di presentarvi il tutorial vero e proprio mi permetto di pastare una mail che mi spedì Olga il giorno dopo aver esaminato il crackme.

Okkei, è venuto il momento di farvi umiliare......Voi uomini.....duri, rudi, virili.....ehhhhhh.....questo scherzetto non me lo dovevate fare, guardatevi sta mail, nella sua semplicità spiega quasi tutto :).....vabbè non esageriamo, è comunque un ottimo mini essay :)

Tralascio la prima parte perché potrebbe rivelarvi aspetti sconcertanti di questa donna apparentemente seria...ma che in realtà non lo è :)))))))))).....Ecco cosa mi disse:

--- snip ---- snip ----
Il problema relativo al reversing dell'algoritmo nasce dal fatto che i valori finali dei quattro gruppi in cui spezzetti il serial vengono generati sottraendo da ognuno un valore che è ricavato dai gruppi stessi (come avere un'equazione con quattro incognite ed un termine noto).

Il secondo problema è dovuto al fatto che non è possibile neanche il calcolo analitico della funzione inversa, e ciò a causa della funzione 'Mod' usata nel calcolo di ciò che alla fine dovrà finire in EBX e quindi sottratto ad ognuno dei quattro gruppi (due dei quali preventivamente 'elaborati'), operazione che di fatto introduce una quinta incognita; ciò, in pratica, impedisce di usare un sistema di equazioni.
>Lei con un week-end si è accorta del mio MOD e voi ne avete parlato
>solo una volta in ML e poi basta.......il silenzio :)

Quest'ultimo problema sarebbe stato parzialmente ovviabile restringendo opportunamente il campo di calcolo, cosa fattibile se l'andamento dei valori finali forniti dalle funzioni fosse stato in qualche modo convergente.
Ma l'output è periodico, con periodo diverso per ognuno dei quattro valori (ti allego grafico con l'andamento di due dei quattro output forniti dei serial da 0000 0000 0000 0000 a 0000 0000 0000 00re) per cui non è possibile restringere i valori per un semi brute-force.
File:Fx.gif

A questo punto mi sono realmente scocciata, ed ho smesso.

A proposito, chi credevi di prendere per...la fortuna, con la faccenda dell'aiutino? Il fatto che il serial fosse di 16 caratteri è una cosa terribilemnte ovvia; è il resto che non lo è affatto!

Ok, per stasera ho delirato già abbastanza; ti saluto e vado in palestra.

Alga

Hihihihhi.....Tanto per farvi rendere conto di che pasta è fatta....Cmq per chi non fosse riuscito a visitare il sito prima della pubblicazione dell'intervista sulla repubblica comunico che avevo creato una mini-soluzione di Olga prendendola dalla sua mail che restava cmq ottima....Poi però ha deciso di farsi avanti....Godetevi questo concentrato di conoscenza :)


Ecco il listato della parte relativa all'algoritmo, commentato. Qualche considerazione alla fine. 00401256 6A11 push 00000011 17 caratteri max da copiare

                                                (un 'aiutino', eh?)     

00401258 68CC204000 push 004020CC in un buffer che inizia qui 0040125D FF3518204000 push dword ptr [00402018]

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

                                 |

00401263 E85D020000 Call 004014C5 00401268 A1CC204000 mov eax, dword ptr [004020CC] primo gruppo in EAX 0040126D 69C078265793 imul eax, 93572678 Que, sei un IMBROGLIONE! 00401273 8B1DD0204000 mov ebx, dword ptr [004020D0] secondo gruppo 00401279 69DB05735426 imul ebx, 26547305 e lo sei anche qui! 0040127F 8B0DD4204000 mov ecx, dword ptr [004020D4] terzo gruppo 00401285 69C914985637 imul ecx, 37569814 ormai sei smascherato 0040128B 8B15D8204000 mov edx, dword ptr [004020D8] quarto gruppo 00401291 69D215376589 imul edx, 89653715 bah, lasciamo perdere... 00401297 03C3 add eax, ebx ...tutti questi... 00401299 03C1 add eax, ecx ...vergognosi trucchi... 0040129B 03C2 add eax, edx ...che giungono... 0040129D 50 push eax 0040129E A35D144000 mov dword ptr [0040145D], eax ...fin qui! 004012A3 33C0 xor eax, eax OK, riprendiamo con le cose serie 004012A5 A1CC204000 mov eax, dword ptr [004020CC] somma dei codici... 004012AA 0305D0204000 add eax, dword ptr [004020D0] ASCII I e II gruppo 004012B0 A361144000 mov dword ptr [00401461], eax parziale 1 004012B5 A1D4204000 mov eax, dword ptr [004020D4] somma dei codici... 004012BA 0305D8204000 add eax, dword ptr [004020D8] ASCII III e IV gruppo 004012C0 A375144000 mov dword ptr [00401475], eax parziale 2 004012C5 A161144000 mov eax, dword ptr [00401461] 004012CA 48 dec eax (parziale 1)-1 004012CB 8B1D75144000 mov ebx, dword ptr [00401475] parziale 2 004012D1 FF0D75144000 dec dword ptr [00401475] insisti, eh? 004012D7 0FAFC3 imul eax, ebx (GrI+GrII-1)*(GrIII+GrIV)... 004012DA A379144000 mov dword ptr [00401479], eax ...salvato in 401479 004012DF E805000000 call 004012E9 OK, proseguiamo...

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

                                 |

004012E4 E8AC010000 Call 00401495 ...prima di terminare

* Referenced by a CALL at Address: |004012DF | 004012E9 83F8FF cmp eax, FFFFFFFF rende 'unsigned'... 004012EC 7F06 jg 004012F4 ...il valore salvato... 004012EE 90 nop 004012EF 90 nop 004012F0 90 nop 004012F1 90 nop 004012F2 F7D8 neg eax ...in 401479 prima di...

* Referenced by a (U)nconditional or (C)onditional Jump at Address: |004012EC(C) | 004012F4 B914000000 mov ecx, 00000014 004012F9 99 cdq 004012FA F7F9 idiv ecx ...dividerlo per 20d (la parte intera del ''' risultato resta in EAX)
A questo punto EAX contiene int(((GrI+GrII-1)*(GrIII+GrIV))/20), ed è utilizzato come CONTATORE
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |0040131F(C) |

INIZIA LOOP

004012FC 8B1DCC204000 mov ebx, dword ptr [004020CC] soliti... 00401302 0FAFCB imul ecx, ebx ...luridi... 00401305 8B0DD4204000 mov ecx, dword ptr [004020D4] ...imbrogli... 0040130B 0FAFC9 imul ecx, ecx ...di Quequero 0040130E 48 dec eax decrementa il contatore 0040130F C105CC20400005 rol dword ptr [004020CC], 05 rotaz. a sn I gruppo 00401316 C10DD420400004 ror dword ptr [004020D4], 04 rotaz. a dx III gruppo 0040131D 85C0 test eax, eax 0040131F 75DB jne 004012FC chiude il loop 00401321 833D79144000FF cmp dword ptr [00401479], FFFFFFFF riconsideriamo... 00401328 7F0A jg 00401334 ...(GrI+GrII-1)*(GrIII+Gr4)... 0040132A 90 nop ...per renderlo 'unsigned'... 0040132B 90 nop ...prima di sottrarre... 0040132C 90 nop 0040132D 90 nop 0040132E F71D79144000 neg dword ptr [00401479]

* Referenced by a (U)nconditional or (C)onditional Jump at Address: |00401328(C) | 00401334 812D79144000FACC2103 sub dword ptr [00401479], 0321CCFA ...QUESTO 0040133E 833D79144000FF cmp dword ptr [00401479], FFFFFFFF e ancora 00401345 7F0A jg 00401351 00401347 90 nop 00401348 90 nop 00401349 90 nop 0040134A 90 nop 0040134B F71D79144000 neg dword ptr [00401479] A questo punto in 401479 è contenuto il valore che verrà definitivamente utilizzato nel resto dell'algoritmo e che è denominato 'Kpr' nel programma di TEST. Solo da esso dipende la variabilità dei valori finali delle funzioni relative a tutti e quattro i gruppi al variare anche di un solo carattere in un solo gruppo
* Referenced by a (U)nconditional or (C)onditional Jump at Address: |00401345(C)| 00401351 E801000000 call 00401357 OK, andiamo avanti 00401356 C3 ret


* Referenced by a CALL at Address: |00401351 | 00401357 A1CC204000 mov eax, dword ptr [004020CC] 0040135C E899000000 call 004013FA numeratore II termine equazione gruppo1 00401361 E873000000 call 004013D9 denominatore II termine equaz. gruppo1 00401366 291DCC204000 sub dword ptr [004020CC], ebx I termine - II termine 0040136C A1CC204000 mov eax, dword ptr [004020CC] ehi Que, ma non ti... 00401371 A365144000 mov dword ptr [00401465], eax ...togli mai il vizio? 00401376 A1D0204000 mov eax, dword ptr [004020D0] 0040137B E87A000000 call 004013FA numeratore II termine equazione gruppo2 00401380 E854000000 call 004013D9 denominatore II termine equaz. gruppo2 00401385 291DD0204000 sub dword ptr [004020D0], ebx I termine - II termine 0040138B A1D0204000 mov eax, dword ptr [004020D0] 00401390 A369144000 mov dword ptr [00401469], eax 00401395 A1D4204000 mov eax, dword ptr [004020D4] 0040139A E85B000000 call 004013FA numeratore II termine equazione gruppo3 0040139F E835000000 call 004013D9 denominatore II termine equaz. gruppo3 004013A4 291DD4204000 sub dword ptr [004020D4], ebx I termine - II termine 004013AA A1D4204000 mov eax, dword ptr [004020D4] 004013AF A36D144000 mov dword ptr [0040146D], eax 004013B4 A1D8204000 mov eax, dword ptr [004020D8] 004013B9 E83C000000 call 004013FA numeratore II termine equazione gruppo4 004013BE E816000000 call 004013D9 denominatore II termine equaz. gruppo4 004013C3 291DD8204000 sub dword ptr [004020D8], ebx I termine - II termine 004013C9 A1D8204000 mov eax, dword ptr [004020D8] 004013CE A371144000 mov dword ptr [00401471], eax 004013D3 E831000000 call 00401409 oh, finalmente! 004013D8 C3 ret


CALCOLO DEL DENOMINATORE DEL SECONDO TERMINE

* Referenced by a CALL at Addresses: |00401361 , 00401380 , 0040139F , 004013BE | 004013D9 8B1D79144000 mov ebx, dword ptr [00401479] Kpr

* Referenced by a (U)nconditional or (C)onditional Jump at Address: |004013EB(C) |

INIZIA LOOP PER CALCOLO Mod(Kpr/255d)

004013DF 81EBFF000000 sub ebx, 000000FF 004013E5 81FBFF000000 cmp ebx, 000000FF 004013EB 7FF2 jg 004013DF chiude loop 004013ED 99 cdq 004013EE F7FB idiv ebx Gruppo/Mod(Kpr/255d) 004013F0 0FAF0579144000 imul eax, dword ptr [00401479] e moltiplicato per Kpr 004013F7 8BD8 mov ebx, eax risultato in EBX 004013F9 C3 ret


CALCOLO DEL DENOMINATORE DEL SECONDO TERMINE

* Referenced by a CALL at Addresses: |0040135C , :0040137B , :0040139A , :004013B9 | 004013FA 0FAFC0 imul eax, eax Gruppo al quadrato 004013FD 83F8FF cmp eax, FFFFFFFF vedi prima 00401400 7F06 jg 00401408 00401402 90 nop 00401403 90 nop 00401404 90 nop 00401405 90 nop 00401406 F7D8 neg eax

* Referenced by a (U)nconditional or (C)onditional Jump at Address: |00401400(C) | 00401408 C3 ret

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

A QUESTO PUNTO, NELLE LOCAZIONI (DWORD) CHE CONTENEVANO I QUATTRO GRUPPI SI HA INVECE IL RISULTATO DEL CALCOLO, CHE VIENE CONFRONTATO CON IL TERMINE NOTO

00401409 A1CC204000 mov eax, dword ptr [004020CC] 0040140E 3D585C180C cmp eax, 0C185C58 I termine noto=202923096d 00401413 7568 jne 0040147D errato! :) 00401415 90 nop 00401416 90 nop 00401417 90 nop 00401418 90 nop 00401419 A1D0204000 mov eax, dword ptr [004020D0] 0040141E 3D0F60F255 cmp eax, 55F2600F II termine noto=1441947663d 00401423 7558 jne 0040147D errato! :) 00401425 90 nop 00401426 90 nop 00401427 90 nop 00401428 90 nop 00401429 A1D4204000 mov eax, dword ptr [004020D4] 0040142E 3DB268CE35 cmp eax, 35CE68B2 III termine noto=902719666d 00401433 7548 jne 0040147D errato! :) 00401435 90 nop 00401436 90 nop 00401437 90 nop 00401438 90 nop 00401439 A1D8204000 mov eax, dword ptr [004020D8] 0040143E 3DFAEC3E1F cmp eax, 1F3EECFA IV termine noto=524217594d 00401443 7538 jne 0040147D errato! :) 00401445 90 nop OK, tutti esatti 00401446 90 nop 00401447 90 nop 00401448 90 nop 00401449 6A20 push 00000020

* Possible StringData Ref from Data Obj ->"Bravo!" Come può essere (facilmente?) verificato seguendo l'algoritmo passo per passo, il serial viene suddiviso in quattro gruppi da quattro caratteri, ognuno dei quali deve soddisfare la seguente equazione:

Grn - ( ( Grn² / Mod(Kpr / 255) ) * Kpr ) + kn = 0

con n che varia da uno a quattro. kn sono le quattro costanti finali. Grn vale invece:

  • i quattro codici ASCII dei gruppi corrispondenti per n = 2 e 4
  • I quattro codici ASCII del gruppo I ruotati a sinistra di cinque posizioni per Mod(int(Knum/20)/160) volte per n = 1
  • I quattro codici ASCII del gruppo III ruotati a destra di quattro posizioni per Mod(int(Knum/20)/8) volte per n = 3

dove Knum vale (GrI+GrII-1)*(GrIII+GrIV).

In realtà nel crackme la rotazione viene eseguita per Knum/20 volte (ed infatti il programma impiega un'eternità per la verifica del serial), ma il metodo dato qui è molto più breve (è quello usato nel programma di TEST per eseguire il calcolo - se non l'avessi fatto così, il programma avrebbe impiegato DUE eternità per calcolare 50 serial di seguito, ed io non so a quanto tempo corrispondano esattamente due eternità :); spiegare in dettaglio perché la formula utilizzata sia equivalente suonerebbe come un insulto all'intelligenza di chi legge, quindi non lo farò :).

Allora, è possibile percorrere l'algoritmo in senso inverso? Ed è possibile ricavare per via analitica il numero di serie?
Bene, i due problemi (e le loro risoluzioni) sono, da un punto di vista matematico, equivalenti.

Perchè un algoritmo possa venire percorso in senso inverso (la sua trasposizione Assembly, intendo - il discorso non è valido per il codice sorgente scritto in un linguaggio ad alto livello), ogni passo deve essere riconducibile ad un'equazione di primo grado ad un'incognita - il valore da ricavare per risalire al passo immediatamente precedente. Il calcolo eseguito nella routine che inizia in 4013D9 preclude questa possibilità, poiché viene effettuato servendosi di tutti e quattro i gruppi di numeri del serial (e cioè di quattro incognite).

La risoluzione analitica è possibile, essendo risaliti alle equazioni, se le equazioni possono comporre un sistema, e se il numero di equazioni che compongono il sistema è uguale al numero delle incognite (direbbe Monsieur De Lapalisse, noto per affermare le cose più ovvie).
Nel nostro caso abbiamo quattro equazioni e quattro incognite; il problema (oltre alla relativa complessità che si incontrerebbe nel risolvere il sistema per sostituzione) risiede nella presanza della funzione Mod.
Essa infatti non è invertibile (non esiste corrispondenza biunivoca tra i singoli elementi dell'insieme che costituiscono i valori di ingresso e quelli che costituiscono i valori in uscita).
Si noti, tuttavia, che Mod(Kpr/255) è equivalente a Kpr-n*255 (anzi, questo è proprio il metodo usato dall'algoritmo per il calcolo della funzione all'interno del programma).
Ciò introduce, di fatto, una quinta incognita, che rende impossibile la soluzione analitica.

Una soluzione alternativa potrebbe essere quella di un brute force su n, calcolando sequenzialmente il sistema per diversi valori di n
Per restringere il range dei valori di n su cui effettuare il brute force si potrebbe verificare quali siano i valori minimi e massimi che Kpr può assumere, ed utilizzare i valori di n che non rendano negativo il denominatore(questo è il motivo della presenza, nel programmino di TEST, della memorizzazione dei valori minimo e massimo).

Sarebbe meglio memorizzare i valori minimo e massimo assunti dal denominatore per vari valori del serial, ma questo non è stato implementato.

Anche perché, arrivata a questo punto, mi sono accorta del fatto che non si vinceva niente, ed ho mollato.

Ciao a tutti
Alga


Disclaimer

I documenti qui pubblicati sono da considerarsi pubblici e liberamente distribuibili, a patto che se ne citi la fonte di provenienza. Tutti i documenti presenti su queste pagine sono stati scritti esclusivamente a scopo di ricerca, nessuna di queste analisi è stata fatta per fini commerciali, o dietro alcun tipo di compenso. I documenti pubblicati presentano delle analisi puramente teoriche della struttura di un programma, in nessun caso il software è stato realmente disassemblato o modificato; ogni corrispondenza presente tra i documenti pubblicati e le istruzioni del software oggetto dell'analisi, è da ritenersi puramente casuale. Tutti i documenti vengono inviati in forma anonima ed automaticamente pubblicati, i diritti di tali opere appartengono esclusivamente al firmatario del documento (se presente), in nessun caso il gestore di questo sito, o del server su cui risiede, può essere ritenuto responsabile dei contenuti qui presenti, oltretutto il gestore del sito non è in grado di risalire all'identità del mittente dei documenti. Tutti i documenti ed i file di questo sito non presentano alcun tipo di garanzia, pertanto ne è sconsigliata a tutti la lettura o l'esecuzione, lo staff non si assume alcuna responsabilità per quanto riguarda l'uso improprio di tali documenti e/o file, è doveroso aggiungere che ogni riferimento a fatti cose o persone è da considerarsi PURAMENTE casuale. Tutti coloro che potrebbero ritenersi moralmente offesi dai contenuti di queste pagine, sono tenuti ad uscire immediatamente da questo sito.

Vogliamo inoltre ricordare che il Reverse Engineering è uno strumento tecnologico di grande potenza ed importanza, senza di esso non sarebbe possibile creare antivirus, scoprire funzioni malevole e non dichiarate all'interno di un programma di pubblico utilizzo. Non sarebbe possibile scoprire, in assenza di un sistema sicuro per il controllo dell'integrità, se il "tal" programma è realmente quello che l'utente ha scelto di installare ed eseguire, né sarebbe possibile continuare lo sviluppo di quei programmi (o l'utilizzo di quelle periferiche) ritenuti obsoleti e non più supportati dalle fonti ufficiali.