Cel	: Impulsy 3.0.2.1
Opis	: Taryfikator polaczen modemowych
URL	:
Tools	: SoftIce,Filemon

Ok jedziemy, program imp jest bardzo uzytecznym programem w czasach
kiedy kazdy czlowiek staje sie niewolnikiem wszechobecnego internetu.

Program jest spakowany aspackiem ale to nie powinno stanowic problemu
...mam nadzieje :)

1.Program nie ma mozliwosci wpisania bezposrednio ani nijak inaczej
name+s/n, ale program jest shareware wiec jest jakas mozliwosc
rejestracji.Przewaznie autorzy stosuja 2 typy rozwiazan
a) program wymaga aby w rejestrze win byly juz zapisane dane
rejestracyjne
b) program wymaga pliku-klucza licencyjnego

W wiec odpalamy regmona i filemona, nastepnie imp.W listingu regmona
nie mozna znalezc nic "podejrzanego" w stylu UserName czy RegCode(choc
nie zawsze trzeba sie sugerowac tym ze program akurat bedzie szukal
wartosci w stylu RegCode moze to byc rownie dobrze ActualXpos...)
natomiast listing filemona wyglada nieco interesujaco
...
Imp32	Open	D:\INET\IMPULSY\IMPSDF30.DAT	NOTFOUND	OPENEXISTING READONLY DENYNONE 	

Program szuka jakiegos pliku w swoim katalogu ale nie moze go znalezc,
wszystkie inne pliki udaje sie mu otworzyc, tylko tego jednego nie ma.

A wiec tworzymy plik IMPSDF30.DAT w katalogu programu, w si zakladamy
pulapke bpx CreateFileA do "d esp->4;p ret;", teraz gdy jakis program
bedzie wywolywal funkcje CreateFileA w oknie danych pokaze nam sie
nazwa pliku ktory ma byc otwarty.Uruchamiamy imp jeszcze raz z tak
zastawiona pulapka i czekamy az program bedzie probowal otworzyc
plik IMPSDF30.DAT.

00449B1A:	call	CreateFileA		; <--proba otwarcia pliku
00449B20:	mov	[ebp][-0004],eax	; uchwyt pliku
00449B23:	cmp	d,[ebp][-0004],0FF	; jesli -1 to nastapil
00449B27:	jne	000449B4C		; blad podczas otwierania
00449B29:	call	GetLastError
00449B2F:	push	eax
00449B30:	call	00044FED0   -------- (2)
00449B35:	add	esp,004 ;""
00449B38:	mov	eax,[ebp][-0014]
00449B3B:	push	eax
00449B3C:	call	000454A10   -------- (3)
00449B41:	add	esp,004 ;""
00449B44:	or	eax,-001 ;""
00449B47:	jmp	000449D45   -------- (4)
00449B4C:	mov	ecx,[ebp][-0004]	; ecx uchwyt pliku
00449B4F:	push	ecx			; zapamietaj uchwyt pliku
00449B50:	call	GetFileType		; w eax typ pliku*
00449B56:	mov	[ebp][-000C],eax
00449B59:	cmp	d,[ebp][-000C],000	; czy to FILE_TYPE_UNKNOWN
00449B5D:	jne	000449B8C		; jesli nie to skacz
00449B5F:	mov	edx,[ebp][-0004]
00449B62:	push	edx			; inaczej zamknij plik
00449B63:	call	CloseHandle ;KERNEL32.dll

Wartosci zwracane przez GetFileType:

FILE_TYPE_UNKNOWN	equ 0			; nieokreslony typ pliku
FILE_TYPE_DISK		equ 1			; normalny plik
FILE_TYPE_CHAR		equ 2
FILE_TYPE_PIPE		equ 3
FILE_TYPE_REMOTE	equ 8000h

Po wyjsciu z tej procki:

00417841:	mov	ecx,[ebp][-0014]
00417844:	push	ecx
00417845:	call	00044A620		; po wyjsciu z tej procedury w eax
0041784A:	add	esp,004			; znajduje sie wartosc okreslajaca dlugosc
0041784D:	cmp	eax,05C			; pliku, sprawdzenie czy plik ma 92bajty
00417850:	je	00041786F
00417852:	mov	d,[00055E228],000000011	; znacznik badboy
0041785C:	mov	edx,[ebp][-0014]
0041785F:	push	edx
00417860:	call	0004496C0
00417865:	add	esp,004 ;""
00417868:	xor	eax,eax
0041786A:	jmp	000417ACA		; wyjscie z procedury sprawdzajacej klucz

