RingZ3r0 Presenta
 
Data: 20/12/1998 Titolo: Reversing, come iniziare. Autore: T3X
 
Tools usati:
  • Microsoft's DEBUG.EXE
  • ALittleBitOfMyPoorBrain
 
 

Livello di difficolta': *'

*=Novizio, **=Apprendista, ***=Esperto, ****=Guru
 

LE INFORMAZIONI CHE TROVATE ALL'INTERNO DI QUESTO FILE SONO PER PURO SCOPO DIDATTICO. L'AUTORE NON INCORAGGIA CHI VOLESSE UTILIZZARLO PER SCOPI ILLEGALI.



Reversing, come iniziare.

 
Ok, intanto una breve intro. Il mio scopo è di fornire un aiuto a chi vorrebbe
iniziare a giokare kol debugger, principalmente per i wannabecrackers che non
sanno dove sbattere la testa. Se infatti è vero che la Rete offre una vagonata
di testi e tutorialz, questi sono in inglese e soprattutto prevedono ke ki li
legge sia già kapace di fare kuello ke viene spiegato (un po' kome le banke ke
per darti dei soldi pretendono ke tu li abbia già...).
Cerkerò anke di dare qualke dritta sui toolz e su kome usarli, sempre partendo
dal presupposto di skrivere per persone ke di crackin' non sanno (ankora;)
nulla. Io stesso non sono un guru del Reverse Engeneering, sono anni ke non
metto mano al debugger, pratikamente da kuando trovo kuello ke mi serve già
pronto sulla Rete, e sono sikuramente più agile usando il mio vekkio DEBUG.COM
ke i più recenti SoftICE, IDA & C.
Bene, that's all, si komincia.
Innanzitutto crackare un programma (io ho il vizio di dire 'sproteggere') vuol
dire modificarne il comportamento al fine di ottenerne un utile, ovvero per
esempio evitare ke ci kieda kodici di registrazione, eliminare i fastidiosi NAG
screen (quelle skermate ke ci fanno il pistolotto affinkè si metta mano al
portafogli), evitare di dover kopiare tutto un CD pieno zeppo di minkiate 
filmati orripilanti ke okkupano inutilmente centianaia di Mb un tempo preziosi e
ora inkredibilmente sprekati); insomma, crakkare! :)
Sfortunatamente non esiste *IL* metodo per crakkare, esistono solo alcune linee-
guida generali. Il vero cracker deve trovare sempre la soluzione migliore kaso
per kaso, a volte mi è bastato cerkare un po' nei files di certi gioki per 
trovare qua e là le password e mettere sempre la stessa ovunkue (parlo di kuei 
gioki per DOS di svarati anni fa ke kiedevano la tal parola in tale pagina o 
amenità simili, vedi MechWarrior, Search for the King e moltissimi altri, era 
una protezione molto in voga insieme ai diski kiave).
Il metodo più ovvio comunque rimane quello di mettere mano al codice eseguibile 
del programma, e a questo punto occorre necessariamente fare un passo indietro.
Creare un programma vuole dire creare un codice sorgente in un linguaggio ad
'alto' livello (C/C++, Pascal, Basic (blearp)) e poi passarlo ad un compilatore
che crea il codice oggetto, e ankora passare il codice oggetto ad un linker per
creare l'eseguibile finale, che ora come ora possiamo immaginare essere una 
sequenza di istruzioni elementari in linguaggio macchina. Il problema nasce dal 
fatto che mentre il sorgente è abbastanza chiaro, perlomeno per i nostri scopi 
(vi sfido a kapire kualkosa o trovare *UN* kommento nei miei programmi ...), una 
volta kompilato e ottenuto l'eseguibile finale (.EXE, .COM o .DLL per WinZozzo) 
si perde pratikamente ogni informazione di massima sul programma, ke deve essere 
kuindi ispezionato kon un debugger per tracciarne l'esekuzione e rikostruirne il 
funzionamento. Diciamo ke la creazione di un file eseguibile è un procedimento
one-way, ovvero che non esiste un metodo per ricostruire esattamente il sorgente 
originale partendo dal suo compilato, sempre appunto a kausa della perdita di 
informazioni (nomi di variabili, tipi di routines etc. etc.).
Ho fatto kuesta premessa perkè vorrei far kapire ke la diffikoltà più grossa per 
un cracker è kuella di farsi un' idea del funzionamento del programma, di kome è 
strutturato e di dove andare a cerkare la parte di kodice su kui intervenire. 
Veniamo al sodo ora.
Eravamo rimasti al linguaggio makkina, urge spiegazione ;) Il linguaggio makkina 
è un codice ke è direttamente eseguibile dal processore, senza ulteriori 
trasformazioni. Il metodo per leggere il linguaggio macchina è di utilizzare un 
debugger, un altro programma che ci permette di visualizzare in un codice
mnemonico più 'umano' le operazioni che il processore andrà a kompiere ed 
eventualmente tracciarne passo passo l'esekuzione. Si tratta ovviamente di 
operazioni elementari come somme, shiftamenti, salti & kompagnia bella, 
visualizzate kon diciture kriptike come SUB AL,BL (Subtract BL from AL), JNZ 
XYZK (Jump if NotZero to XYZK) e altre amenità.
Purtroppo non ho il tempo di fare un korso di l.m. , probabilmente nemmeno le 
konoscenze, per questo konsiglio kaldamente a tutti di imparare un minimo di 
linguaggio makkina prima di tentare qualsiasi approccio; Forse riuscirete ad 
arrivare lo stesso alla fine del tutorial, ma di fronte ad un programma vero 
probabilemte vi verrà la voglia di lasciar perdere tutto e fankulo il crackin'.
Nella mia 'karriera' di cracker ho imparato ke le istruzioni più interessanti 
sono davvero poke, non okkorre essere dei maniaci dell'assembler e questo di 
certo facilita le cose. Una delle istruzioni più incontrate in percentuale 
all'interno di un programma è di sicuro quella di kiamata di procedura, una 
sorta di GOSUB ke in realtà è kodifikata come CALL. La sua sintassi è CALL 
[indirizzo]. Vediamo un esempio stupido per fissare le idee. Immaginiamo per un 
momento di essere nel bel mezzo dell'esekuzione di un programma DOS, con una 
rappresentazione del kodice del tipo segmento:offset (non kambia kuasi nulla 
sotto Win, l'importante è il koncetto) :


 SEGM:OFFS    CODICE     MNEMONICO

1F47:0100    BB1000     MOV BX,0010
1F47:0103    B82000     MOV AX,0020
1F47:0106    E8F71E     CALL 2000
1F47:0109    3D0000     CMP AX,0000
1F47:010C    742B       JZ 0139
    .          .             .
    .          .             .

Allora, kuesto esempio davvero banale serve ad illustrare alkune istruzioni:
La prima e la sekonda istruzione karicano il valore 0x0010 esadecimale nel 
registro BX e 0x0020 esadecimale nel registro AX; i registri del processore sono 
una sorta di 'variabili' interne utilizzabili più o meno liberamente per 
eseguire dei kalkoli, delle assegnazioni o per tenere l'indirizzo di posizioni 
partikolari di memoria, e sono ovviamente più di 2.
La terza istruzione è una kiamata di procedura, kome dicevo una sorta di GOSUB e 
RETURN del BASIC. Kuando il processore inkontra una CALL, per prima kosa salva 
nello stack il valore korrente dell' offset all'interno del segmento, valore ke 
si trova nel registro IP (EIP nella modalità 386 estesa), in modo da potervi 
tornare una volta terminata la procedura, dopodikè salta alla posizione 
1F47:2000 dove presumibilmente è kontenuto il kodice della procedura. Vediamolo :

 
SEGM:OFFS    CODICE     MNEMONICO

1F47:2000    51         PUSH CX
1F47:2001    52         PUSH DX
    .           .           .
   [  kodice della routine   ]
    .           .           .
1F47:24AE    5A         POP DX
1F47:24AF    59         POP CX
1F47:24B0    C3         RET

Le prime due istruzioni salvano il valore dei registri CX e DX nello stack, una 
zona di memoria riservata individuata dai registri SS:SP (Stack Segment:Stack 
Pointer) ke funziona kome una pila di oggetti, nella kuale il primo oggetto 
estratto è kuello ke è stato inserito per ultimo. Per kuesto le due istruzioni 
POP finali hanno l'ordine invertito rispetto alle PUSH.
L'istruzione RET ha il kompito (normalmente) di far tornare il programma 
all'istruzione immediatamente successiva a kuella della kiamata, nel nostro kaso 
a 1F47:0109 CMP AX,0000 , in pratika facendo una sorta di 'POP IP'.
Immaginiamo ora ke la procedura kompresa tra 1F47:2000 e 1F47:24B0 esegua 
svariati kompiti, ke kontenga ank'essa a sua volta delle kiamate, tra kui magari 
la verifika della registrazione del kodice del programma stesso, e ke subito 
prima di ritornare a 1F47:0109 imposti il registro AX a 0 o a 1 , a seconda ke 
il programma sia registrato o meno. In kuesto kaso non ci importa un kakkio di 
KOME tale verifika venga fatta, a noi importa sapere ke il proseguimento del 
programma è influenzato (per kuel ke riguarda la registrazione dello stesso) dal 
valore assunto da AX.
l' istruzione 1F47:0109 CMP AX,0000 konfronta il valore (CoMPare) di AX kon 0, e 
viene settato un flag sempre del processore (il flag Zero o ZF; in realtà anke 
il Carry Flag, CF, se i 2 operandi sono Unsigned, ma a noi non ce ne frega una 
cippa :);
Se i due operandi, qui AX e 0 kombaciano, ovvero se AX=0 kuesto benedetto flag 
ZF viene posto a 1, tutto qui; l'istruzione successiva, 1F47:010C JZ 0139 (Jump 
if Zero to 0139) è un salto kondizionato dal valore del flag ZF : se ZF vale 0 
il programma kontinua il suo flusso regolarmente, mentre se ZF vale 1 il 
processore 'salta' alla lokazione 1F47:0139. A kuesto punto è kiaro ke tra 
1F47:010C e 1F47:0139 si troverà la parte di kodice ke visualizza il NAG screen, 
magari una procedura di registrazione o kualke altra rottura di palle, e ke a 
1F47:0139 invece inizia il programma vero e proprio. Inutile dire ke in questo 
kaso banale e fin troppo inventato basta mettere un salto incondizionato nella 
locazione di memoria 1F47:010C ovvero un bel JMP 0139 (JuMP to 0139) ed ottenere :

 
SEGM:OFFS    CODICE     MNEMONICO

