Cybult 4 by ToMKoL [c4U]

Zainstalowalem ostatnio SI i przypadkiem cisnalem Ctrl-D, tak wiec
trzeba bylo sobie troche przypomniec jak sie tym poslugiwac i tak
oto wpadlo mi w rece crackme 4 by cybult. A wiec do dziela. Najpierw
wrzucimy to sobie pod IDA i popatrzymy co dla nas cybult przygotowal:
	cdq				;zeruj edx
	sub ebx, ebx			;zeruj ebx
	clc				;odznacz flage carry
	or dl, 83h			;do dl 83h
	mov eax, dword ptr CreateFileA+2;do eax wskaznik na createfiela
	xor dl, byte ptr [oo]		; "O" - w edx powstanie CCh
	mov eax, [eax]			;
	cmp [eax], dl			;sprawdz czy jest bpx na createfilea
	lea eax, uname			;do eax adres bufora name
	jnz nobpx			;brak bpx'a
	sub eax, 0FFFFFF88h		;ustaw eax na nazwe pliku
	xor dword ptr [eax+ebx*4], 18101C0Bh;po tym nazwa z miss zmini sie na fuck
Czyli na poczatek cybult sprawdza czy nie zalozylismy pulapki na
CreateFileA, jesli zalozylismy to nazwa naszego pliczku zmieni sie
z miss.you na fuck.you. Dosc ciekawa metoda anti-bpx, tyle ze to nam
zycia nie utrudni. Idac dalej widzimy wywolanie DialogBoxParamA, wiec zobaczmy
jakie komunikaty obsluguje nasze crackme:
	movzx	eax, uMsg
	sub	ebx, ebx
	cmp	ax, wm_close
	jz	close
	cmp	ax, wm_destroy
	jz	close
	cmp	ax, wm_showwindow
	jz	_showwindow
	cmp	ax, wm_command
	jz	command
Czyli interesowac nas moze wm_command i wm_showwindow, bo pozostale sa
raczej malo ciekawe. A wiec zobaczmy wm_command:
command:
	cmp wParam, 7			;ktos kliknal statica
	jnz msgloop			;
	sub ebx, ebx			;
	push hWnd			;
	pop edx				;
	push 400000h			;
	pop ecx				;
	mov esi, offset msgparams	;parametry wywolania
	mov dword ptr [esi], 28h	;wielkosc
	mov [esi+4], edx		;hInstance
	mov [esi+8], ecx		;hWnd
	mov dword ptr [esi+0Ch], offset skill;text
	mov dword ptr [esi+10h], offset info;caption
	mov dword ptr [esi+14h], 80h	;styl
	mov dword ptr [esi+18h], 2	;ikona
	push esi			;parametry
	call MessageBoxIndirectA	;pokaz about
Czyli taki maly about jesli ktos kliknie na napis na staticu.
Dalej zostalo nam tylko wm_showwindow, ktore zastepuje tu powszechnie znane
i uzywane wm_initdlg. A wiec przyjrzyjmy sie:
najpierw ladowana i ustawiana jest ikonka oraz ladowany i podmieniany jest
kursor dla statica, dalej mamy cos co nas interesuje
	push ebx			;
	push FILE_ATTRIBUTE_NORMAL	;
	push OPEN_EXISTING		;
	push ebx			;
	push ebx			;
	push GENERIC_READ		;
	push offset file		;
	call CreateFileA		;odczyt pliku
	inc eax				;
	jz brak				;
	dec eax				; 
Czyli otwieramy istniejacy plik tylko do odczytu. Dalej jest mala zabawa cybulta,
ktora to pominiemy i dalej widzimy:
	mov hFile, eax			;zapisz uchwyt
	push ebx			;
	push eax			;
	call GetFileSize		;
	cmp eax, 42h			;rozmiar pliku 66 bajtow
	ja brak				;jak wiekszy to wypad
	mov filesize, eax		;zapisz wielkosc pliku
	push ebx			;
	push offset byte_403000		;
	push eax			;
	push offset buffor		;
	push hFile			;
	call ReadFile			;odczyt pliku
	test eax, eax			;
	jnz check			;odczytano plik
	push hFile			;
	call CloseHandle		;zwolnij uchwyt pliku
	jmp brak			;

check:
	call	check_file		;mielenie pliku
Czyli sprawdzenie czy plik nie jest wiekszy niz 66 bajtow i jesli nie jest to nastapi
odczyt i sprawdzenie zawartosci pliku. Wiec spojrzmy czego cybult wymaga od pliku:
	mov ecx, filesize		;rozmiar pliku do ecx
	mov esi, offset buffor		;bufor z odczytanym plikiem
	mov edi, esi			;do edi to samo
	...
