Menu

Microsoft's DEBUG.EXE

 

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
1000
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 ist
1000
ruzioni:
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
1000
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ù
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
c8d
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)].

Top: Sicurezza su Internet - Back
Previous: Reversing Delphi - Tutorial interattivo - Up: Sicurezza su Internet - Next: 1st tutorial

This page last updated: Friday 08 November 2002 at 3:59pm

Please send any comments on this page to Astalalista.

Labelled with ICRA

This page is powered by Copyright Button(TM).
Click here to read how this page is protected by copyright laws.

Use this button to
NOT browser button


begin banner Exchange zone

Member of BannerPower Rotation System

Home Main Portal Translate Tell A Friend Create Page Create Site Search Site Search WWW E-mail Login Insert A Link Free for All Free Dating Forum disabled-come soon Guestbook Links Vote For Us disabled-come soon Head of Household Life Insurance | Dclick Marketing Blog | Necklace | Kitten | Beaded Necklace