Terzo Corso U.I.C.


10/10/99

by Steda

 
 

UIC's Home Page

Published by Quequero


Davvero i miei migliori complimenti per Steda che ha fatto un tutorial impeccabile con tanto di key generator

 
UIC's form
E-mail: steda@europe.com
Steda
UIC's form

Difficoltà

( )NewBies (X)Intermedio ( )Avanzato ( )Master

 

Scaricate qui l'allegato

 

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.

Seriale e keygen
Written by Steda

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

WDasm 8.93

HexWorkshop 2.01

URL o FTP del programma

Dal sito di Quequero alla terza prova della U.I.C. http://quequero.cjb.net

Notizie sul programma 

Questo è il terzo programma che Quequero ha scritto per la U.I.C.
E' costituito da due text-box in cui inserire il proprio nick ed una password valida.
Come già anticipatoci da Quequero il progr. è scritto con codice auto-modificante.

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

Note finali

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

Vorrei ricordare che il software va comprato e  non rubato, dovete registrare il vostro prodotto dopo il periodo di valutazione. Non mi ritengo responsabile per eventuali danni causati al vostro computer determinati dall'uso improprio di questo tutorial. Questo documento è stato scritto per invogliare il consumatore a registrare legalmente i propri programmi, e non a fargli fare uso dei tantissimi file crack presenti in rete, infatti tale documento aiuta a comprendere lo sforzo immane che ogni singolo programmatore ha dovuto portare avanti per fornire ai rispettivi consumatori i migliori prodotti possibili.
Noi reversiamo al solo scopo informativo e di miglioramento del linguaggio Assembly.
Capitoooooooo????? Bhè credo di si ;)))) 

 
UIC's page of reverse engineering, scegli dove andare:

Home   Anonimato   Assembly    ContactMe  CrackMe   Links   
NewBies   News   Forum   Lezioni  
Tools   Tutorial 

UIC