1F47:0100    BB1000     MOV BX,0010
1F47:0103    B82000     MOV AX,0020
1F47:0106    E8F71E     CALL 2000
1F47:0109    3D0000     CMP AX,0000
1F47:010C    EB2B       JMP 0139     <---- MODIFIKATO
    .          .             .
    .          .             .

L'ultima kosa per questa introduzione è il fatto ke nel modifikare le istruzioni 
del programma bisogna assulutamente rispettare gli 'spazi' a disposizione ! 
Kuesto è MOLTO importante, per non inkasinare il kodice del programma. Se io 
avessi voluto ad esempio mettere l'istruzione di salto inkondizionato subito 
dopo la kiamata, ovvero al posto del CMP AX,0000 (oramai assolutamente inutile), 
poteva succedere una kosa del tipo :

 SEGM:OFFS    CODICE     MNEMONICO

 1F47:0100    BB1000     MOV BX,0010
 1F47:0103    B82000     MOV AX,0020
 1F47:0106    E8F71E     CALL 2000
 1F47:0109    EB2E       JMP 0139     <---- MODIFIKATO
 1F47:010B    00742B     ADD [SI+2B],DH  <---- SPUTTANATO
     .          .             .
     .          .             .

Ke kazz è successo? Semplice, l'istruzione CMP AX,0000 è 'lunga' 3 byte, mentre 
JMP 0139 solo 2 byte, e kuindi il terzo byte '00' è stato inkorporato 
nell'istruzione successiva, ke il processore ha interpretato kome ADD [SI+2B],DH 
, una kosa in kuesto kaso partikolare irrilevante perkè non verrà mai eseguita, 
ma decisamente brutta e potenzialmente  distruttiva in altre situazioni (kompito 
a kasa  : tradurre ADD [SI+2B],DH ;-). Ma se sono testardo e voglio a tutti i 
kosti mettere il mio JMP nella lokazione 1F47:0109 ?!?! Ekkeppalle , ok ok...
C'è una istruzione dei processori 80X86 ke serve a fare nulla, si kiama NOP e 
corrisponde all'esadecimale 0x90 (kuale cracker non lo sa?!?!), lunga un byte e 
kon la kuale 'aggiustare' il kodice zoppikante. L'ultima versione potrebbe 
essere kuella ottenuta mettendo all ' indirizzo 1F47:010B l'istruzione NOP 
ottenendo :

 SEGM:OFFS    CODICE     MNEMONICO

 1F47:0100    BB1000     MOV BX,0010
 1F47:0103    B82000     MOV AX,0020
 1F47:0106    E8F71E     CALL 2000
 1F47:0109    EB2E       JMP 0139     <---- MODIFIKATO
 1F47:010B    90         NOP          <---- AGGIUNTO
 1F47:010c    742B       JZ  0139     <---- RIPRISTINATO (ma non viene mai eseguito)
     .          .             .
     .          .             .

