Data	: 19.01.2oo1
Cel	: TagGen 4.5
URL	: http://www.hisoftware.com
Opis	: 
Toolz	: SoftIce,IDA

Program umozliwia wprowadzenie danych rejestracyjnych juz na samym
starcie, wpisujemy wiec nasz imie, firme i numer rejestracyjny,
bpx hmemcpy i sledzimy ale nie bede omalwial calego procesu dochodzenia
do checka tylko zajme sie sama procedura sprawdzajaca poprawnosc seriala.
Procedura ta jest zaszyta w bibliotece ShrLk21.dll ktora jest kopiowana
do windows\system po zainstalowaniu proga.

00444BC2	mov	eax, [ebp+var_4]	; serial
00444BC5	call	get_str_length		; pobierz rozmiar stringa
00444BCA	cmp	eax, 14			; jesli serial < 14 znakow bad boy
00444BCD	jl	loc_444CBD
00444BD3	lea	edx, [ebp+var_18]
00444BD6	mov	eax, [ebp+var_4]
00444BD9	call	str_upper		; serial do upper case
00444BDE	mov	edx, [ebp+var_18]
00444BE1	lea	eax, [ebp+var_4]
00444BE4	call	@System@@LStrLAsg$qqrv ; System __linkproc__ LStrLAsg(void)
00444BE9	mov	eax, [ebp+var_4]	; wskaznik do seriala
00444BEC	mov	bl, [eax+1]		; 2 bajt z seriala
00444BEF	mov	eax, [ebp+var_4]	; wskaznik do seriala
00444BF2	mov	al, [eax+4]		; 5 bajt z seriala
00444BF5	mov	[ebp+var_11], al	; zapisz ten bajt
00444BF8	mov	eax, [ebp+var_4]	; wskaznik do seriala
00444BFB	mov	al, [eax+5]		; 6 bajt z seriala
00444BFE	mov	[ebp+var_12], al	; zapisz ten bajt

00444C01	lea	eax, [ebp+var_4]	; wskaznik do wskaznika ciagu
00444C04	mov	ecx, 1			; ilosc bajtow do wyciecia
00444C09	mov	edx, 2			; pozycja(liczac od 1)
00444C0E	call	@System@@LStrDelete$qqrv ; System __linkproc__ LStrDelete(void)
00444C13	lea	eax, [ebp+var_4]	; "obciety" string
00444C16	mov	ecx, 1
00444C1B	mov	edx, 4
00444C20	call	@System@@LStrDelete$qqrv ; System __linkproc__ LStrDelete(void)
00444C25	lea	eax, [ebp+var_4]
00444C28	mov	ecx, 1
00444C2D	mov	edx, 4
00444C32	call	@System@@LStrDelete$qqrv ; System __linkproc__ LStrDelete(void)

Najpierw sprawdzane jest czy dlugosc wprowadzonego seriala jest
mniejsza niz 14 znakow, potem pobierane sa odpowiednio 2,5 i 6 bajt
z seriala, bajty 5 i 6 zostaja zapisane do tymczasowych buforow,
nastepnie z seriala zostaja "skasowane" bajty wlasnie na pozycjach
2,5 i 6, jedziemy dalej:

00444C37	xor	eax, eax
00444C39	mov	al, bl			; w bl 2 znak z seriala
00444C3B	sub	eax, 41h		; odejmij bajt 41h czyi "A"
00444C3E	imul	eax, 1Ah		; *1Ah
00444C41	xor	edx, edx
00444C43	mov	dl, [ebp+var_11]	; 5 bajt seriala
00444C46	sub	edx, 41h		; ponownie odejmij "A"
00444C49	add	eax, edx		; dodaj do siebie
00444C4B	mov	edx, [ebp+arg_0]
00444C4E	mov	[edx], eax		; zapisz
00444C50	xor	ebx, ebx
00444C52	lea	edx, [ebp+var_10]
00444C55	mov	eax, ds:dword_44A874
00444C5A	call	str_upper		; ciag "rob2000" do upper case
00444C5F	mov	eax, [ebp+var_10]
00444C62	call	get_str_length
00444C67	test	eax, eax
00444C69	jle	short loc_444C7E
00444C6B	mov	edx, 1
00444C70 
00444C70 loc_444C70:
00444C70	mov	ecx, [ebp+var_10]
00444C73	movzx	ecx, byte ptr [ecx+edx-1]
00444C78	add	ebx, ecx		; sumuj bajty ciagu "ROB2000"
00444C7A	inc	edx
00444C7B	dec	eax
00444C7C	jnz	short loc_444C70