A wiec sprawdzana jest dlugosc pliku-klucza, plik klucz musi miec zatem
92(5Ch) bajty,w przeciwnym wypadku program uruchamia sie jako unregistered
a wiec wypelniamy te 92 bajty wartoscia 00h,ponownie uruchamiamy program, tym
razem po porownaniu wielkosci pliku, jestesmy przenoszeni w do nastepnego 
fragmentu kodu:

0041786F:	push	032			; ilosc bajtow
00417871:	push	000576518		; adres gdzie zostanie wczytany
00417876:	mov	eax,[ebp][-0014]	; plik
00417879:	push	eax			; uchwyt
0041787A:	call	0004491E0   -------- (1)
0041787F:	add	esp,00C ;""
00417882:	mov	[ebp][-0010],eax
00417885:	push	002
00417887:	push	00057654A ;" WeJ"
0041788C:	mov	ecx,[ebp][-0014]
0041788F:	push	ecx
00417890:	call	0004491E0   -------- (2)

Program odczytuje plik do bufora(VA=000576518h) w roznych porcjach(92bajty),ale w
normalnej kolejnosci.

0041791F:	movsx	edx,word ptr[00057654C]	; 2bajty spod 57654C
00417926:	test	edx,edx			; czy to 0000h
00417928:	jne	000417947		; jesli !=0 idz dalej
0041792A:	mov	d,[00055E228],000000011	; znacznik badboy
00417934:	mov	eax,[ebp][-0014]
00417937:	push	eax
00417938:	call	0004496C0
0041793D:	add	esp,004 ;""
00417940:	xor	eax,eax
00417942:	jmp	000417ACA		; wyjscie z procedury sprawdzajacej keya

Po odczytaniu calosci pliku program sprawdza 2 bajty spod 57654Ch,
bufor gdzie zostal odczytany plik to 576518h, czyli offset w pliku gdzie
nie powinna znajdowac sie wartosc 0000h to 57654Ch-576518h=34h=52dec.
Jesli pod offsetem 52 w pliku IMPSDF30.DAT mielismy wartosc 0000h zastepujemy
ja dowolna liczba rozna od 0 np.39=27h czyli 27h 00h.Uruchamiamy program
jeszcze raz(mozna tez bezposrednio zmodyfikowac pamiec w si).Test na 0
przechodzimy i jestesmy w:

00417947:	push	000576566		; 576566h-576518h=78dec offset w pliku
0041794C:	call	000448DA0
00417951:	add	esp,004			; nie lepiej pop ebx tylko 1 bajt ;)
00417954:	test	eax,eax			; 0?
00417956:	jne	000417975		; nastepne sprawdzenie

Procedura pod 448DA0 konwertuje liczbe zapisana jako string(dec) na odpowiadajaca
jej wartosc w hexach, wynik jest zwracany w eax.A wiec jesli pod offsetem 78 naszego
pliku klucza zapiszemy string "11" procka zwroci nam wartosc 0Bh w eax.Modyfikujemy
nasz plik klucz zapisujac np "11" pod offsetem 78.Po tej modyfikacji dojdziemy do
nastepnego sprawdzenia

.00417975:	push	000576566		; ten sam offset 78
.0041797A:	call	000448DA0		; na hex
.0041797F:	add	esp,004
.00417982:	cmp	eax,00000E66Bh		; czy string spod 78 to liczba wieksza
.00417987:	jg	0004179A6		; od 58987?Jesli tak nastepne sprawdzenie

Znowu musimy zmodyfikowac plik klucz, tym razem pod offsetem 78 zapisujemy string "58988" :)
Przechodzimy do nastepnego etapu:

004179A6:	push	000576566		; znowu offset 78
004179AB:	call	000448DA0		; tym razem prog sprawdza czy
004179B0:	add	esp,004			; nasza liczba to "42957"
004179B3:	cmp	eax,00000A7CD
004179B8:	jne	0004179CD
004179BA:	mov	eax,[ebp][-0014]
004179BD:	push	eax
004179BE:	call	0004496C0   -------- (3)
004179C3:	add	esp,004 ;""
004179C6:	xor	eax,eax
004179C8:	jmp	000417ACA		; wyjscie z procki badbad
004179CD:	push	000576566 ;" Wef"
004179D2:	call	000448DA0
004179D7:	add	esp,004 ;""
004179DA:	cmp	eax,000003041		; czy nasza liczba to "12353"
004179DF:	jne	0004179F4
004179E1:	mov	ecx,[ebp][-0014]
004179E4:	push	ecx
004179E5:	call	0004496C0   -
004179EA:	add	esp,004 ;""
004179ED:	xor	eax,eax
004179EF:	jmp	000417ACA   -
004179F4:	push	000576566 ;"
004179F9:	call	000448DA0   -
004179FE:	add	esp,004 ;""
00417A01:	cmp	eax,000000910		; czy nasza liczba to "2320"
00417A06:	jne	000417A1B   -

