Menu

Beginner's crack

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 NAGscreen
(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 kasoper 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
.
.
.
.
.
.etc...
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ù
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 [ManiaC]GreetZ : a tutti i D4RkSiDErz per le kose ke abbiamo saputo fare, al bro M|kky,
Layne e tutti gli altri ke non ho voglia di menzionare :-)
t3x@cryogen.com

Top: Sicurezza su Internet - Back
Previous: The Italian CRaCKiNG Encyclopedia vol. 6 - Up: Sicurezza su Internet - Next: Appunti su chiavi Hasp e SmartCards by BlackDruiD

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

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 Seo Quote | Effective Weight Loss Pill | Free Casino Games | Blognoodles | Merchant Services Help