00444C7E	lea	edx, [ebp+var_1C]
00444C81	mov	eax, [ebp+var_8]
00444C84	call	str_upper		; name do upper case
00444C89	mov	eax, [ebp+var_1C]
00444C8C	lea	ecx, [ebp+var_18]
00444C8F	mov	edx, ebx
00444C91	call	sub_445450		; ???
00444C96	mov	edx, [ebp+var_18]
00444C99	mov	eax, [ebp+var_4]
00444C9C	call	@System@@LStrCmp$qqrv ; System __linkproc__ LStrCmp(void)
00444CA1	jnz	short loc_444CA9

Program pobiera 2 i 5 bajt z seriala, od 2 odejmuje 41h i mnozy razy
0Ah, od 5 rowniez odejmuje 41h i do tego dodaje wynik operacji
przeprowadzonych na 2 bajcie, wynik zostaje zapisany, nastepnie
liczona jest suma bajtow z stringa "ROB2000" i wynik sumowania jest
umieszczony w rejestrze ebx.Po wyliczeniu sumy nastepuje skok do
procki pod 445450:

00445450	push	ebp
00445451	mov	ebp, esp
...
0044547A	mov	eax, [ebp+var_4]	; name
0044547D	call	get_str_length		; pobierz dlugosc
00445482	test	al, al			; jesli 0 wyjdz
00445484	jbe	short loc_4454CF
00445486	mov	[ebp+var_5], al		; zapisz dlugosc name
00445489	mov	bl, 1
0044548B 
0044548B loc_44548B:
0044548B	lea	eax, [ebp+var_C]
0044548E	xor	edx, edx
00445490	mov	dl, bl
00445492	mov	ecx, [ebp+var_4]
00445495	mov	dl, [ecx+edx-1]		; kolejne bajty z name
00445499	movzx	ecx, si			; w esi jest suma bajtow z "ROB2000"
0044549C	shr	ecx, 8			; przesun 8 bitow w prawo
0044549F	xor	dl, cl			; bajt z name xor (suma shr 8)
004454A1	call	unknown_libname_29
004454A6	mov	edx, [ebp+var_C]
004454A9	mov	eax, edi
004454AB	call	@System@@LStrCat$qqrv ; System __linkproc__ LStrCat(void)
004454B0	xor	eax, eax
004454B2	mov	al, bl
004454B4	mov	edx, [edi]		; pobierz zxorowany bajt
004454B6	movzx	eax, byte ptr [edx+eax-1]
004454BB	add	si, ax			; dodaj ten bajt do sumy w si
004454BE	imul	ax, si, 0AD9Ch		; suma*0AD9Ch
004454C3	add	ax, 56CEh		; suma+056CEh
004454C7	mov	esi, eax		; zapisz ponownie do esi
004454C9	inc	ebx
004454CA	dec	[ebp+var_5]		; zmniejsz licznik bajtow name
004454CD	jnz	short loc_44548B	; czy juz wszystkie?
004454CF 
004454CF loc_4454CF:
004454CF	lea	edx, [ebp+var_C]
004454D2	mov	eax, [edi]
004454D4	call	sub_445340		; ???
004454D9	mov	edx, [ebp+var_C]
004454DC	mov	eax, edi
004454DE	call	@System@@LStrLAsg$qqrv ; System __linkproc__ LStrLAsg(void)
004454E3	xor	eax, eax
004454E5	pop	edx
004454E6	pop	ecx
004454E7	pop	ecx
004454E8	mov	fs:[eax], edx
004454EB	push	offset loc_445500
004454F0 
004454F0 loc_4454F0:
004454F0	lea	eax, [ebp+var_C]
004454F3	call	@System@@LStrClr$qqrr17System@AnsiString ; System __linkproc__ LStrClr(System::AnsiString &)
004454F8	retn

Sytuacja wyglada tak, program wykorzystuje sume bajtow wyliczona z 
rob-a do zaszyfrowania user name, po zakonczeniu petli, wywolywana
jest jeszcze funkcja ktora konwertuje zaszyfrowane bajty do znakow
ascii tylko, ze konwertowane znaki sa "nieco" rozne od ich odpowiednikow
w hex-ach, zeby zobaczyc dlaczego wystarczy zajrzec do procki pod
445340:

004453AB loc_4453AB:
004453AB	xor	eax, eax
004453AD	mov	al, [ebp+var_5]
004453B0	mov	edx, [ebp+var_4]
004453B3	xor	ebx, ebx
004453B5	mov	bl, [edx+eax-1]		; kolejne bajty zaszyfrowanego name
004453B9	shr	ebx, 4			; hi-->lo nibble
004453BC	add	bl, 31h			; dodaj 31h("1")
004453BF	cmp	bl, 39h			; sprawdz czy to cyfra
004453C2	jbe	short loc_4453C7	; jesli tak zapisz ja
004453C4	add	bl, 7			; dodaj 7 aby zamienic na znak A..F
004453C7 
004453C7 loc_4453C7:
004453C7	lea	eax, [ebp+var_C]
004453CA	mov	edx, ebx
004453CC	call	unknown_libname_29
004453D1	mov	edx, [ebp+var_C]
004453D4	mov	eax, esi
004453D6	call	@System@@LStrCat$qqrv ; System __linkproc__ LStrCat(void)
004453DB	xor	eax, eax
004453DD	mov	al, [ebp+var_5]	
004453E0	mov	edx, [ebp+var_4]
004453E3	mov	bl, [edx+eax-1]		; ten sam bajt co wyzej
004453E7	and	bl, 0Fh			; zostaw low nibble
004453EA	add	bl, 31h			; dodaj 31h("1")
004453ED	cmp	bl, 39h			; jesli to cyfra zapisz ja
004453F0	jbe	short loc_4453F5
004453F2	add	bl, 7			; inaczej dodaj 7
004453F5 
004453F5 loc_4453F5:
004453F5	lea	eax, [ebp+var_C]
004453F8	mov	edx, ebx
004453FA	call	unknown_libname_29

Standardowo aby przekonwertowac hex-->ascii po wyszczegolnieniu
low i hi nibble dodaje sie bazowa wartosc 30h("0") i potem dodaje
sie 7 w zaleznosci czy po dodaniu 30h wynik to cyfra, tutaj autor
zastosowal takie rozwiazanie, ktore wyklucza znalezienie sie
w serialu bajtow "0".Po wyjsciu z tej i poprzedniej procki jestesmy
w kodzie glownym:

00444C91	call	sub_445450		; tu juz bylismy
00444C96	mov	edx, [ebp+var_18]	; porownaie naszego obcietego
00444C99	mov	eax, [ebp+var_4]	; seriala i wyliczonego
00444C9C	call	@System@@LStrCmp$qqrv ; System __linkproc__ LStrCmp(void)
00444CA1	jnz	short loc_444CA9	; skok do bad boy
00444CA3	mov	eax, [ebp+var_C]
00444CA6	mov	byte ptr [eax], 1
00444CA9 
00444CA9 loc_444CA9:
00444CA9	mov	eax, [ebp+arg_0]	; tutaj byl zapisanyw wynik odejmowania
						; od 2 i 5 znaku 41h
00444CAC	cmp	dword ptr [eax], 0	; jesli !=0 skok bad boy
00444CAF	jnz	short loc_444CBD
00444CB1	cmp	[ebp+var_12], 'C'	; sprawdz czy 6 bajt to 'C'
00444CB5	jz	short loc_444CBD	; skok do good boy
00444CB7	mov	eax, [ebp+var_C]
00444CBA	mov	byte ptr [eax], 0	; znacznik niezarejestrowania
00444CBD 
00444CBD loc_444CBD:
00444CBD	xor	eax, eax

Po wygenerowaniu poprawnego seriala, jest on porownywany z prowadzonym
przez usera(ale z wykasowanymi bajtami 2,5 i 6), jesli te ciagi sa takie
same sprawdzane jest czy wynik operacji

((2 bajt-41h)*8)+(5 bajt-41h)=0?		; jesli 2 i 5 bajt to "A"
						; operacja da 0 w wyniku

jesli wynik jest rowny 0 to nastepuje ostatnie sprawdzenie, czy 6 bajt
seriala to znak 'C' jesli tak program podziekuje za rejestracje i poprosi
o restart.Po wygenerowaniu seriala nalezy wstawic(nie nadpisac!) na 2
i 5 pozycje bajty ktore spelnia warunek "A", na 6 pozycje w serialu
wstawic "C" i voila :)


bart^CrackPl
cryogen@box43.pl