Te sprawdzenia sa bezsensowne poniewaz te trzy liczby sa mniejsze od 58987
i zostalyby wyeliminowane na etapie sprawdzenia czy liczba pod offsetem 78
jest wieksza od 58987.Mozliwe, ze autor chcial kogos zablokowac...Nastepnie:

00417A1B:	mov	w,[ebp][-001C],00000	; tu bedzie wynik
00417A21:	mov	d,[ebp][-0018],000000000; licznik poczatkowy 0
00417A28:	jmps	000417A33--------------------\	; 1raz, nie zwiekaszaj licznika
00417A2A:	mov	eax,[ebp][-0018]             |	; eax licznik
00417A2D:	add	eax,001 ;""                 |	; zwieksz licznik(kompilator chyba nie wiedzial co to inc ;)
00417A30:	mov	[ebp][-0018],eax        <----/
00417A33:	movsx	ecx,w,[00057654C]	; slowo spod offsetu(57654Ch-576518h) 52dec w pliku
00417A3A:	cmp	[ebp][-0018],ecx	; ilosc powtorzen petli zalezy od slowa spod offsetu 52
00417A3D:	jge	000417A57		; wyjscie z petli
00417A3F:	mov	edx,[ebp][-0018]	; licznik
00417A42:	movsx	ax,b,[edx][000576518]	; 576518 zaczynajac od 1 bajtu z pliku klucza pobieraj wartosci
00417A4A:	mov	cx,[ebp][-001C]		; rozszerz o znak
00417A4E:	add	cx,ax			; pobierz ostatnio zapisany wynik,dodaj do siebie
00417A51:	mov	[ebp][-001C],cx		; zapisz wynik
00417A55:	jmps	000417A2A		; powtorz petle word ptr[klucz[52]] razy

Kolejne bajty sa do siebie dodawane uwzgledniajac znak(wartosci od 0-127 traktowane
sa jako dodatnie,128-256 jako ujemne)np.

Przypuscmy, ze w edx mamy wartosc 127 i wykonamy instrukcje movsx ax,dl.Rejestr ah bedzie
okreslal znak bajtu z dl a rejestr al wartosc bajtu z dl

  ax
00  7F
ah  al

ale juz np gdy w dl bedzie wartosc 128 i wykonamy instrukcje movsx ax,dl.
Rejestr ah przyjmie wartosc znaku(w tym przypadku -1 czyli 0FFh), al przyjmie
wartosc z dl,i w ax bedzie wartosc:

FF  80
ah  al
    ^^wartosc 128
^^znak,-1

Trzeba uwazac zeby pod offsetem 52 nie byla zbyt duza wartosc,bo
moze wystapic jakis nieoczekiwany blad.Po wyjsciu z petli:

00417A57:	push	000576566		; (576566h-576518h)=78
00417A5C:	call	000448DA0		; znowu string spod offsetu 78 jest konwertownay na wartosc w hex
00417A61:	add	esp,004 ;""
00417A64:	mov	edx,[ebp][-001C]	; wygenerowany wczesniej w petli wynik
00417A67:	and	edx,00000FFFF ;"  __"	; tylko wartosc word
00417A6D:	cmp	eax,edx			; czy wygenerowany wynik=Str2Hex(klucz[78])
00417A6F:	je	000417A8B		; jesli sa sobie rowne to wychodzimy z procedury z eax=1
00417A71:	mov	d,[00055E228],000000011 ;"
00417A7B:	mov	eax,[ebp][-0014]
00417A7E:	push	eax
00417A7F:	call	0004496C0   -------- (3)
00417A84:	add	esp,004 ;""
00417A87:	xor	eax,eax
00417A89:	jmps	000417ACA		; badboy
00417A8B:	mov	ecx,[ebp][-0014]