decrypt1:
	lodsb				;
	xor al, 54h			;
	neg al				;
	dec al				;
	xor al, 43h			;
	rol al, 2			;
	sub al, 7			;
	sub al, 14h			;
	not al				;
	inc al				;
	add al, 0FEh			;
	dec al				;
	ror al, 3			;
	add al, 7			;
	stosb				;
	loop decrypt1			;pierwsze deszyfrowanie keyfile'a
Tak pokrotce przedstawia sie pierwsze deszyfrownanie pliku, bez zbednych smieci. Ta petelka
przetworzy kazdy znak z naszego pliku, ale narazie to pominiemy. Dalej mamy:
	sub	ecx, 4				;rozmiar pliku -4
	js	bad				;
Jesli plik byl mniejszy niz 4 bajty skoczy, gdyz ecx<0
calccrck:
	lodsb					;
	rol	eax, 3				;
	xor	edx, eax			;
	rol	edx, cl				;
	loop	calccrck			;obliczenie crc keyfile
	neg	edx				;
	mov	crck, edx			;zapis
Ta petelka oblicza sobie takie crc z naszego pliku-4 ostatnie bajty i zachowuje na pozniej.
	or al, 14h			;do al 20
	rol eax, 8			;teraz ah=20 al=0
	mov edi, offset uname		;bufor na name
	lodsb				;
	xor al, 73h			;
	rol al, 3			;
	cmp al, ah			;
	ja bad				;
	or dl, al			;
	movzx ecx, ah			;
	push cx				;
	sub cl, dl			;
	or byte ptr [licznik], cl	;licznik=20
	pop cx				;
Tutaj male sprawdzonko czy pierwszy bajt pliku to 73h, jesli tak przechodzimy do
deszyfrowania name.
decname:
	lodsb				;
	xor al, 9Bh			;
	ror al, 3			;
	sub al, 18h			;
	rol al, cl			;
	or al, al			;
	jz bad				;
	stosb				;
	dec ecx				;
	cmp cl, dl			;
	ja decname			;deszyfrowanie name
	inc byte ptr [licznik]		;licznik=21
Czyli nasze name po przejsciach musi zajac rowne 20 bajtow, jesli wczesniej bedzie
bajt 00h to zrobimy wypad, wiec nasz plik musi byc 1 bajt staly + 20 bajtow name + 4 bajty crc.
Tak wiec narazie nasz plik zajmuje 25 bajtow z czego pierwszy jest staly, 20 kolejnych to
zaszyfrowane name, a 4 ostatnie to crc calego pliku. Lecimy dalej:
	or	al, 0Fh				;al=15
	rol	eax, 8				;ah=15 al=0
	mov	edi, offset company		;bufor na company
	or	dl, byte ptr [licznik]		;dl=21
	add	esi, edx			;
Teraz bedzie deszyfrowane company ale jeszcze zanim to nastapi jest taka sobie petelka, ktora
nic robi poza zajmowaniem czasu. A wiec zobaczmy jak przedstawia sie deszyfrowanie company:
	lodsb				;
	neg al				;
	xor al, 4Dh			;
	dec al				;
	cmp al, ah			;
	ja bad				;
	push eax			;
	sub ah, al			;
	add byte ptr [licznik], ah	;
	pop eax				;
	and ebx, 0FFh			;
	mov bl, al			;
	movzx ecx, ah			;
Tu sprawdzenie czy 22 bajt rowny B4h, jesli nie to wypad.
deccomp:
	lodsb				;
	xor al, 11h			;
	rol al, 5			;
	sub al, 3Ch			;
	test al, al			;
	jz bad				;
	stosb				;
	dec cx				;
	cmp cl, bl			;
	ja deccomp			;deszyfrowanie company
	inc byte ptr [licznik]		;
Tak pokrotce przedstawia sie deszyfrowanie company. Company musi zajac 15 bajtow w pliku.
Tak wiec nasz plik liczy juz 1+20+1+15+4=41 bajtow. Zobaczmy co dalej:
	xor ax, 800h			;ax=800h
	and al, ah			;
	sub bx, bx			;
	or bl, byte ptr [licznik]	;
	add esi, ebx			;
	mov edi, offset crchex		;bufor na crc
	lodsb				;
	xor al, ah			;
	add al, 7Fh			;
	dec al				;
	rol al, 1			;
	cmp al, ah			;
	jnz bad				;
	sub ah, 4			;
	add byte ptr [licznik], ah	;
	movzx edx, ah			;
Tu kolejny staly bajt 8Eh.
deccrc:
	lodsb				;
	dec al				;
	sub al, 66h			;
	stosb				;
	dec edx				;
	jnz deccrc			;deszyfruj crc
	inc byte ptr [licznik]		;
