Jump to content
Dr4k3

Un micro-tutorial, pentru cei neinitiati in cracking

Recommended Posts

Posted

Un micro-tutorial, pentru cei neinitiati in cracking, de SfYnX

Este vorba de un program care trimite e-mailuri la mai multe

adrese de odata (spamming ,indeed :) ), dar versiunea

neinregistrata, are o limita de 3 adrese.

Exista doua solutii la problema ta:

1) Se inregistreaza programul

2) Se patchuieste proramul ca sa trimita oricat de multe mesaje, chiar

fiind neinregistrat.

Sigur, metoda mai simpla este metoda 2. Metoda mai frumoasa si mai

utila, insa, este metoda 1 (poate mai are niste nag screenuri, care

dispar la inregistrare, etc).

Voi incerca sa descriu pe scurt metoda de inregistrare generala, care

lucreaza la 90% din programele shareware.

La crackuiala unui program (inregistrarea), planul negru de actiune

este urmatorul:

1. Se incearca inregistrarea cu un cod de inregistrare aiurea

2. Se gaseste functia care face inregistrarea in program:

2.1. Se gaseste punctul unde se citeste codul introdus

2.2. Se gaseste punctul in care se face compararea codului cu

3.1 Daca este codul corect, se inregistreaza programul cu codul

corect

3.2 Daca este un cod generat din codul nostru introdus, se

gaseste in program metoda de transformare a codului introdus

3.2.1. Se scrie o functie generala pentru efectuarea acestei

transformari

3.2.2. Se extrapoleaza functia cu parametrul , pentru a gasi

codul corect de inregistrare.

Voila, nici 4 pasi :).

Ei, acesti pasi necesita ceva cunostinte si resurse: cunoasterea

limbajului de asamblare si NuMega Soft-Ice instalat. Eventual si

Borland Pascal sau C sau alt limbaj de nivel inalt, pentru a putea

scrie functia de transformare a codului (si extrapolarea), functie

care poate fi scrisa si in assembler, sau chiar in debug.exe, daca

nu ai nici un compilator prin zona. Voi incerca sa descriu pe scurt

pasii pe rand, straduindu-ma sa fiu cat mai inteles si lipsit de

aiureli si greseli :).

Pasul 1:

Este clar: Vom incerca sa inregistram programul cu un cod

invalid. Deobicei, cand selectam 'Register', ne apare un dialog, unde

introducem acest cod [si numele, adresa, etc].

Pasul 2:

Pentru a gasi functia care face inregistrarea, trebuie in primul rand

sa gasim unde se afla parametrii acesteia, sau codul nostru introdus

(alti parametri, ca adresa, etc, nu ne intereseaza, sau ne intereseaza

mai tarziu, in cazul in care acestia participa in transformarea codului

nostru introdus). Dar, ca sa nu ma intind pe 100 de pagini,

sa consideram ca suntem in cazul cel mai simplu, adica programul

jertva va compara codul nostru introdus cu un cod pe care il are scris

in el, adica ceva de genul:

if cod_introdus<>cod_corect then mesaj('Dute-n dracu!') else

mesaj('Thanks for paying $500 for our program');

Ceea ce trebuie sa aflam ca if-ul acesta sa fie false, este

constanta cod_corect. Pentru a putea sa-l aflam, trebuie mai intai

sa gasim in program punctul unde se executa acest if.

Ar fi o idee grozava, daca am putea impune soft-ice-ul sa se opreasca

atunci cand se face vreo operatie cu codul nostru (ca, de exemplu, acest

if).

Pentru aceasta, in soft-ice exista notiunea de breakpoint.

Ei,aceste break-pointuri se pot pune cu o sumedenie de conditii, ca,

de exemplu, executia unei functii API, citirea sau scrierea din/in vreun

port, citirea/scrierea unei adrese din memorie, etc.

Acum, daca am sti adresa variabilei noastre (codul) in memorie, am

putea pune un breakpoint pe accesarea acestei adrese, oprindu-ne chiar

la if-ul multdorit :). Asfel, problema ar fi rezolvata.

Cum aflam, insa adresa codului introdus ??? Iarasi, printr-un

breakpoint.

Si anume, vom pune un breakpoint pe functia windows de citire din

dintr-un control. In cele mai multe cazuri, aceasta se realizeaza

prin urmatoarele functii:

GetWindowTextA

GetDlgItemTextA

Iar in soft-ice, pentru a ne opri atunci cand se executa aceasta

functie, se utilizeaza comanda BPX (Breakpoint on execution):

BPX

Ei, noi nu stim care din aceste doua functii este utilizata in program,

deci,

vom pune breakpoint pe ambele. Dar cand? Pai, anume atunci cand

am introdus codul invalid in dialogul de registrare, dar inainte

de a apasa pe OK. Deci, dupa ce am scris tot ce a vrut programul in

dialogul de registrare, nu apasam OK, ci apasam Ctrl-D, pentru a intra

in softice. Aici vom scrie:

BPX GetWindowTextA

BPX GetDlgItemTextA

Cu Ctrl-D iesim din softice inapoi in proramul nostru.

Cand apasam pe OK, ne vom trezi in softice, la inceputul unei

din aceste doua functii, sa zicem, GetWindowTextA. Ce facem

mai departe?

***********************************************************************

Sa facem o abatere si sa analizam aceasta functie. Declaratia ei in

Win32 API este urmatoarea:

int GetWindowText(int wndhandle, char *buffer, int maxstrLen);

Pentru a chema aceasta functie in C, vom folosi comanda:

result=GetWindowText(myWndHandle, *MyBuffer, 32);

Aceasta inseamna, sa ne dea textul inscris in fereastra cu

ID=myWndHandle, sa-l puna in MyBuffer si sa ia doar 32 de caractere.

Dar cum se cheama aceasta functie in assembler? Parametrii pe care

ii transmitem la functie intr-un limbaj de nivel inalt, se pun pe stack,

care

este un segment de memorie, in care se stocheaza date "una peste alta".

Adresa ultimei bucatele de date aflata pe stack, se afla in

registrul ESP (extended stack pointer). Cand executam comanda

push, procesorul decrementeaza automat valoarea acestui registru cu

marimea

operandului de la push (eg, push EAX, va pune valoarea din EAX, pe stack

la adresa SS:ESP, iar ESP=ESP-4, pentru ca registrul EAX este de 32

biti,

deci 4 bytes). Comanda POP va incrementa registrul ESP cu marimea

operandului...

Bine, sa ne intoarcem la chemarea GetWindowTextA. Pentru a chema

aceasta functie in assembler, va trebui sa executam urmatoarele

instructiuni:

Push 20 ; lungimea stringului in hexazecimal

lea eax,myBuffer ; eax = adresa myBuffer

Push eax ; punem adresa pe stack

Push dword ptr [esi+1D1] ; punem pe stack ID-ul (sau handle-ul)

ferestrei, aflat in memorie la esi+1D1h

CALL USER32!GetWindowTextA ; luam textul...

***********************************************************************

Pasul 2.1

Acum am inteles (sper) cum este chemata functia in assembler, sa ne

intoarcem

deci in softice (unde ne-am oprit), cand suntem la inceputul functiei

GetWindowTextA, in USER32.DLL. Nu avem nevoie sa vedem cum se citeste

valoarea acesetei functii de catre Windows, deci, ca sa ne intoarcem

in programul nostru, apasand tasta F11. Acum suntem la urmatoarea

instructiune dupa CALL USER32!GetWindowTextA.

Sa examinam putin cu ce parametri a fost chemata aceasta functie

(sa vedem ce s-a pus pe stack), vom vedea ceva de genul:

Push 20 ; lungimea stringului

* Lea eax, [ebp-3C] ; Eax=ebp-3c

mov ecx, dword ptr [esi+2D] ;...

push eax ; adresa buferului

push ecx ; handle-ul...

CALL USER32!GetWindowTextA ; cheama functia..

push 00000000 ; adaoga un zero pe stack...etc

....

cu (*) am marcat punctul interesant. Acum am aflat unde este buferul

nostru, deci unde a fost

luat textul nostru: la ebp-3C.

Daca scriem comanda D EBP-3C (Display Memory at), vom vedea in fereastra

de date din softice

codul pe care l-am introdus. S-ar putea sa nu fie chiar codul, ar putea

fi numele sau adresa

pe care a mai cerut-o. In acest caz, apasam Ctrl-D pentru a ne opri la

urmatoarea chemare

a functiei GetWindowText, pana cand D EBP-3C=codul nostru.

Pasul 2.2

Acum, pentru a vedea ce face programul cu aceasta variabila, va trebuia

punem un breakpoint pe

citirile/scrierile din/in aceasta adresa de memorie. In Soft-Ice,

aceasta se face cu comanda

BPM (Breakpoint on Memory access):

BPM

In cazul nostru adresa este ebp-3c, deci vom scrie:

BPM (EBP-3C)

Apasand Ctrl-D, ne vom opri in momentul in care se manipuleaza datele de

la adresa EBP-3C, si

anume la instructiunle (de exemplu):

0234C001 DEC CX

INC EDI

INC ESI

MOV AL,Byte ptr [EDI] * ; AL=[EDI]

MOV BL,Byte ptr [ESI] ; BL=[ESI]

CMP AL,BL ; if AL<>BL then

JNZ 0234CA4D ; goto 0234CA4D

CMP CX,0 ; If CX<>0 then

JNZ 0234C001 ; goto 0234C001

....

Pentru mine aceasta inseamna urmatoarea comparatie:

again:

CX:=CX-1

EDI:=EDI+1;

ESI:=ESI+1;

If var1[EDI]<>var2[ESI] then goto abort_loop

If CX<>0 then goto again

Pentru ca SoftIce s-a oprit la *, inseamna ca codul nostru se compara cu

ceva. Ceva inseamna,

de fapt codul corect. Care se afla la adresa ESI.

Pasul 3.1.

Deci, pentru a-l vedea, este suficient sa scriem comanda:

D ESI

Scriem pe-o hartiuta codul, scoatem toate breakpointurile pe care le-am

pus:

BC * (clear breakpoint *), iesim din SoftIce, cu Ctrl-D si mai facem o

data

registrarea cu acelasi nume si adresa, dar cu codul corect.

Uite ca am si crackuit programul.

Doar ca sa ma exprim corect: Ceea ce am descris eu aici este cazul

ideal, adica metoda cea

mai simpla de protectie (care, totusi, este utilizata in 80% din

cazuri). Exista metode

foarte complicate de protectie, dar diferenta de complexitate pentru un

cracker adevarat

este doar ceva timp in plus petrecut la crackuirea programului.

Posted

mersi, :D e foarte bun tutorialul, chiar nu stiam cum procedeaza programul la inregistrare, sunt foarte binevenite tutorialele astea de initiere, te ajuta sa intelegi cum "gandesc" programele, cred ca o sa ma apuc de asm sa inteleg mai bine :P

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...