Program oblicza sobie na podstawie bajtow(zaczynaja od poczatku pliku-klucza)
pewna wartosc(petla powtarzana jest tyle razy ile wynosi wartosc hex spod
offsetu 52 w naszym pliku-kluczu).Nastepnie jesli wartosc ta zgadza sie z
wartoscia przekonwertowanego ciagu spod offsetu 78 w pliku program uruchamia sie jako full.
Ale jesli spojrzycie na about, zobaczycie ze prog jest licencjonowany dla...krzakow,
osobiscie lubie przyrode ale nie lepiej byloby zobaczyc tam wlasnego nicka?
Przesledzmy wiec dalej procedure(a wiec F12):

00417BE2:	call	0004011AE		; wywolanie procedury sprawdzajacej klucz
00417BE7:	add	esp,004 ;""
00417BEA:	mov	[000576584],eax		; zapisz znacznik rejestracji
00417BEF:	cmp	d,[000576584],000 ;" "
00417BF6:	jne	000417C1F		; skok jesli klucz jest ok
...
00417C1F:	mov	ecx,[00055E224]
00417C25:	mov	[00055E23C],ecx
00417C2B:	movsx	edx,w,[00057654C]	; wartosc hex spod offsetu 52 w pliku kluczu
00417C32:	push	edx
00417C33:	push	000576518		; bufor gdzie zostal wczytany plik klucz
00417C38:	call	00040164F		; <--ciekawe ;)

W srodku 40164F:
004176FA:	push	ebp
004176FB:	mov	ebp,esp
004176FD:	sub	esp,068 ;"h"
00417700:	mov	d,[ebp][-0068],000000000;licznik poczatkowy
00417707:	jmps	000417712
00417709:	mov	eax,[ebp][-0068]
0041770C:	add	eax,001 ;""
0041770F:	mov	[ebp][-0068],eax
00417712:	mov	ecx,[ebp][-0068]
00417715:	cmp	ecx,[ebp][0000C]	; wartosc hex spod offsetu 52 w pliku kluczu
00417718:	jae	000417731
0041771A:	mov	edx,[ebp][00008]	; bufor gdzie zostal wczytany plik klucz
0041771D:	add	edx,[ebp][-0068]	; dodaj licznik=aktualny bajt
00417720:	movsx	eax,b,[edx]		; al=kolejne bajty z bufora
00417723:	not	eax			; not al
00417725:	add	eax,002 ;""		; dodaj 2
00417728:	mov	ecx,[ebp][-0068]
0041772B:	mov	[ebp][ecx][-0064],al	; zapisz tak przekonwertowany bajt
0041772F:	jmps	000417709		; powtorz petle
00417731:	lea	eax,[ebp][-0064]
00417734:	mov	esp,ebp
00417736:	pop	ebp
00417737:	retn

Procka odszyfrowuje bajty zadanego bufora,wywolanie tej procki wyglada nastepujaco

push	lDLugoscCiaguDoOdszyfrowania
push	offset lpCiagDoOdszyfrowania
call	00040164F

w naszym wypadku wywolanie wyglada tak:

push	dword ptr[bufor_gdzie_zostal_odczytany_klucz[52]]
push	offset bufor_gdzie_zostal_odczytany_klucz
call	00040164F

Latwo(?) sie domyslec ze slowo spod offsetu 52 w pliku kluczu stanowi
dlugosc,ale czego,no podpowiem nazwy licencjonowanego uzytkownika.

Szukajac "podejrzanych" stringow natknalem sie na takie cosik

'Lpqjb.qjsbdlb',0

jak sobie zmniejszycie o 1 wartosc kazdego bajtu z tego ciagu to otrzymacie text

'Kopia-piracka',0

