Autor: Ptasiek Cel: GodeZip 98 Skad: Enter 5/99 Czym: SI Efekt: serial&keyGenerator
Wstep:
Wielu newbies crackujac progi z prostymi wrecz sztandarowymi zabezpieczeniami zazwyczaj szuka poprawnego seriala w pamieci. Niestety nie zawsze program jest tak uprzejmy i podaje go nam jak na tacy w oknie danych SI. Sa tez progi, w ktorych poprawnosc seriali sprawdza sie poprzez przeprowadzenie na nich jakichs operacji matematycznych i operowania wynikiem. Jeden z takich progow zostal opisany przeze mnie wczesniej(BannerShow2). Dzis mam zaszczyt przedstawic kolejny produkt nie generujacy poprawnego seriala.
GodeZip jest progiem do zarzadzania zzipowanymi plikami. Posiada licznik uruchomien - limit 25. Rejestruje sie go przez podanie nr licencji i kodu odblokowujacego. Brzmi groznie, ale w rzeczywistosci algorytm jest banalny.
Uruchamiamy proga z zaladowanym SI. Przechodzimy do okienka rejestracyjnego i wpisujemy jakies dane:
licencja: 123123123123 kod : qwerty
Wchodzimy do SI (CTRL+D) i ustawiamy breakpointy na standardowe funkcje API pobierania textu:
bpx getwindowtexta bpx getdlgitemtexta
Wychodzimy z SI (CTRL+D) i klikamy OK. Zadzialala pulapka na Getdlgitemtexta. Spoko, widzimy, ze funkcja ta wywolywana jest dwa razy - pobieraja one licencje i kod.
Idziemy dalej - krok po kroku, wchodzac do najblizszej procedury(F8 - gdy step na instrukcji call):
* Referenced by a CALL at Addresses:
|:00402CCA , :00402F30
|
:004027CC 55 push ebp
:004027CD 89E5 mov ebp, esp
:004027CF 57 push edi
:004027D0 56 push esi
:004027D1 53 push ebx
:004027D2 8B5D08 mov ebx, dword ptr [ebp+08]
:004027D5 BE1CD34300 mov esi, 0043D31C;(nasza licencja)
* Possible StringData Ref from Code Obj ->"G1111111"
|
:004027DA BF91254000 mov edi, 00402591
:004027DF B809000000 mov eax, 00000009
:004027E4 89C1 mov ecx, eax
:004027E6 FC cld
:004027E7 A800 test al, 00
:004027E9 F3 repz
:004027EA A6 cmpsb;porownanie jej z G1111...
:004027EB 0F843D020000 je 00402A2E;jezeli rowne to skacz
Takich porownan jest jeszcze kilka. W ten prymitywny sposob autor chcial sie bez watpienia zabezpieczyc przed crackerami. No coz nie na wiele mu sie to zdalo. Idziemy dalej:
:00402825 E85AFFFFFF call 00402784;dziwna procka - uzywa dodatkowego ;rejestru segmentowego - chyba jakis antidebug - ale nie dziala na SI ;(moze sie myle) :0040282A 85C0 test eax, eax :0040282C 0F8501020000 jne 00402A33 :00402832 803B44 cmp byte ptr [ebx], 44;w [EBX] nasz kod, a ;konkretnie jego 1-y znak jest porownywany z 'D' :00402835 0F94C0 sete al;nadaj al wartosc flagi Z ;jezeli ostatnio porownywane wartosci so rowne to Z=1 w przeciwnym razie ;Z=0 :00402838 0FB6D0 movzx edx, al :0040283B 8B4D0C mov ecx, dword ptr [ebp+0C];wpisz do [ECX] ;nasza licencje :0040283E 803947 cmp byte ptr [ecx], 47;i porownaj 1-y znak licencji ;z 'G' dalej analogicznie jw :00402841 0F94C0 sete al :00402844 25FF000000 and eax, 000000FF;EAX:=EAX AND FF :00402849 85D0 test eax, edx;EAX AND EDX - ale zmienia ;tylko znacznik - ww rejestry bez zmian. :0040284B 0F84D7010000 je 00402A28;jesli Z=1 to skacz :00402851 E82EFFFFFF call 00402784
Spostrzezenia: procka ta, wywolywana jest dwa razy. Prawdopodobnie ten drugi CALL przy starcie proga, co by znaczylo, ze seriale nie sa przechowywane w postaci zaszyfrowanej Dalej 1-y znak licencji porownywany jest z 'G', a 1-y kodu z 'D' potem wykonywane jest EAX AND FF
AND jest logiczna operacja na bitach:
argument1(bit_nr_X)=1 gdy argument1(bit_nr_X)=1 oraz argument2(bit_nr_X)=1.
W kazdym innym przypadku daje zero.
Przyklady:0 AND 255 = 0 00000000 11111111 00000000 1 AND 255 = 1 00000001 11111111 00000001 128 AND 63 = 10000000 00111111 00000000
A wiec jak wynika z powyzszego numery musza sie zaczynac na wskazane litery. Wyjdzmy wiec z SI i uzupelnyjmy nasze nr o te znaki - i wsio od poczatku
G123123123123 Dqwerty
Ok, nastepnie zaczyna sie proces sprawdzania zgodnosci licencji z kodem:
:00402858 0F85CA010000 jne 00402A28 :0040285E 0FBE5306 movsx edx, byte ptr [ebx+06];EDX=kod[7] :00402862 8B4D0C mov ecx, dword ptr [ebp+0C] :00402865 0FBE4101 movsx eax, byte ptr [ecx+01];EAX=licencja[2] :00402869 83C01E add eax, 0000001E;EAX=EAX+1e :0040286C 39C2 cmp edx, eax;porownaj EAX i EDX :0040286E 0F85B4010000 jne 00402A28;jesli rozne to skacz :00402874 E80BFFFFFF call 00402784;nic waznego
W tym fragmencie listingu prog bierze siodmy znak kodu i porownuje go z drugim znakiem licencji powiekszonym o 1e. Konkretnie porownuje ich cody ASCII So tutaj i ponizej sa zaleznosci wymagane przez procke, aby numery byly poprawne. Idziemy w dol zmieniajac flage przy kazdym skoku az dojdziemy do:
:00402A15 7511 jne 00402A28 :00402A17 E868FDFFFF call 00402784 :00402A1C 85C0 test eax, eax :00402A1E 7508 jne 00402A28 :00402A20 B801000000 mov eax, 00000001;EAX=1 :00402A25 EB0E jmp 00402A35;skocz do dziekczynnego messageboxa
Cala filozofia opiera sie na spisaniu wszystkich zaleznosci znakow licencji od znakow kodu i napisac maly keyGen, aby dokonczyc dziela. Komu nie chce sie zmudnie spisywac dzialan ten ma je spisane ponizej w zalaczonym source keyGena.: Generuje on licencje na podstawie kodu, a wiec Twoj nick nie bedzie widoczny w oknie About.. Mozna opierajac sie na tym source'u napisac odwrotna funkcje, ale jej wynikami beda znaki ASCII spoza zakresu widzialnosci wINSHITA.
uses crt;
var licencja,kod:string;i:byte;
begin;
licencja[1]:='D';
writeln('The GodeZip98 keyGenerator made by Ptasiek. Enjoy it!');
writeln('Polish crack rulz');
writeln('Enter string');
readln(kod);
insert('D',kod,1);
if length(kod)<16 then
for i:=length(kod)+1 to $f do kod[i]:='a';
licencja[2]:=chr(ord(kod[7])-$1e);
licencja[3]:=chr(ord(kod[6])-$17);
licencja[4]:=chr(ord(kod[3])-$1f);
licencja[5]:=chr(ord(kod[8])-$11);
licencja[6]:=chr(ord(kod[4])-$13);
licencja[7]:=chr(ord(kod[2])-$15);
licencja[8]:=chr(ord(kod[5])-$1d);
licencja[9]:=chr(ord(kod[9])-$1e);
licencja[$e]:=chr(ord(kod[$a])-$1c);
licencja[$f]:=chr(ord(kod[$b])-$18);
licencja[$c]:=chr(ord(kod[$c])-$15);
licencja[$d]:=chr(ord(kod[$d])-$16);
licencja[$b]:=chr(ord(kod[$e])-$1b);
licencja[$a]:=chr(ord(kod[$f])-$1d);
licencja[1]:='G';
clrscr;
writeln;
write('Kod : ');
for i:=1 to $f do
begin;
write(kod[i]);
gotoxy(wherex-1,wherey-1);
write('_');
gotoxy(wherex,wherey+1);
end;
writeln;
writeln;
write('licencja : ');
for i:=1 to $f do
write(licencja[i]);
end.
Dobra, teraz dla sprawdzenia uruchamiamy proga poraz drugi i... Unregistered - co sie stalo - czyzby nie docenilismy autora, ktory wyposazyl proga w opcje falszywej rejestracji - A niech sie tam cracker ucieszy. Ale nigdzie nie wywolywana jest innna procka sprawdzajaca. Wobec tego ustalmy gdzie przechwywany jest serial. Uruchamiamy regmona i nasz prog. Ciekawie wyglada plik godezip.ini Przejrzyjmy go:
(..) licencenum= licencekey= (..)
Co jest?, brakuje danych. Tak jakby prog ich nie wpisal. Chwila zastanowienia(no, moze dwie chwile) olsnienie - setup proga polegal jedynie na skopiowaniu plikow z CD so looknijmy w attrybuty tego pliku - no tak tylko_do_odczytu. Usunmy ow attrybut i zarejestrujmy prog jeszcze raz. Super dziala! Oto przyklad na banalne rozwiazanie skomplikowanego z pozoru problemu. Na dzis to juz wszystko tradycyjnie jesli masz jakies pytania, uwagi sugestie pisz:
dreadpl@polbox.com
Ptasiek