Ovviamente si potrebbe NOPpare anke il JZ 0139, ma perkè farlo ? :-) Kosì va 
ugualmente, almeno per kuesto esempietto. Al posto dei NOP, se sono tanti e si 
sospetta ke il programma in kualke maniera possa kontrollare se il proprio 
kodice è stato alterato kontando appunto le  okkorrenze di NOP consekutivi si 
possono aggiungere istruzioni 'inutili' kome una sequenza pari di DEC AX e INC 
AX o tutto kuello ke puo' venirvi in mente ke non alteri il kodice; Per favore 
non fate kritike sulla banalità dell'esempio, era voluta e so benissimo ke in 
kasi reali le kose non vanno kosì (perlomeno non più; Terminator 2 era un 
giokino skifoso almeno kuanto la sua protezione,  addirittura era tutto 
kontenuto in una CALL, è bastato NOPparla e addio skermata di protezione ;-).
La domanda ke mi aspetterei è : "Ma kome kazzo fai a sapere ke la CALL 2000 
esegue le verifike e ke in AX c'è il risultato?!?!?" La risposta ci riporta a 
kuello ke dissi nella intro : è tutta questione di kapire kome funziona il 
programma, non ci sono skemi fissi. Si prova, si inventa, si tenta, si spera in 
una botta di kulo (serve SEMPRE) e prima o poi i programmi cedono. A volte mi 
son bastati 10 minuti (vedi Terminator 2) altre volte è stata questione di 
svariate ore totali (il Conseal 1.04 ad esempio, ma li' è kolpa dell' 
inesperienza kon le Win32 :), altre volte ho rinunciato (si, il tempo è 
tiranno...).
Se volete provare ad assemblare l'esempio ke ho riportato, da WIn9X aprite una 
finestrella DOS e scrivete 'debug'; vi apparirà un trattino ed il prompt, voi 
skrivere A e date invio, dovreste ottenere una kosa del tipo 'XYZK:0100 _ ' : 
ora potete digitare le istruzioni (MOV BX,0 etc etc ), e kuando avete finito 
date CONTROL+C; date U 100 e invio, se avete fatto tutto bene dovreste trovare 
l'esempio, segmento a parte (kuello kambia). 
Happy Crackin' a tutti, e andate a rakkattare un buon libro sul linguaggio 
makkina degli 80x86. Alla prossima lezione.

   
                                                                    T3X 

(C) 1998 T3X  for RingZer0
  _________        ____  ___                                                   
  ########@ a##gg  \##B ,##M                                                   
  ########@,#####@  M##C&##"  <------------------------=< [ EFnet or IRCnet ]          
     ##@   &#" Q##  `#####N                                                    
     ##@       Q#B   7###B     GReEtZ GoEs oUt To: Tutti i D4RkSiDErz per le
     ##@      g#B"    ###C  kose ke abbiamo saputo fare, ai bros M|kky, Layne,
     ##@      ###@   ,###@       Slay, Hija, EvilBUU, GOLDRAKE, a Maddevil,    
     ##@       \##a  &####a     Eko, R4|k3r, Net-Call e tutti quelli ke non         
     ##@   ##  ]##J /##@##W            ho voglia di menzionare :-)
     ##@   Q#g_d##  @##"Q##g      Ovviamente a tutti koloro ke tengono in
     ##@   `####B" Z##N `##B,         piedi il progetto RingZer0      
            `"""               
      E' assolutamente VIETATO riprodurre questo testo usando fusilli
  Barilla per comporre le lettere nonchè utilizzare le informazioni quivi
         contenute per fare colpo sulla compagna di banco strafiga
                          [tanto non funziona(mai)].