|
Secondo corso UIC Qualche trucco per la soluzione ;)
|
|
Data
|
by
-=Götterdämerung=-
|
|
|
22/08/2005
|
UIC's
Home Page
|
Published by Quequero
|
|
|
Grazie gotter, ottimo tutorial!!
|
|
|
....
|
- E-mail:
die.gotterdamerung@gmail.it
- Gotterdamerung su irc.azzurra.org: #crack-it
|
....
|
|
Difficoltā
|
(X)NewBies ( )Intermedio ( )Avanzato ( )Master
|
|
-
- Eccomi finalmente ad affrontare i corsi per studenti, e sono già al secondo!! :P
- Per questo tutorial ci servirà un debugger qualsiasi per poter vedere il codice, ma molto più importante sarà avere un pizzico di astuzia e la conoscenza dello ZEN.
Dimenticavo... un cervello funzionante è indispensabile! (Copyright degli aventi diritto :P)
- La pagina dei "Corsi per Studenti UIC"
- Questo corso
è stato già strarisolto da un sacco di studenti, ma dopo averlo
risolto per conto mio e aver controllato le soluzioni degli altri mi sono
accorto che nessuno aveva detto una cosa fondamentale, inoltre ho trovato
un piccolo trick per la registrazione; vado quindi a esporre questi due argomenti
invece di risolvere normalmente il corso. (Que, scusa se mi faccio i caXXi
miei :D )
Per affrontare questo tutorial è necessario leggersi le soluzioni precedenti,
oppure aver già risolto il corso! Non pensate male, non sono uno sfaticato,
ma penso che queste riflessioni dopo un lungo tutorial passerebbero inosservate.
-- Argomento 1: La lunghezza del nome --
Non vi devo fare presente che anche su questo
argomento sono state spese diverse parole, però si è sempre
parlato della lunghezza _massima_ del nome, mai di quella minima, che, secondo
me, è invece molto importante, e spero anche per voi dopo aver letto
quello che vi vado a dire :)
Abbiamo notato che grazie ad un controllino il bravo Que ci presenta una finestrella
contenente un errore se non viene inserito nessun username... ma perché?
Ebbene, come avete notato analizzando il codice (se non lo avete fatto tornate
alle soluzioni precedenti!), esiste sì un limite massimo per il nome,
pari a 4 caratteri, o almeno è quello su cui viene calcolato il seriale
(poiché una Dword contiene 4 caratteri (ripeto, se non capite -> soluzioni
già fatte!)) ma oltre al controllo sul nome vuoto, non esiste un controllo
sulla lunghezza minima del nome!
Grazie a quelle due righe su cui il Que ha ripreso tanti studenti: mov edi,ecx;
mul edi, durante la prima iterazione del ciclo, ovvero quando ecx è
nullo, abbiamo già visto che la prima lettera genererà sempre
lo stesso corrispondente nel seriale, ovvero 9, quindi, dato che il seriale
è lungo esattamente quanto il nome, QUALSIASI nome di una sola lettera
(ovvero qualsiasi lettera o carattere che vi passi per la tastiera) e il numero
9 costituiscono una coppia nome/seriale validi!!!
Abbiamo quindi un keymaker alternativo:
-
-
-
void main (void)
{
printf("Inserisci un nome di una sola
lettera: ");
getchar();
printf("Il seriale corrispondente e':
9\n :P :P :P");
}
|
Questo conclude l'argomento; ovviamente l'importante
non era trovare un nome e un seriale di un solo carattere, ma capire che se
il seriale è ricavato dal nome, più corto è il nome e meno
calcoli ci saranno fatti sopra (a volte) rendendo in questo modo molto più
semplice lo studio di quello che accade durante la generazione del seriale.
- -- Argomento 2: L'algoritmo di crittazione
--
Stavolta l'argomento è più serio...
non è stato fatto notare molto (anche se qualcuno lo ha detto, scusate,
ma non ricordo chi...) che il programma prende come carattere di fine stringa
un byte posto a 00; questo è quello che provoca problemi se inserite
un nome o un seriale troppo lungo, oppure se dopo uno lungo ne scrivete uno
più corto (ci avevate mai provato?) perché il programma non
ri-inizializza la zona di memoria dove scrive questi dati e quindi se trova
altri byte, anche dopo quelli da noi immessi, che siano diversi da 00 continua
nella sua analisi per la generazione del seriale.
Ma non è questo il problema che voglio trattare ora, magari guardatevelo
con Olly, bensì quello inverso! Nella generazione del seriale infatti
è presente una istruzione SHL 2 e una ROR 4, ma mentre la seconda istruzione
non provoca perdita di bit, perché quelli spostati vengono riportati
in cima, la prima CANCELLA i due bit più significativi del byte ottenuto
finora, operazione che può portare all'azzeramento del byte che il
programma sta 'crittando'.
Come 'e allora'?? Se il byte si azzera, al ciclo successivo, quando il seriale
viene fatto rientrare tra 66h e 30h, trovando un byte azzerato prima della
fine della stringa il ciclo terminerà prima di aver generato tutto
il seriale, quindi fornendo un seriale corretto solo parzialmente (dal punto
di vista della logica del programmatore, vero Que LOL
NdQ ;)), ma funzionante!
Abbiamo detto e ridetto che il primo carattere del serial è e sempre
sarà 9, quindi questa eccezione nel nostro caso può essere generata
solo nei caratteri successivi al primo.
Prendendo in considerazione solo i tre cicli successivi al primo, ripassiamo
cosa viene fatto per crittare il carattere da noi immesso:
-
-
-
II ciclo III
ciclo IV ciclo
-------------------------------------
xor 1 xor
2 xor 3
mul 1 mul
2 mul 3
-25 -25 -25
+1 +2 +3
xor 45 xor
D1 xor FF
+45 +D1 +FF
shl 2 shl
2 shl 2
ror 4 ror
4 ror 4
-5 -5 -5
|
Siccome vengono spostati a sinistra gli ultimi 2 bit, avremo che 4 sono le possibili combinazioni di avere un byte finale nullo, ovvero che prima dello SHL ci sia uno di questi byte: 00010100 (14h); 01010100 (54h); 10010100 (94h); 11010100 (D4h), questi perché il ROR 4 è in particolare scambia i primi 4 bit con gli altri 4, quindi dopo lo SHL dei 4 byte qui sopra otterremo sempre 50h e dopo il ROR 4 questo diventerà 05h che grazie all'ultima sottrazione diventerà un bello 00.
Per sapere quali caratteri inserire nel nome per ottenere uno di questi byte basta fare le operazioni inverse rispetto all'algoritmo partendo dall'operazione subito prima di SHL 2, ovvero dove conosciamo quale byte usare, quindi a questo punto facciamo un bel tabellone e vediamo cosa succede facendo tornare questi quattro byte in cima alla catena di crittaggio :)
-
-
==============================================
| II ciclo | 14h | 54h | 94h | D4h |
|------------+-------+-------+-------+-------|
| -45 | CFh | 0Fh | 4Fh | 8Fh |
| xor 45 | 8Ah | 4Ah | 0Ah | CAh |
| -1 | 89h | 49h | 09h | C9h |
| +25 | AEh | 6Eh | 2Eh | EEh |
| div 1 | AEh | 6Eh | 2Eh | EEh |
| xor 1 | AFh | 6Fh | 2Fh | EFh |
|------------+-------+-------+-------+-------|
| ASCII | ? | 'o' | '/' | ? |
==============================================
==============================================
| III ciclo | 14h | 54h | 94h | D4h |
|------------+-------+-------+-------+-------|
| -D1 | 43h | 83h | C3h | 03h |
| xor D1 | 92h | 52h | 12h | D2h |
| -2 | 90h | 50h | 10h | D0h |
| +25 | B5h | 75h | 35h | F5h |
| div 2 | imp | imp | imp | imp |
| xor 2 | --- | --- | --- | --- |
|------------+-------+-------+-------+-------|
| ASCII | --- | --- | --- | --- |
==============================================
==============================================
| IV ciclo | 14h | 54h | 94h | D4h |
|------------+-------+-------+-------+-------|
| -FF | 15h | 55h | 95h | D5h |
| xor FF | EAh | AAh | 6Ah | 2Ah |
| -3 | E7h | A7h | 67h | 27h |
| +25 | 0Ch | 1Ch | 8Ch | 4Ch |
| div 3 | 04h | imp | imp | imp |
| xor 3 | 07h | --- | --- | --- |
|------------+-------+-------+-------+-------|
| ASCII | ? | --- | --- | --- |
==============================================
|
OK, siamo tornati in cima e possiamo vedere che nel secondo ciclo siamo riusciti a risalire a tutti e quattro i byte, anche
se solamente due sono inseribili da tastiera (veramente grazie alla tabella ASCII potremmo inserire anche gli altri due,
ma quando il prog fa il GetWindowTextA se controllate il buffer noterete che vengono presi dei valori diversi; immagino che
dipenda dall'encoding del testo, ma non ne sono assolutamente sicuro), quindi inserendo in seconda posizione una 'o' o un '/'
il ciclo di generazione del seriale si fermerà dopo aver generato solo il primo carattere, che abbiamo detto essere 9.
Nel secondo ciclo troviamo un div 2, che ci dà delle rotture di scatole, infatti i risultati non sono propriamente
impossibili, ma danno un resto!
Questi risultati non possono essere accettati perché in realtà dobbiamo considerare che la routine di crittazione
esegue un'operazione MUL 2 dopo la quale qualsiasi byte sarà pari... e come notate nessun byte prima del DIV 2 è pari...
Nel terzo ciclo la stessa solfa: possiamo risalire ad uno, che però non è digitabile da tastiera e gli altri tre
danno dei resti nella divisione, quindi non sono accettabili.
Eccoci, ho finito di esporre
quello che ho trovato di particolare in questo programmino... adesso sotto con
il prossimo corso!
See ya on the last days...
-=Götterdämerung=-
Vorrei ringraziare veramente TANTISSIMO Quequero, ovviamente, per tutta la UIC e quello che
ho imparato grazie ad essa, e AndreaGeddon, per i suoi crackme e perché risponde alle mie mail da niubbo.
Un saluto e un ringraziamento anche a tutto il chan #crack-it con cui riesco ad avere relazioni (solo verbali!).
Vorrei ricordare che il software va comprato
e non rubato, se volete registrare questo programma rivolgetevi all'iguana di Que.
Non mi ritengo responsabile per eventuali problemi mentali dovuti all'uso improprio
di questo tutorial in combinazione con il prog di Que. Questo documento è stato
scritto per farvi capire che anche se non sembra tutto è importante e lo ZEN
aiuta in ogni frangente della vita.
Reversiamo al solo scopo informativo e per
migliorare la nostra conoscenza del linguaggio Assembly.