Terzo Corso U.I.C. |
|
|
10/10/99 |
by Steda |
|
Published by Quequero |
||
Davvero i miei migliori complimenti per Steda che ha fatto un tutorial impeccabile con tanto di key generator |
||
| UIC's form |
|
UIC's form |
Difficoltà |
( )NewBies (X)Intermedio ( )Avanzato ( )Master |
Il programma è scritto da Quequero per la terza lezione della U.I.C.
Il programma è scritto con codice auto-modificante; in questo tut ci accingeremo a crackarlo, a trovare una pass. valida per il nostro nick, creeremo un keygen, e cercheremo di capire al meglio il metodo con cui si auto-modifica.
Terza prova U.I.C.
Introduzione |
Un saluto a tutti! Rieccomi con questo mio tut fra di voi.
Devo a tutti voi le mie scuse per non aver partecipato fin'ora alla mailing-list, ma la seguo costantemente e entro poco parteciperò anch'io. Ciauzzz a tutti ed Happy Cracking.
Tools usati |
SoftIce 324
URL o FTP del programma |
Notizie sul programma |
Essay |
Inizio questo mio tutorial col dirvi che sono entrato nel programma utilizzando un bpx sull'handle della text box.
In SoftIce:
task ;per vedere i processi residenti in memoria
hwnd taskname(tre) ;per vedere gli handle del programma
bmsg handle(della text box) wm_gettext: bmsg 0C88 wm_gettext
Gli handle cambiano ogni volta che si riavvia il programma, perciò dovrete trovare il vostro con il metodo sopra descritto e non utilizzare 0C88.
Alla pressione del tasto "Register" si entra in Soft Ice... ci troviamo in USER... F12 fino a Kernel.Alloc e state certi che al prossimo F12 sarete proprio all'interno del programma da crackare.
:00401583 mov al, byte ptr [ecx+0040209B] ;porta il nick in al
carattere per carattere
:00401589 mov edi, 0000000B ; muove "B" in edi
:0040158E cdq ;* Converte una DoubleWord in una QuadWord per
preparare una divisione
:0040158F idiv edi ;** Alla fine del listato troverai una
spiegazione su questa funzione
:00401591 add eax, edx ;somma eax con edx, il risultato è posto in
eax
:00401593 shl eax, 1 ;shifta un bit a sinistra
:00401595 mov dl, al ;copia al in dl
:00401597 call 0040160C
:0040159C xor eax, eax ;azzera eax
:0040159E mov al, dl ;copia dl in al
:004015A0 xor al, 81 ;xora al con 81
:004015A2 xor al, 40 ;xora al con 40
:004015A4 mov byte ptr [ecx+004020C7], al ;salva il carattere
modificato in memoria
:004015AA inc ecx ;incrementa ecx per proseguire la crittazione con
il prossimo carattere
:004015AB cmp ecx, 00000004 ;controlla a che punto è la crittazione
:004015AE jnz 0040137E ;Torna all'inizio della procedura; se sono
stati già processati i primi quattro caratteri ritorna all'inizio.
Call 40160C
:0040160C cmp dl, 7A ;confronta il carattere crittato con 7A
:0040160F jg 00401617 ;salta se il valore è troppo elevato
:00401611 cmp dl, 30 ;confronta il carattere con 30
:00401614 jl 00401621 ;salta se il valore è troppo basso
:00401616 ret ;torna all'istruzione successiva alla call
:00401617 sub dl, 0A ;sottrae "A"(10) a dl
:0040161A cmp dl, 7A ;confronta di nuovo il valore
:0040161D jg 00401617 ;salta se è ancora troppo elevato
:0040161F jmp 00401616
:00401621 add dl, 0A ;aggiunge "A"(10) a dl
:00401624 cmp dl, 30 ;confronta di nuovo il valore
:00401627 jl 00401621 ;salta se è ancora troppo basso
:00401629 jmp 00401616
Questi sono i calcoli che il programma effettua sul nick per farlo
rimanere in un range di valori accettabili: Questa volta Quequero ha fatto in modo che la
pass generata sia costituita solo da numeri.
:00401516 mov ecx, 00000004 ;porta 4 in ecx
:0040151B xor eax, eax ;azzera eax
:0040151D mov al, byte ptr [ecx+0040209B] ;porta il nick in al
carattere per carattere, iniziando dal quinto
:00401523 cmp ecx, dword ptr [0040210F] ;Questa locazione contiene
la lunghezza del nick+1
:00401529 jz 0040131C ;salta se il cmp è affermativo
:0040152B mov edi, 00000008 ;muove 8 in edi
:00401530 cdq ;* Converte una DoubleWord in una QuadWord per
preparare una divisione
:00401531 idiv edi ;** Alla fine del listato troverai una
spiegazione su questa funzione
:00401533 add al, dl ;somma al con dl, il risultato è posto in al
:00401535 shl al, 03 ;shifta tre bit a sinistra
:00401538 ror al, 1 ;ruota 1 bit a destra
:0040153A add al, 06 ;aggiunge 6 ad al
:0040153C shl al, 1 ;shifta un bit a sinistra
:0040153E xor al, byte ptr [0040210F] ;xora al con la lunghezza del
nick+1
:00401544 mov edi, 00000003 ;Edi=3
:00401549 cdq ;* Converte una DoubleWord in una QuadWord per
preparare una divisione
:0040154A idiv edi ;** Alla fine del listato troverai una
spiegazione su questa funzione
:0040154C add al, dl ;somma al con dl, il risultato è posto in al
:0040154E mov dl, al ;copia al in dl: dl=al
:00401550 call 0040160C ;call già trattata, vedi sopra
:00401555 mov al, dl ;copia dl in al: al=dl
:00401557 xor al, 82 ;xora al con 82
:00401559 shl al, 02 ;shifta al di due bit a sinistra
:0040155C ror al, 02 ;ruota al di due bit a destra
:0040155F mov byte ptr [ecx+004020C7], al ;salva il carattere
modificato in memoria
:00401565 xor eax, eax ;cancella eax
:00401567 inc ecx ;incrementa ecx
:00401568 cmp ecx, 00000008 ;confronta ecx con 8
:0040156B jnz 0040151B ;torna all'inizio della procedura(il
precedente cmp con 8 blocca la lunghezza del nick a 8 caratteri; se il nick è più lungo,
i primi 8 caratteri vengono xorati con la sua reale lunghezza).
Nick <8 salta con il jmp condizionale in 401529
Nick >8 esegue un paio di nop ed arriva allo stesso punto del jmp condizionale di 401529
Eccoci arrivati finalmente alla nostra pass.
:004014E7 xor eax, eax ;azzera eax
:004014E9 mov al, byte ptr [ecx+004020AF] ;porta la pass in al
carattere per carattere
:004014EF xor al, 81 ;la xora con 81
:004014F1 xor al, 40 ;viene xorrata ancora con 40
:004014F3 mov bl, byte ptr [ecx+004020C7] ;porta il nick crittato in
bl carattere per carattere
:004014F9 cmp al, bl ;confronta i due valori
:004014FB jnz 00401170 ;salta se i valori sono diversi (pass errata)
:00401501 inc ecx ;incrementa ecx
:00401502 cmp ecx, 00000004 ;controlla a che punto è la verifica
della pass con il nick
:00401505 jne 004014E7 ;Torna all'inizio della procedura; continua
se sono stati già controllati i primi quattro caratteri della pass.
:004015C3 mov ecx, 00000004 ;muove 4 in ecx
:004015C8 xor eax, eax ;azzera eax
:004015CA mov al, byte ptr [ecx+004020AF] ;porta la pass in al
carattere per carattere, iniziando dal quinto
:004015D0 cmp ecx, dword ptr [0040210F] ;confronta ecx con la
lunghezza del nick+1
:004015D6 jz 004013A5 ;SALTA ALLA MESSAGE BOX DI COMPLIMENTI SE HA
FINITO IL CHECK
:004015D8 xor al, 82 ;xora la pass con 82
:004015DA shl al, 02 ;la shifta di due bit a sinistra
:004015DD ror al, 02 ;la ruota di due bit a destra
:004015E0 mov bl, byte ptr [ecx+004020C7] ;porta il nick crittato in
bl carattere per carattere, iniziando dal quinto
:004015E6 cmp al, bl ;confronta i due valori
:004015E8 jnz 00401170 ;salta se i valori sono diversi(pass errata)
:004015EE inc ecx ;incrementa ecx
:004015EF cmp ecx, 00000008 ;confronta ecx con 8
:004015F2 jnz 004015C8 ;torna all'inizio della procedura(il
precedente cmp con 8 blocca la lunghezza del nick a 8 caratteri; se il nick è più lungo,
i primi 8 caratteri vengono xorrati con la sua reale lunghezza).
Nick <8 salta con il jmp condizionale in 4015D0
Nick >8 esegue un paio di nop ed arriva allo stesso punto del jmp condizionale di 4015D0
=========================================================================================
*CDQ - Converet una DoubleWord in una QuadWord (386+ only)
Uso: CDQ
Non apporta nessuna modifica ai flag.
Convere la DoubleWord che si trova in EAX, in una QuadWord in EDX:EAX
Nel programma in questione azzera EDX (CDQ=XOR EDX, EDX)
=========================================================================================
**DIV e IDIV:
Per la divisione esistono 2 istruzioni una per i numeri senza segno (DIV) e una per
quelli col segno (IDIV).
Entrambe ritornano il quoziente e il resto, e la loro sintassi è:
DIV < registro|memoria >
IDIV < registro|memoria >
Per effettuare una divisione di un numero a 16bit per uno di 8bit si deve mettere il numero da dividere in AX e specificare il divisore in un altro registro.
Il risultato della divisione sarà in AL e il resto in AH
Attenzione: Il dividendo viene perso.
Se invece vogliamo dividere un numero a 32 bit per uno di 16 si deve mettere il dividendo in DX:AX, specificare il divisore in un registro a 16 bit (che non sia AX o DX) ed effettuare la divisione.
Avremo il risultato in AX e il resto in DX.
Nel programma di Quequero avviene proprio questo: Il dividendo è posto in DX:AX(un carattere del nostro nick) ed il divisore è posto in DI(un valore fisso: prima B poi 8 ed infine 3). Dopo la divisione il programma somma il resto al risultato della divisione e continua la crittazione con questo nuovo valore.
Per dividere tra loro due numeri a 16 bit si deve prima trasformare il dividendo in un numero a 32 bit (tramite l'istruzione CWD)
Se si cerca di effettuare una divisione per 0 o se il quoziente non sta nei registri viene generata una chiamata all'int 0,il programma termina e il controllo torna al DOS. Per evitare questo problema ci sono due modi: o si controlla il valore del divisore prima di effettuare la divisione, oppure si intercetta l'int 0 e si riscrive una routine di interrupt per gestire l'evento.
=========================================================================================
Ora apro una parentesi su come il programma di Quequero si automodifica. Avrete notato che ho omesso tutte le parti di codice con cui il programma si automodifica (sarebbe stato inutile ripetere lo stesso discorso più volte); Vi espongo ora la mia spiegazione.
Importantissima è l'istruzione "repz" che in pratica ripete un'istruzione(generalmente su stringhe) un tot di volte indicato da cx.
Vediamo in particolare il suo funzionamento:
Repz:
1) Controlla il valore di cx (se è uguale a zero passa alla prossima istruzione)
2) Esegue l'operazione sulla stringa
3) Aumenta o diminuisce il valore di Si e/o Di a seconda dello stato del direction flag(DF); L'incremento è di uno se l'operazione è sui Byte, di due se sulle Word
4) Decrementa cx
5) Torna al punto 1
=========================================================================================
In combinazione con "repz" viene spesso utilizzata l'istruzione movsb o movsw, dove "b" sta per Byte e "w" per word.
L'istruzione "movsb" muove un byte da DS:SI a ES:DI.
DS: Data segment, l'area di memoria alla quale la CPU accede in lettura(i dati).
SI: Source Index, è un puntatore all'interno di un segment (di solito DS) che viene letto dalla CPU.
ES: Extra segment, altra area di memoria alla quale la CPU accede, ma questa volta in scrittura. In pratica, la CPU legge da DS:SI e và a scrivere il byte (o la word) letta in ES:DI.
DI: Destination Index, anche questo è un puntatore all'interno di un segment (di solito ES) dove la CPU và a scrivere. Andando a vedere all'indirizzo ES:DI, se vedete che ci viene mosso qualcosa, potreste anche capitare in locazioni interessanti...
=========================================================================================
Dopo questa piccola parentesi passiamo ora alla spiegazione pratica del codice automodificante di Quequero:
Il programma è protetto in modo da automodificarsi in più parti, sempre prima dell'esecuzione delle stesse: in pratica Quequero ha diviso le istruzioni sulla crittazione del codice in più parti che vengono poi richiamate pian piano dal programma (Unico problema: Il programma una volta avviato si automodifica, ma non ritorna poi alla forma originaria e con Soft Ice si legge praticamente tutto senza problemi. Si deve chiudere il programma e poi riavviarlo per rivedere di nuovo il procedimento di automodifica). Steda ha ragione ma questa situazione era voluta proprio per non complicare troppo il programma NdQue
Queste sono alcune istruzioni per l'automodifica del programma.
401235: MOV ESI,004015C1
40123A: MOV EDI,00401265
40123F: MOV ECX,00000049
La prima istruzione muove in Esi il punto in cui si trova il codice da eseguire.
La seconda muove in Edi la destinazione in cui i byte dovranno essere scritti.
La terza muove in ecx il numero di byte che dovranno essere trascritti prima di finire l'automodifica.
Come già detto prima Quequero ha omesso la fase di rimodifica del codice e dopo la prima esecuzione il codice è già modificato.
Si può notare facilmente la fase di automodifica steppando in Soft Ice con F8 e attivando la finestra code (code on) in modo da vedere anche come cambiano tutti gli op-code.
La password per il mio nick è 844206
Eccoci arrivati al crack del programma: dato che Quequero ha inserito del codice automodificante (Self-Modifyng code) per il crack dobbiamo cambiare più indirizzi; vi mostro come l'ho modificato io:
401235: BEC1154000 MOV ESI,004015C1---> BEC3154000 MOV ESI,004015C3
40123A: BF65124000 MOV EDI,00401265---> BF74134000 MOV EDI,00401374
40123F: B901000000 MOV ECX,00000001---> B949000000 MOV ECX,00000049
40124A: 689B204000 PUSH 0040209B------> E956010000 JMP 4013A5 ;la call di
congratulazioni
Le istruzioni modificate le ho riprese dallo stesso programma nel punto in cui si automodifica per accedere alla message box di complimenti, le ho solo spostate all'inizio del programma, subito dopo la lettura del nick, ed ho sostituito un'istruzione push in jmp verso la call di complimenti.
Ho modificato la vicina locazione 40124A per non cambiare troppo il codice originale,
infatti sia il jmp che ci manda alla message box di congratulazioni che il vecchio push,
occupano lo stesso numero di byte, e le istruzioni intermedie non influenzano minimamente
il funzionamento del programma.
La locazione 401244(repz movsb) deve rimanere invariata per permettere al programma di
effettuare le dovute modifiche e saltare correttamente alla nostra message box.
Infatti questa istruzione è un loop: viene eseguita il numero di volte che è indicato in
ecx(nel nostro caso 49 volte). Ogni passaggio decrementa ecx ed incrementa i registri Esi
ed Edi, fino a quando ecx non diventa 0, ma la cosa più importante è che riporta i byte
nascosti nel punto in cui li deve eseguire.
=========================================================================================
Questo è il sorgente del mio Keygen.
Essendo il mio primo progr. scritto in Tasm se qualcuno mi consiglia come migliorarlo avrà i miei migliori ringraziamenti.
;KeyMaker.ASM - Steda@europe.com
SEG_A SEGMENT
ASSUME CS:SEG_A, DS:SEG_A
ORG 100H
INIZIO: JMP START
Messaggio DB "Key generator per la terza lezione della U.I.C. Writen by Steda",10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"Inserisci il tuo nick",58,'$'
max_len EQU 1000
nick db max_len dup(?) ;Riserva una locazione di memoria per il Nick name
pass db max_len dup(?) ;lo stesso vale per la password
START:
mov dx,OFFSET Messaggio
mov ah,09h
int 21h ; Questo stampa a video il messaggio iniziale e chiede di inserire il proprio Nick
;====================================================================
xor si, si
prossimo_car:
mov ah,01h
int 21h ;L'Int 21 con ah=01 genera una richiesta di input da tastiera.
cmp al,0Dh ;Se il tasto digitato è Return al prossimo jmp salta ed inizia il progr. di generazione della pass.
je Parti
mov nick[si],al ; Salva in Nick
inc si
jmp prossimo_car
Parti:
inc si
mov bp, si
xor si, si
xor ax,ax
xor cl,cl
uno:
mov al, nick[si] ;carica il primo carattere in al
mov di, 11 ;in esadecimale "B"
xor dx, dx ;al posto di cdq che non funziona
idiv di
add ax, dx
shl ax, 1
mov dl, al
call range ;E' posta quasi alla fine del listato
xor ax, ax ;azzera ax
mov al, dl
xor al, 129
xor al, 64
mov pass[si], al ;salva il carattere modificato in memoria
inc si
cmp si, 4
jnz uno ;Torna all'inizio della procedura
xor ax, ax ;azzera ax
due:
mov al, nick[si] ;porta il nick in al carattere per carattere
cmp si, bp
jz tre ;salta a poi se il cmp è affermativo
mov di, 8 ;muove 8 in di
xor dx, dx
idiv di
add al, dl ;somma al con dl, il risultato è posto in al
shl al, 03 ;shifta tre bit a sinistra
ror al, 1 ;ruota 1 bit a destra
add al, 06 ;aggiunge 6 ad al
shl al, 1 ;shifta un bit a sinistra
xor ax, bp
mov di, 3 ;di=3
xor dx, dx
idiv di
add al, dl ;somma al con dl, il risultato è posto in al
mov dl, al ;copia al in dl: dl=al
call range ;call già trattata, vedi sopra (o sotto???)
mov al, dl ;copia dl in al: al=dl
xor al, 130 ;in esa 82
shl al, 02 ;shifta al di due bit a sinistra
ror al, 02 ;ruota al di due bit a destra
mov pass[si], al ;salva il carattere modificato in memoria
xor ax, ax ;cancella ax
inc si ;incrementa si
cmp si, 8 ;confronta si con 8
jnz due
tre:
xor ax, ax ;azzera ax
xor si, si ;azzera si
quattro:
mov al, pass[si] ;porta la pass in al carattere per carattere
xor al, 129 ;la xorra con 129
xor al, 64 ;viene xorrata ancora con 64
mov pass[si], al ;risalvo la pass nella stessa locazione di memoria
inc si ;incrementa si
cmp si, 4
jnz quattro ;Torna all'inizio della procedura
xor ax, ax ;azzera ax
cinque:
mov al, pass[si] ;porta la pass in al carattere per carattere
cmp si, bp
jz fine
xor al, 130 ;xorra la pass con 130
shl al, 02 ;la shifta di due bit a sinistra
ror al, 02 ;la ruota di due bit a destra
mov pass[si], al ;risalvo la pass nella stessa locazione di memoria
inc si ;incrementa si
cmp si, 8 ;confronta si con 8
jnz cinque
jmp fine
range:
cmp dl, 122 ;confronta il carattere crittato con 122
jg elevato ;salta se il valore è troppo elevato
cmp dl, 48 ;confronta il carattere con 30
jl basso ;salta se il valore è troppo basso
indietro:
ret ;torna all'istruzione successiva alla call
elevato:
sub dl, 10 ;sottrae 10 a dl
cmp dl, 122 ;confronta di nuovo il valore
jg elevato ;salta se è ancora troppo elevato
jmp indietro
basso:
add dl, 10 ;aggiunge 10 a dl
cmp dl, 48 ;confronta di nuovo il valore
jl basso ;salta se è ancora troppo basso
jmp indietro
fine:
mov ah,02h
mov dh,5h
mov dl,20h
int 10h ; Specifico in quali coordinate dello schermo stampo la pass.
dec si
mov pass[si+1],'$' ;aggiungo il terminatore
xor si, si
mov ah,09h
mov dx, offset pass
int 21h ;stampo la pass. a video
RETN
SEG_A ENDS
END inizio
Il generatore di pass. è quasi identico al listato assembly del programma originale, ho perciò spiegato solo alcune istruzioni.
Queste sono le istruzioni che ho usato per compilare il programma:
tasm /z c:\tasm5\progra\uic\terzo.asm
tlink /t c:\tasm5\progra\uic\terzo.obj
|
Un doveroso ringraziamento a Quequero che è ormai il nostro + grande insegnante.
Ringrazio anche b0nu$: grazie per aver scritto dei tutorial così interessanti (dai suoi tut sono prese le spiegazioni su repz, div, idiv, cdq).
Un saluto a tutti i partecipanti della U.I.C., mi scuso inoltre con tutti voi dato che non ho mai il tempo di partecipare alla mailing-list, ma vi informo che leggo tutti i vostri mex e presto parteciperò anch'io.
Ciauzzzzzzzz by Steda
Disclaimer |
Home
Anonimato Assembly
ContactMe CrackMe Links
NewBies News Forum Lezioni
Tools Tutorial