Tu deszyfrowanie crc z mix(name) xor mix(company), czyli kolejne 4 bajty pliku to zaszyfrowane
crc. Wiec mamy 1+20+1+15+1+4+4=46 bajtow, zblizamy sie do granicy 66 bajtow wyznaczonej przez
cybulta. Zobaczmy wiec co dalej:
	imul eax, 0			;eax=0
	lea eax, [eax+eax*4]		;po co to, eax=0 0+0*4=0
	sub ebx, ebx			;
	or bl, byte ptr [licznik]	;
	add esi, ebx			;
	lea edi, [eax+offset keyword]	;bufor na keyword
	lea edi, [eax+edi]		;bufor+0
	lodsd				;deszyfrowanie keyword'a
	mov edx, eax			;
	lea eax, [eax]			;eax=eax
	rol edx, 8			;
	ror eax, 8			;
	and edx, 0FF00FFh		;
	and eax, 0FF00FF00h		;
	or eax, edx			;
	xor eax, 1315BE2h		;
	rol eax, 1			;
	stosd				;
	ror eax, 80h			;
	or ax, ax			;
	jz bad				;
	rcl eax, 20h			;
	sub eax, 656D614Eh		;Name - fragment keyword'a
	jnz bad				;
To poczatek deszyfrowania naszego keyword'a. Caly keyword brzmi Nameless Angel In Me. Czyli
mamy juz komplet 1+20+1+15+1+4+20+4=66 bajtow, nasz kompletny plik. Tu wystarczy wyliczyc
bajty, ktore po przejsciach dadza nam staly keyword. Teraz zostalo nam jeszcze crc:
	lodsd				;
	sub crck, eax			;sprawdzenie crc pliku
	jnz bad				;
	sub edx, edx			;
	mov ebx, edx			;
	mov esi, offset uname		;
Zaraz po sprawdzeniu keyword'a sprawdzanie jest crc calego pliku, czyli ostanie 4 bajty.
namecrc:
	movzx eax, byte ptr [esi]	;
	test al, al			;
	jz compcrc			;
	rol eax, 3			;
	sub edx, eax			;
	shrd edx, eax, 9		;
	inc esi				;
	jmp namecrc			;crc z name
Maly mix dla obliczenia crc z name
compcrc:
	mov edi, offset company		;
compcrc2:
	movzx 	eax, byte ptr [edi]	;
	test al, al			;
	jz check_crc			;
	inc eax				;
	xor eax, 897DAC83h		;
	ror eax, 9			;
	add ebx, eax			;
	shld ebx, eax, 5		;
	inc edi				;
	jmp compcrc2			;crc z company
Maly mix dla obliczenia crc z company
check_crc:
	xor edx, ebx			;edx crc
	sub edx, crchex			;crc zapisane w pliku
	jnz bad				;czy poprawne
	add edx, crchex			;do edx crc
	push edx			;
	push offset format		;
	push offset crc			;
	call wsprintfA			;hex2string
Teraz jesli mix(name) xor mix(company) rowny crc zapisanemu w pliku to juz po wszytkim.
Czyli zeby miec poprawny plik musimy zrobic cos takiego:
1 bajt rowny 73h - staly
20 bajtow name - wszystkie musza byc rozne od 00h
1 bajt rowny B4h - staly
15 bajtow company - wszystkie musza byc rozne od 00h
1 bajt rowny 8Eh - staly
4 bajty crc z mix(name) xor mix(company)
20 bajtow keyword'a - stale
4 bajty crc calego pliku
Teraz tylko name szyfrujemy przez odwrotna procke jaka bylo deszyfrowane i to samo z company.
Crc z mixera liczymy tak jak w crackme z nie zaszyfrowanego name i company, na koniec liczymy
crc z pliku i mamy gotowy plik klucz.

	push	41h			;65
	pop	ecx			;

sprawdz:
	test	eax, eax		;czy dobry plik
	jz	brak			;
	dec	ecx			;
	jnz	sprawdz			;tak jak mowilem nudzi mu sie, 65 razy
	push	offset uname		;sprawdza czy plik byl dobry, bez sensu
	push	3			;id name
	push	hWnd			;
	call	SetDlgItemTextA		;name
Tu sa ustawiane wszystkie dane i mamy crackme registered.

Keygen wraz ze zrodlami zalaczony oraz lekko okomentowany dump z idy crackme.

Greetz goes to:
cybult - fajne crackme, ale 3 byla fajniesza, szkoda tylko, ze 256 bit brute force przy bardzo
dlugim i zamotanym algo a i tak nie mam pewnosci, ze da sie policzyc serial
ged_ - no jak znalazles juz grzybki, moze otworzymy jakas plantacje?
Kwasek - moze jak juz zrobiles rekompilke bomb2 to ja zlamiesz, a moze jeszcze rekompilka multi?
Tymon - chyba jestes moim najlepszym dostawca rozwiazan ostatnimi czasy
oraz dla wszystkich ktorzy pisza tutoriale a nie tylko suche keygeny.

Jesli cos ode mnie chcecie to piszcie tom_c4u@o2.pl, najwyzej nie odpisze.
Zapraszam na www.crackmes.prv.pl