0041EB6A:	mov	d,[ebp][-0008],00000001C	; zapamietaj wartosc 1Ch
0041EB71:	mov	d,[ebp][-0020],000000022
0041EB78:	mov	eax,[ebp][-0008]	; eax == 1C
0041EB7B:	sub	eax,001 ;""		; zmniejsz eax == 1B
0041EB7E:	mov	[ebp][-0008],eax	; znowu zapamietaj
0041EB81:	push	0005603E8		; offset 'Lpqjb.qjsbdlb',0
0041EB86:	lea	ecx,[ebp][-001C]
0041EB89:	push	ecx
0041EB8A:	call	000448FF0
0041EB8F:	add	esp,008 ;""
0041EB92:	mov	edx,[ebp][-0008]	; wartosc 1Bh
0041EB95:	sub	edx,[00055E228]		; 0
0041EB9B:	mov	[ebp][-0008],edx	; zapamietaj
0041EB9E:	lea	eax,[ebp][-001C]
0041EBA1:	push	eax			; offset 'Lpqjb.qjsbdlb',0
0041EBA2:	call	00044A0D0		; pobierz dlugosc ciagu
0041EBA7:	add	esp,004 ;""		; rownaj stos
0041EBAA:	mov	[ebp][-0004],eax	; zapamietaj dlugosc
0041EBAD:	mov	d,[ebp][0FFFFFBF4],000000000
0041EBB7:	jmps	00041EBC8   -------- (3)
...
0041EBC8:	mov	edx,[ebp][0FFFFFBF4]	;
0041EBCE:	cmp	edx,[ebp][-0004]	;
0041EBD1:	jae	00041EBEC   -------- (1);
0041EBD3:	mov	eax,[ebp][0FFFFFBF4]	;
0041EBD9:	mov	cl,[ebp][eax][-001C]	;
0041EBDD:	sub	cl,001 ;""		; procka deszyfrujaca
0041EBE0:	mov	edx,[ebp][0FFFFFBF4]	;
0041EBE6:	mov	[ebp][edx][-001C],cl	;
0041EBEA:	jmps	00041EBB9   -------- (2);

0041EBEC:	mov	eax,[ebp][-0004]
0041EBEF:	mov	b,[ebp][eax][-001C],000
0041EBF4:	cmp	d,[000576584],000	; sprawdz znacznik rejestracji
0041EBFB:	je	00041EC4C		;
0041EBFD:	movsx	ecx,b,[000576518]	; pobierz 1 bajt z user name(juz rozszyfrowanego)
0041EC04:	test	ecx,ecx			; czy to 00h
0041EC06:	je	00041EC4C		; jesli to 00h to cos jest nie tak
0041EC08:	movsx	edx,b,[000576518]	; pobierz 1 bajt z user name(juz rozszyfrowanego)
0041EC0F:	cmp	edx,020			; czy to spacja(20h)
0041EC12:	je	00041EC4C		; jesli tak to bledny klucz
0041EC14:	cmp	d,[ebp][-0008],000	; jesli wartosc != 0
0041EC18:	je	00041EC25		; pokaz info Kopia-piracka

Pod 41EBF4h sprawdzany jest znacznik rejesteracji,jesli jest rowny 0
to w About zobaczymy text "Ta kopia nie zostala zarejestrowana"
Pod 41EBFDh pobierany jest pierwszy bajt z rozszyfrowanego user name
jesli jest rowny 00h lub jest to spacja(20h)to rowniez w about zostanie wyswietlony text
,ze ta kopia nie zostala zarejestrowana.


Tworzenie pliku-klucza:
=======================
1.Tworzymy plik 92bajtowy(wypelniony 00h wazne!)
2.Pod offsetem 52dec zapisujemy w postaci word dlugosc nazwy
lic uzytkownika
3.Nazwe uzytkowanika kopiujemy na poczatku pliku-klucza
4.Nazwe uzytkownika szyfrujemy wg algorytmu

	mov	edx,offset lpKlucz
	movzx	ecx,word ptr[lpKlucz+52]

	sub	eax,eax
@crypt_user_name:
	mov	al,[edx]
	dec	eax
	dec	eax
	not	eax
	mov	[edx],al
	inc	edx
	loop	@crypt_user_name

5.Na podstawie zaszyfrowanego user name obliczamy pseudo sume kontrolna wg:
	mov	edx,offset lpKlucz
	movzx	ecx,word ptr[lpKlucz+52]
	sub	eax,eax
	sub	ebx,ebx
@make_crc:
	movsx	ax,byte ptr[edx]
	add	ebx,eax
	inc	edx
	loop	@make_crc

	cmp	ebx,58987		; warunek sprawdzany przez program
	jbe	@wrong_name

5.Obliczona wartosc zamieniamy na string(na postac dziesietna)
6.Przekonwertowana wartosc w postaci stringa kopiujemy pod offset 78 w pliku
7.Tak spreparowany plik klucz umieszczamy w katalogu z programem
8.Uruchamiamy progsa,about i powinno byc ok jesli tylko postepowaliscie zgodnie
z moimi wskazowkami :))




PS.W zalaczeniu keygen


bart^CrackPl
cryogen@free.net.pl