Dongle reverse engineering
Hasp dongles

by Zafer/BSCA
(03 September 1997)
(Part C added 19 Oct 1997)

Well, it was about time that somebody explained the vagaries of dongle reverse engineering... (even if, for now, this tutorial looks more like a technical specification of the various hasp-dongle services :(
Important stuff, as you wil see. Anyway I must confess that I never used a program with a dongle, and all I knew (before reading these essays) was that you had to intercept the I/O calls to the dongle parallel port, or, more precisely, fake the return codes... well, as you'll see reading this very good tutorial by Zafer, one never ends learning!

This tutorial is under development, Zafer has promised to send the remaining parts asap... (dear readers, you are the first in the world to surf onto such stuff :-)


A tutorial on dongles reverse engineering


by Zafer, September 1997

A) introduction to HASP.

B) let's do it (dos).

C) let's do it (Win).

D) tips & tricks.


INTRODUCTION TO HASP



 These essay series only covers hasp dongle protection (anyway, i  didn't see

 too many applications using something other than hasp or sentinel)... sentinel 

 dongles are also an important topic that we must take care of.



 ok. lets start learning some facts about the hasp family



# HASP-3

--------

Cheapest hasp dongle.



# MemoHASP

----------

There are two different memohasp's.. memohasp-1 which has 112 bytes read/write memory and

memohasp-4 which has 496 bytes read/write memory (496 bytes.. argghh)



# NetHASP

---------

NetHASP is infact memohasp-4 and by connecting only one hasp to a network station, you can 

run it from all stations.. (limited users) It has 496 bytes read/write memory



# TimeHASP

----------

These dongles contains internal realtime clock. There are two different timehasp's

timehasp has 16 bytes read/write memory, timehasp-4 has 512 bytes read/write memory



# 36 series

-----------

HASP 36pin (centronics) versions of HASP.



# HASPCard

----------

It allows you to put dongle(s) inside the computer.. 



note: HASP dongles uses d0-d7, init, atfdxt, pe lines ("#36 series" uses d0-d7, busy)



0 Hasp Protection Methods



0.1 Hasp Envelope

	This is just a envelope applied to the executable files..



0.1.1 HASP Error Level Codes

	1 Hasp not found

	2 Illegal HASP 

	3 Program is modified

	4 No Authorization

	5 Out of runtimes

	6 No answer from NetHasp Licence Manager (Nethasp only)

	7 Too many users (Nethasp only)

	8 Runtime expired (TimeHasp only)



0.2 API

	The api (obj or dll) program can check for the presence (or absence) of

the dongle and respond as you wish. And you can gain moreover access to the 

dongle's memory.



0.2.1 Resident hasp driver

        It's a tsr which provides the same hasp services as the API.

 "haspres" is the program. the default interrupt is int 63h, but it can

 be loaded as "haspres xx" where xx is the int #.





-------------------------------------------------

1. Hands on API



 Hasp (Service, SeedCode/IdleTime, LptNum/ProgNum, Password1, Password2, Par1, Par2, Par3, Par4)

 usage for asm:



call:	bh=service

	ax=SeedCode/IdleTime

	bl=LptNum/ProgNum

	cx=Password1

	dx=Password1

	di=address

	si=data

	es=buffer segment (for functions Read/WriteBlock, Set* ; ax=buffer offset)

	



return:	ax=Par1

	bx=Par2

	cx=Par3

	dx=Par4



1.1 Service

  Service    	Name 		Operation

-------------------------------------------------------------------------

    	 1	IsHasp		Checks if a Hasp is connected



returns 	Par1 		0 no hasp

				1 HASP of any type

-------------------------------------------------------------------------

	 2	HaspCode	Gets the return codes for a given seed code.



returns 	Par1/2/3/4	Return Code1/2/3/4

-------------------------------------------------------------------------

	 3	ReadWord	Reads 1 word from MemoHasp



returns		Par2		1 word

		Par3		Status (read Status below)

-------------------------------------------------------------------------

	 4	WriteWord	Writes 1 word to MemoHasp



returns		Par3		Status (read Status below)

-------------------------------------------------------------------------

	 5	HaspStatus	Checks the type of Hasp	

				Checks which port its connected to.

				Checks to memory size.



returns		Par1		1 MemoHasp-1

				4 MemoHasp-4	

				0 Other Types

		Par2		0 HASP-3

				1 MemoHasp-1/MemoHasp-4

				3 TimeHasp

				5 TimeHasp-4

		Par3		Paralel port #

-------------------------------------------------------------------------

	 6	HaspID		Gets Hasp ID #





returns		Par1		Low word of ID #

		Par2		High word of ID #

		Par3		Status (read Status below)

-------------------------------------------------------------------------

	40	LastStatus	Checks the status of the last call to NetHasp



returns		Par1		NetStatus

				0 last call was successful

				otherwise its status (read Status below)

		Par2		SystemError (a context-dependent errorcode)

-------------------------------------------------------------------------

	41	HaspCode	Get the return codes for a given seed code. (NetHasp)



call		SeedCode	SeedCode (0-65535)

		ProgNum	Number assigned to the application in NetHasp

		Password1	First NetHASP password

		Password2	Second NetHASP password



returns		Par1/2/3/4	Return Code 1/2/3/4

-------------------------------------------------------------------------

	42	Login		Requests permission from NetHasp Licence Manager



call		SeedCode	SeedCode (0-65535)

		ProgNum	Number assigned to the application in NetHasp

		Password1	First NetHASP password

		Password2	Second NetHASP password



returns		Par1/2/3/4	Return Code 1/2/3/4

-------------------------------------------------------------------------

	43	Logout		Requests session termination from NetHasp Licence Manager



call		ProgNum	Number assigned to the application in NetHasp

		Password1	First NetHASP password

		Password2	Second NetHASP password

-------------------------------------------------------------------------

	44	ReadWord	Reads 1 word from NetHasp



call		SeedCode	SeedCode (0-65535)

		ProgNum	Number assigned to the application in NetHasp

		Password1	First NetHASP password

		Password2	Second NetHASP password

		Par1		Address (NetHASP mem address 00-247)



returns		Par2		Data

		Par3		Status (read Status below)

-------------------------------------------------------------------------

	45	WriteWord	Writes 1 word to NetHasp



call		SeedCode	SeedCode (0-65535)

		ProgNum	Number assigned to the application in NetHasp

		Password1	First NetHASP password

		Password2	Second NetHASP password

		Par1		Address (NetHASP mem address 00-247)

		Par2		Data



returns		Par3		Status (read Status below)

-------------------------------------------------------------------------

	46	HaspID		Gets NetHasp ID #



call		ProgNum	Number assigned to the application in NetHasp

		Password1	First NetHASP password

		Password2	Second NetHASP password



returns		Par1		IDLow (low word if ID #)

		Par2		IDHigh (high word if ID #)

		Par3		Status (read Status below)



Note: ID #=IDLow+65536*IDHigh (idlow,high are unsigned)

-------------------------------------------------------------------------

	48	idleTime	Specifys a max time frame for idle stations (NetHasp)



call		IdleTime 	(time frame in minutes 0-65535)

		ProgNum	Number assigned to the application in NetHasp

		Password1	First NetHASP password

		Password2	Second NetHASP password

-------------------------------------------------------------------------

	50	ReadBlock	Reads a block from MemoHasp



call		Par1		Start Address 

				Defines the initial HASP mem address for reading block

				0-55 = MemoHasp-1

				0-247= MemoHasp-4

				0-247= TimeHasp-4

		Par2		Block Length (Block size in words)

		Par3		Buffer Segment (Segment address of a variable/address)

		Par4		Buffer Offset  (Offset address of a variable/address)



returns		Par3		Status (read Status below)

-------------------------------------------------------------------------

	51	WriteBlock	Writes a block to MemoHasp



call		Par1		Start Address 

				Defines the initial HASP mem address for writing block

				0-55 = MemoHasp-1

				0-247= MemoHasp-4

				0-247= TimeHasp-4

		Par2		Block Length (Block size in words)

		Par3		Buffer Segment (Segment address of a variable/address)

		Par4		Buffer Offset  (Offset address of a variable/address)



returns		Par3		Status (read Status below)

-------------------------------------------------------------------------

	52	ReadBlock	Reads a block from NetHasp



call		ProgNum	Number assigned to the application in NetHasp

		Password1	First NetHASP password

		Password2	Second NetHASP password

		Par1		Start Address 

				Defines the initial NetHASP mem address for reading block

				(0-247)

		Par2		Block Length (Block size in words) (max 24words)

		Par3		Buffer Segment (Segment address of a variable/address)

		Par4		Buffer Offset  (Offset address of a variable/address)



returns		Par3		Status (read Status below)

-------------------------------------------------------------------------

	53	WriteBlock	Writes a block to NetHasp



call		ProgNum	Number assigned to the application in NetHasp

		Password1	First NetHASP password

		Password2	Second NetHASP password

		Par1		Start Address 

				Defines the initial NetHASP mem address for writing block

				(0-247)

		Par2		Block Length (Block size in words) (max 24words)

		Par3		Buffer Segment (Segment address of a variable/address)

		Par4		Buffer Offset  (Offset address of a variable/address)



returns		Par3		Status (read Status below)

-------------------------------------------------------------------------

	70	SetTime		Sets TimeHasp clock



call		Password1	first timehasp password

		Password2	second timehasp password

		Par1		Second

		Par2		Minute

		Par4		Hour (00-23)



returns		Par3		Status (read Status below)

-------------------------------------------------------------------------

	71	GetTime		Gets TimeHasp time



call		Password1	first timehasp password

		Password2	second timehasp password



returns		Par1		Second

		Par2		Minute

		Par3		Status (read Status below)

		Par4		Hour (00-23)

-------------------------------------------------------------------------

	72	SetDate		Sets TimeHasp date



call		Password1	first timehasp password

		Password2	second timehasp password

		Par1		Day

		Par2		Month

		Par4		Year (00-99)



returns		Par3		Status (read Status below)

-------------------------------------------------------------------------

	73	GetDate		Gets Timehasp date	



call		Password1	first timehasp password

		Password2	second timehasp password



returns		Par1		Day

		Par2		Month

		Par3		Status (read Status below)

		Par4		Year (00-99)

-------------------------------------------------------------------------

	74	WriteByte	Writes 1 byte to TimeHasp		



call		Password1	first timehasp password

		Password2	second timehasp password

		Par1		Address (mem address of TimeHasp 00-15)

		Par2		Data



returns		Par3		Status (read Status below)

-------------------------------------------------------------------------

	75	ReadByte	Reads 1 byte from TimeHasp



call		Password1	first timehasp password

		Password2	second timehasp password

		Par1		Address (mem address of TimeHasp 00-15)



returns		Par2		Data

		Par3		Status (read Status below)

-------------------------------------------------------------------------

	76	WriteBlock	Writes a block to TimeHasp



call		Password1	first timehasp password

		Password2	second timehasp password

		Par1		Start Address 

				Defines the initial TimeHASP mem address for writing block

				(00-15)

		Par2		Block Length (Block size in bytes)

		Par3		Buffer Segment (Segment address of a variable/address)

		Par4		Buffer Offset  (Offset address of a variable/address)



returns		Par3		Status (read Status below)



Note: this service only writes the first 16 bytes of TimeHasp, to write a block

      to 248word mem of TimeHasp-4, use service 51.

-------------------------------------------------------------------------

	77	ReadBlock	Reads a block from TimeHasp



call		Password1	first timehasp password

		Password2	second timehasp password

		Par1		Start Address 

				Defines the initial TimeHASP mem address for reading block

				(00-15)

		Par2		Block Length (Block size in bytes)

		Par3		Buffer Segment (Segment address of a variable/address)

		Par4		Buffer Offset  (Offset address of a variable/address)



returns		Par3		Status (read Status below)



Note: this service only reads the first 16 bytes of TimeHasp, to read a block

      to 248word mem of TimeHasp-4, use service 50.

-------------------------------------------------------------------------

	78	GetHaspID	Gets TimeHasp ID #



call		Password1	first timehasp password

		Password2	second timehasp password



returns		Par1		IDLow (low word if ID #)

		Par2		IDHigh (high word if ID #)

		Par3		Status (read Status below)



Note: ID #=IDLow+65536*IDHigh (idlow,high are unsigned)

-------------------------------------------------------------------------

	85	SetConfigName	Sets the name of NetHasp conf. file 

call		Par2		BufferSize (byte size of buffer containing the name

				of NetHasp conf. file)

		Par3		Buffer Segment (Segment address of the buffer containing

				the name of the NetHasp conf. file)

		Par4		Buffer Offset  (Offset address of the buffer containing

				the name of the NetHasp conf. file)

-------------------------------------------------------------------------

	96	SetServerName	Sets the name of Nethasp Licence Manager to which

				the protected progie will perform a NetHasp Login 

call		Par2		BufferSize (byte size of buffer containing the name

				of NetHasp Licence Manager)

		Par3		Buffer Segment (Segment address of the buffer containing

				the name of the NetHasp Licence Manager)

		Par4		Buffer Offset  (Offset address of the buffer containing

				the name of the NetHasp Licence Manager)

-------------------------------------------------------------------------

1.2 SeedCode



1.3 LptNum

	0 		searches all ports

	1/2/3 		checks lpt1/lpt2/lpt3

	101/102/103 	checks 3bc/378/278   ;(ports you'll have to bpio onto :-)



1.4/5 	Password 1/2





1.6/7/8 Par(ameters) 1/2/3



1.9 Status Codes



1.9.1 HASP-3, MemoHASP, TimeHASP-4, NetHASP



	 0 Successful

	-1 TimeOut (unsuccessful write operation)

	-2 Address is out of range

	-3 Hasp with the specified password was not found

	-4 Hasp was found but it's not MemoHASP

	-5 Unsuccessful write operation

      -999 Invalid service



1.9.2 TimeHASP, TimeHASP-4



	0 Successful

      -20 Invalid day

      -21 Invalid month

      -22 Invalid year

      -23 Invalid seconds

      -24 Invalid minutes

      -25 Invalid hours

      -26 Invalid address (not in range of 0-15)

      -27 TimeOut (unsuccessful write operation)

      -28 Hasp not found

      -29 Hasp was found but it's not TimeHASP



1.9.3 HASP Device Drivers



	-100 Can't open HASP device driver (win32)

	-101 Can't read HASP device driver (win32)

	-102 Can't close HASP device driver (win32)

	-110 Can't open HASP device driver (dos, dos extender, win)

	-111 Can't read HASP device driver (dos, dos extender, win)

	-112 Can't close HASP device driver (dos, dos extender, win)

	-120 Can't allocate DOS memory (dos, dos extender, win protected with stand-alone keys)

	-121 Can't deallocate DOS memory (dos, dos extender, win protected with stand-alone keys)



1.9.4 NetHASP LastStatus



	0 Successful

--Errors which occurs in communication between proggie and NetHASP 

   Licence Manager Or by the parameters you passed to the routine--

	1 IPX, NetBios, TCP/IP protocols haven't installed properly

	2 Communication error (unable to get socket number)	

	3 Communication error

	4 No NetHASP licence manager found

	5 Cannot read the NetHASP licence manager address file

	6 Cannot close the NetHASP licence manager address file

	7 Communication error (failed to send packet)

	8 No Answer from NetHASP licence manager

	10 You didn't call Login Service yet

	11 Communication error (adapter error)

	15 No active NetHASP licence manager found	

	18 Can't perform Login because of an unsuccessful SetServerName call

	19 Syntax error in conf. file (line # returns in Par2, if 0 then there is

                   an enviroment variable with an illegal setting)

	20 Error handling conf. file (system error code in Par2) 

	21 Couldn't allocate memory

	22 Couldn't deallocate memory

	23 Invalid NetHASP mem address

	24 Invalid NetHASP service

	25 Failed to load winsock.dll

	26 Failed to unload winsock.dll

	28 winsock.dll startup error

	40 NetHASP services are not supported



	--Errors which occurs after the client-server communication has been established--

	129 Correct NetHASP is not connected.

	130 ProgNum isn't in the ProgList of NetHASP mem

	131 Error reading from NetHASP mem

	132 Error writing to NetHASP mem

	133 Login request exceeds the # of stations (limited user)

	134 Login request exceeds the # of activations for progie

	135 Logout was called before calling login

	136 NetHASP license manager is busy.

	137 No space in NetHASP log table

	138 Internal NetHASP error (# of licensed stations is larger than allowed by NetHASP)

	139 Computer with NetHASP crached & reactivated (must call login again)

	140 NetHASP license manager does not serve the network of your station

	141 Invalid service

	142 NetHASP license manager matching the name specified in NetHASP conf. file not found

	150 No NetHASP license manager with the assigned name was found

	151 Two or more different NetHASP license managers with the assigned name were found





2.0 Things to remember



        - there can be more than one seedcode

	- it can be checking dongle with dummy passwords to confuse you

	- it can be using the return code as seed for encryption/variable

	- read xoanon's doc. (delaying reactions 

                to a checking)

	- in the dongles memory, program can store a routine, jumptables, seeds

	  for a decryption etc.. (you may need the dongle itself in order to crack the 

                dongle at %100)



Let's do it (DOS)



Second and third part will be ready asap, part four is (partly) already there





Let's do it (Windows)




Part C, added 19 Oct 1997


A introduction to hasp

B let's do it

C ------------------------------ LET'S DO IT (WIN) 

------------------------

D tips & tricks. 





	ok. when writing this doc, i searched some `common` programs to give as

examples but there were no programs given to `public` via ftp/www.



        so, as my target i chose several different programs from local

companies.



1) Our first Victim "Cevirmen"

 Cevirmen translates english-2-turkish, and seems to use Hasp3.



 As i got the program, what i did to crack was using my "Trick1". 

I plugged my leds to the parallel port, and ran the program. Then a 

firmwindow popped up.

I pressed ok and saw my leds flashing. then menu came and i loaded a 

txt, then pressed "Automatic Translation". (but nothing happened.)



	so, i ldr'ed the program, and traveled throu' the code with f10/f8.

soon after the show_firmwindow call, i saw my leds flashing again. :))

looking after the call, i saw some cmp's. Now i knew which call made the 

dongle check.



	next, i loaded the program with ida 3.7 and go to the call which

checked for dongle. 



	notes: 

1.1) cevirmen uses hasp95.vxd for hasp functions so using a bpio 378 

   will do no good to us since our program is in ring 3 and vxd is in 

   ring 0. so you can use bpio -h 378 to set a breakpoint. you'll find 

   yourself in hasp95.vxd so "p ret"'ing you can go back..

1.2) after disasm'ing program i saw a lot of calls to CheckHasp. so 

   patching directly the CheckHasp call is a wiser approach.

1.3) luckily this program used only  services 1 & 2 to check dongle. 

   Which are IsHasp & HaspCode (read HaspApi functions) and luckily 

   again it only compared the return codes of the seed number. (it 

   could have used the return codes for decryption and/or use it as 

   a part of code.) ie. ret codes could be the opcodes of mov eax,1.

1.4) i always recommend you to disasm the file, (as i told you 

   there were too many CheckHasp calls, but there could be some other 

   direct calls to _hasp)

1.5) i changed the addresses and wrote some comments to let you better

   understand in the given disasm forms.

1.6) i'll give these long codes once, so on other cracking usage 

   refer these.



;S u b r o u t i n e      Attributes: bp-based frame

;This is the CheckHasp, it is called many times by the program.



CheckHasp       proc near               ; CODE XREF: sub_409069+1A6p



arg_0           = dword ptr  8



                push    ebp

                mov     ebp, esp

                push    ebx

                mov     ebx, [ebp+arg_0]

                lea     eax, [ebx+0D4h]

                push    eax

                lea     edx, [ebx+0D0h]

                push    edx

                lea     ecx, [ebx+0CCh]         ;

                push    ecx

                lea     eax, [ebx+0C8h]         ;Ret1

                push    eax

                push    dword ptr [ebx+0ACh]

                push    dword ptr [ebx+0A8h]

                push    dword ptr [ebx+0B4h]

                push    dword ptr [ebx+0B0h]

                push    1               	; Service 1 (IsHasp) Checks 

                                                ; if Hasp exists

                call    HaspPushCall    	; call _Hasp



***             cmp     dword ptr [ebx+0C8h], 0 ; Par1=0? (No Hasp=0, Hasp exists=1)

***             jnz     short HaspFound 	; Good Guy



                push    ebx             	; Bad Guy

                call    sub_460A3E

                pop     ecx

                xor     eax, eax

                pop     ebx

                pop     ebp

                retn

; 

---------------------------------------------------------------------------



HaspFound:                              ; CODE XREF: CheckHasp+49j

                lea     edx, [ebx+0C4h]

                push    edx

                lea     ecx, [ebx+0C0h]

                push    ecx

                lea     eax, [ebx+0BCh]

                push    eax

                lea     edx, [ebx+0B8h]

                push    edx

                push    dword ptr [ebx+0ACh]

                push    dword ptr [ebx+0A8h]

                push    dword ptr [ebx+0B4h]

                push    dword ptr [ebx+0B0h]

                push    2               	; Service 2 (HaspCode) gets 

                                                ; return code

                call    HaspPushCall		; call _Hasp



                mov     ecx, [ebx+0B8h] 	; Check return codes for given 

Seed #

                cmp     ecx, [ebx+0D8h]         ;

                jnz     short HaspFail          ;

                mov     eax, [ebx+0BCh]         ;

                cmp     eax, [ebx+0DCh]         ;

                jnz     short HaspFail          ;

                mov     edx, [ebx+0C0h]         ;

                cmp     edx, [ebx+0E0h]         ;

                jnz     short HaspFail

                mov     ecx, [ebx+0C4h]

                cmp     ecx, [ebx+0E4h]

                jz      short HaspOk



HaspFail:                               ; CODE XREF: CheckHasp+9Ej

                                        ; CheckHasp+ACj ...

                push    ebx

                call    sub_460A3E

                pop     ecx

                xor     eax, eax

                pop     ebx

                pop     ebp

                retn

; 

---------------------------------------------------------------------------



HaspOk:                                 ; CODE XREF: CheckHasp+C8j

                mov     eax, 1          ; eax=1 (ok, user has right 

dongle)

                pop     ebx

                pop     ebp

                retn

CheckHasp       endp





	now as you see, the program first checks if the dongle exists. then if

it finds a dongle, it checks for the return codes for the given seed 

code. if

that's ok, too; it puts 1 into eax and returns.. Easy.. ie. change

                cmp     dword ptr [ebx+0C8h], 0 ; Par1=0? (No Hasp=0, 

Hasp exists

                jnz     short HaspFound 	; Good Guy :)



		to Call HaspOk



	then i ran the program again and.. well done Zafer.. :)	





	but let me show you some details.. first of all the following code

comes with the hasp package for software developers to include in their 

code..



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;

;;  HASPBC32.ASM

;;

;;

;;  Description:

;;        This file links the application to the procedure that checks

;;        the HASP key. This file performs the following:

;;

;;          a. Gets the parameters from the application stack.

;;          b. Initialize the appropriate registers.

;;          c. Calls haspreg, procedure that checks the HASP key.

;;	    d. Receives the return values from haspreg and moves them to.

;;	       the stack.

;;

;;  Compilation instructions:

;;

;;        masm -Mx haspbc32;

;;    

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



.386P



_TEXT SEGMENT  BYTE PUBLIC USE32 'CODE'

	ASSUME   CS:_TEXT



	extrn haspreg : near

	public _hasp		



;

; Frame structure after pushing EBP.

;

RetCode4	equ	[EBP+40]    	

RetCode3	equ	[EBP+36]    	

RetCode2	equ	[EBP+32]    	

RetCode1	equ	[EBP+28]    	

PlugNameHi	equ	[EBP+24]    	

PlugNameLow	equ	[EBP+20]    	

Lptnum		equ	[EBP+16]    	

SeedCode	equ	[EBP+12]    	

Cmd		equ	[EBP+8 ]    	



_hasp proc near



	push	Ebp

	mov	Ebp, Esp

	

	push	Eax Ebx	Ecx Edx	Edi Esi



	mov	Esi, RetCode1

	mov	Edi, [Esi]



	mov	Ebx, 0

	mov	Ebx, Cmd

	mov	bh, bl

	mov	bl, 0

	add	Ebx, LptNum



	mov	Eax, SeedCode

	mov	Ecx, PlugNameLow

	mov	Edx, PlugNameHi



	cmp	bh,50	       

	jb	NotBlockOperation  

 	mov	Esi, RetCode4

	mov	Eax, [Esi]



NotBlockOperation:



	mov	Esi, RetCode2

	mov	Esi, [Esi]



	push	Ebp

	call	haspreg

	pop	Ebp



	mov	Edi, RetCode1

	mov	[Edi], Eax

	mov	Edi, RetCode2

	mov	[Edi], Ebx

	mov	Edi, RetCode3

	mov	[Edi], Ecx

	mov	Edi, RetCode4

	mov	[Edi], Edx



	pop	Esi Edi Edx Ecx Ebx Eax 

	pop	Ebp



	ret



_hasp endp

_TEXT   ENDS

       END





ok, this is the common code that you'll see in the hasp protected 

programs.

let's see this in our `cevirmen` example.. our example did a

                call    HaspPushCall		; call _Hasp





HaspPushCall    proc near               ; CODE XREF: CheckHasp+3Dp

                                        ; CheckHasp+8Dp



arg_0           = dword ptr  8

arg_4           = dword ptr  0Ch

arg_8           = dword ptr  10h

arg_C           = dword ptr  14h

arg_10          = dword ptr  18h

arg_14          = dword ptr  1Ch

arg_18          = dword ptr  20h

arg_1C          = dword ptr  24h

arg_20          = dword ptr  28h



                push    ebp

                mov     ebp, esp

                push    [ebp+arg_20]    ; this part just pushes some 

values

                push    [ebp+arg_1C]	; for the _Hasp 

                push    [ebp+arg_18]

                push    [ebp+arg_14]

                push    [ebp+arg_10]

                push    [ebp+arg_C]

                push    [ebp+arg_8]

                push    [ebp+arg_4]

                push    [ebp+arg_0]

                call    NormalHaspCode  ; HaspBC32.asm

                pop     ebp

                retn    24h

HaspPushCall    endp





	i'll skip the NormalHaspCode part since it's the same as 

HaspBC32.asm but will show some parts from HaspReg. I won't comment 

much since it explains itself.



;the code jumps here from the call haspreg

Hasp_           proc near               ; CODE XREF: NormalHaspCode+36p

                pusha

                lea     esi, HaspFFFFFFFF

                cmp     dword ptr [esi], 0FFFFFFFFh

                jz      short Hasp_Skip

                pusha

                lea     esi, GetEnvStrings

                call    dword ptr [esi]

                lea     esi, GetEnvStr_Resul

                mov     [esi], eax

                popa



Hasp_Skip:                              ; CODE XREF: Hasp_+Aj

                lea     esi, HaspFFFFFFFF

                cmp     dword ptr [esi], 0FFFFFFFFh

                jnz     Hasp_Exit

                lea     eax, aKernel32_dll

                push    eax

                call    j_GetModuleHandleA

                lea     esi, ModHandle_Resul

                mov     [esi], eax

                call    ModProcAddy

                lea     esi, GetEnvStrings

                call    dword ptr [esi]

                lea     esi, GetEnvStr_Resul

                mov     [esi], eax

                lea     esi, H_Version

                mov     dword ptr [esi], 94h

                push    esi

                lea     esi, GetVersExA

                call    dword ptr [esi]

                lea     esi, H_Version

                mov     eax, [esi+10h]

                lea     esi, HaspFFFFFFFF

                mov     [esi], eax

                cmp     eax, 2

                jz      loc_469908

                cmp     eax, 1

                jz      loc_469908

                lea     eax, aUtregister

                push    eax

                lea     esi, ModHandle_Resul

                mov     eax, [esi]

                push    eax

                call    j_GetProcAddress

                cmp     eax, 0

                jnz     short ProcNotFnd

                lea     esi, HaspFFFFFFFF

                mov     dword ptr [esi], 1

                jmp     loc_469908

; -----------------------------------------------------------------



ProcNotFnd:                             ; CODE XREF: Hasp_+A6j

                lea     esi, dword_4D9175

                mov     [esi], eax

                lea     esi, ModHandle_Resul

                mov     eax, [esi]

                lea     esi, aUtunregister

                push    esi

                push    eax

                call    j_GetProcAddress

                lea     esi, dword_4D9171

                mov     [esi], eax

                mov     eax, 4000h

                push    eax

                lea     eax, byte_4D90E1

                push    eax

                lea     eax, HaspUt16Dll        ;

                push    eax                     ;

                lea     esi, OpnFile            ;Open Hasp NOT a real file.

                call    dword ptr [esi]

                cmp     eax, 0FFFFFFFFh

                jz      short loc_469908

                lea     esi, HaspFFFFFFFF

                mov     dword ptr [esi], 0Bh

                push    0

                lea     esi, dword_4D9011

                call    dword ptr [esi]

                lea     esi, dword_4D91AA

                mov     [esi], eax

                push    0

                push    0

                lea     eax, dword_4D941C

                push    eax

                push    3

                push    2

                lea     eax, HaspUt16Dll

                push    eax

                lea     esi, dword_4D91AA

                mov     eax, [esi]

                push    eax

                lea     esi, dword_4D9175

                call    dword ptr [esi]

                push    0

                push    2

                lea     esi, MessagBoxA_2

                push    esi

                lea     esi, dword_4D941C

                call    dword ptr [esi]

                lea     esi, MessagBoxA_2

                cmp     word ptr [esi], 0

                jz      short loc_469908

                lea     esi, HaspFFFFFFFF

                mov     dword ptr [esi], 0Ah



loc_469908:                             ; CODE XREF: Hasp_+7Fj 

Hasp_+88j ...

                call    MovEmAll



Hasp_Exit:                              ; CODE XREF: Hasp_+27j

                popa

                lea     ebp, H_JmpAdy

                call    dword ptr [ebp+0]

                pusha

                lea     esi, GetEnvStr_Resul

                push    dword ptr [esi]

                lea     esi, FreeEnvStrA ; Free Envs

                call    dword ptr [esi]

                popa

                retn

Hasp_           endp ; sp = -40h





	and let's see the data parts





seg002          segment para public 'DATA' use32

                assume cs:seg002

                ;org 4D9000h

aGetmodulehandl db 'GetModuleHandleA',0 ; DATA XREF: ModProcAddyo

dword_4D9011    dd 0                    ; DATA XREF: ModProcAddy+12w

..........

a_Hasp95        db '\\.\HASP95',0       ; DATA XREF: CODE:004691EEo

aDeviceiocontro db 'DeviceIoControl',0  ; DATA XREF: ModProcAddy+17o

dword_4D9030    dd 0                    ; DATA XREF: ModProcAddy+29w

..........

aLoadlibrarya   db 'LoadLibraryA',0     ; DATA XREF: ModProcAddy+170o

..........

H_Version       db 94h dup(0)           ; DATA XREF: Hasp_+56o 

Hasp_+6Bo

..........

HaspUt16Dll     db 'HASPUT16.DLL',0     ; DATA XREF: Hasp_+EBo 

Hasp_+12Co

aNetapi32_dll   db 'NETAPI32.DLL',0     ; DATA XREF: CODE:00469392o

..........

a_Hasp          db '\\.\HASP',0

..........



i removed the `....` parts since i don't want this text to be long and 

we don't need to know them for this program. but the removed parts 

included NetApi32 functions for the NetHasp dongle checking which is 

in fact important if  you're cracking a program using NetHasp.





2) Our Second Victim "MTH Psikrometrik Hesabi"

 this program is a kinda addon for acad13.. when you run the program

 a msgbox saying "no dongle or wrong dongle" appears.



        notes:

1.1) this program is a VB4 program.. (damn) It uses hasp95.vxd and 

haspvb32.dll

1.2) dodi's vb4tools (4.10 sept '97) can't disasm with error message 

"can't handle bla bla)



 	ok.. since we can't ida/vb4disasm the program so what?.. well, 

here is what i did.. I installed the vb40.. wrote a simple program like

	a=10

	if a=0 then c=1

	if a=&hffff then c=1

	if a<>0 then .... etc etc



	and examined the result exe trying to figure what the 

"basic cmp"'s hex form is. And found that

	07 xx xx xx xx YY 00 e8 03

	xx..xx=is the number you compare (ie. if a=0  (x..x=0)) 

	yy=comparison (ie. equal, smaller, greater etc.)



	then using bpio -h 378 i tried to find which part checked for 

dongle... after some "p ret"'ing i found myself in vb40032.dll and found 

that there is a part by which your basic code is executed, esi=your basic 

code address. for my example esi=4d2cf8 was IsHasp, 4d2d5b was HaspStatus 

etc. and here is how that looks in the exe file.





004D2CF8:                          B8 15 4A 00 FE 07 84 05

                                   -----------> offset Jumper (IsHasp)

004D2D00:  08 00 0C 00 50 07 00 00-00 00 56 00 E8 03 6C 03 ;07 (00.00.00.00) cmp 0

                          -- ----------- -----------> (56) equal

004D2D10:  94 02 A2 05 08 00 00 00-9C 02 A2 05 08 00 06 00

004D2D20:  98 05 08 00 18 00 98 05-08 00 14 00 98 05 08 00

004D2D30:  10 00 98 05 08 00 0C 00-84 05 08 00 34 04 84 05

004D2D40:  08 00 30 04 50 07 00 00-00 00 50 07 2C 01 00 00

004D2D50:  82 05 08 00 06 00 1E 02-38 06 B8 15 4A 00 FE 07

                                         -----------> offset Jumper 

(HaspStatus)

004D2D60:  84 05 08 00 10 00 50 07-03 00 00 00 56 00 E8 03 ;07 (00..03) cmp 3

                                -- ----------- -----------> (56) equal

004D2D70:  CE 03 94 02 A2 05 08 00-00 00 9E 02 A2 05 08 00

004D2D80:  06 00 98 05 08 00 18 00-98 05 08 00 14 00 98 05

004D2D90:  08 00 10 00 98 05 08 00-0C 00 84 05 08 00 34 04

004D2DA0:  84 05 08 00 30 04 50 07-00 00 00 00 50 07 2C 01

004D2DB0:  00 00 82 05 08 00 06 00-1E 02 38 06 B8 15 4A 00

                                               -----------> offset 

Jumper (GetHaspID)

004D2DC0:  FE 07 84 05 08 00 14 00-50 07 00 00 00 00 6C 00 ;07 (00..00) cmp 0                                      -- ----------- -----    

004D2DD0:  E8 03 34 04 94 02 A2 05-08 00 00 00 E6 03 20 05

           -----> (6c) different

004D2DE0:  84 05 08 00 10 00 50 07-00 00 00 00 AE 00 E8 03 ;07 (00..00) cmp 0

                                -- ----------- -----------> (ae) smaller

004D2DF0:  B0 04 84 05 08 00 0C 00-50 07 00 00 00 00 AE 00 ;07 (00..00) cmp 0

                                      -- ----------- ----- 

004D2E00:  E8 03 88 04 50 07 00 00-01 00 84 05 08 00 10 00

           -----> (ae) smaller

004D2E10:  04 01 50 07 00 00 01 00-44 01 50 07 FF FF 00 00



	and here is what i call "Jumper"



004A15B8 Jumper:         mov     edx, ds:BSS_JmpDat2

004A15BE                 add     edx, 74h

004A15C4                 mov     eax, [edx]

004A15C6                 or      eax, eax

004A15C8                 jz      short JumperSk

004A15CA                 jmp     eax

004A15CC JumperSk:       push    edx

004A15CD                 call    j_DllFunctionCall

004A15D2                 jmp     eax





	ok now, i'll skip the other hex code and try to give you a basic code..

        (note: i tried to generate the basic code myself, so real code can be

        different, but anyway this will give you an idea.)



	Service = IS_HASP

	Call hasp(Service, SeedCode, LptNum, Passw1, Passw2, p1&, p2&, p3&, p4&)

    	If p1& = 0 Then

    		'if p1&(ret code1) =0 then No Hasp Found

    	End If



    	Service = GET_HASP_STATUS

	Call hasp(Service, SeedCode, LptNum, Passw1, Passw2, p1&, p2&, p3&, p4&)

    	'If ??? = 3 Then

    		'can be p1&+p2&+p3&=3 ??

    	'End If



    	Service = GET_ID_NUM

	Call hasp(Service, SeedCode, LptNum, Passw1, Passw2, p1&, p2&, p3&, p4&)

    	If p3& <> 0 Then

      		'if p3&(ret code3 (status))<>0 then No Hasp ID returned.

    	Else

    	'The ID number is a 32 bit integer constructed from the following 

        'equation : p2*65536+p1

	'The following computation converts the two 16 bit integers returned 

        'from the hasp routine to a 32 bit integer.

      	If p2& <0 Then If p1& < 0 Then ID&="(65536" + p2&) * 65536 + 65535 + p1& Else ID&="(65536" + p2&) * 65536 + p1& End If Else If p1& < 0 Then ID&="p2&" * 65536 + 65536 + p1& Else ID&="p2&" * 65536 + p1& End If If ID&="MyID" then 'Heyo.... :)))) End IF End If ok.. to crack this program just change "56"(equal)'s to "6c"(not equal) and vice versa. and you're done.. :) X) Conclusion Part ok, since we're finished with cracking here are some more notes from your fav. cracker. 0) Remember many hasp protected programs have the codes given above. So when you get a hasped program, just search the code.. comment some and you're done.. :) 1) don't ever worry about the garbage codes. our aim is the haspreg call. after the haspreg call, we'll have registers loaded with return codes which we can modify. 2) if the program uses memohasp also check the haspreg call, since the memory contents will be soon returned to an address thus we can gain the info. (you must have the dongle to read the memory contents) 3) Animadeus and I was working on a HaspEmulator but we found a HaspEmulator by MeteO/UCL for DOS. (well done MeteO) but we may release our WinHaspEmulator. :))) 4) Get MeteO's programs, too. He seems to have spent hell a lot of time reverse engineering Hasp. (#ucl'97 @ Efnet and http://ucl.homepage.ru) 5) Keep my introduction to hasp doc handy. You'll need it to understand what your target program is doing. 6) si3.21 and ida 3.7 rocks.. :) (consider buying them) 7) cracking a program, i use Camel, Pepsi, Sepultura, Slayer. (for deeper code analysis, Pantera is also fine) 8) very special greets go to Animadeus (thanx for morale support), The Owl (thanx for morale support. btw, i'm still thinkin' about that 1k chess, eheh) Razzia (thanx for the loong chats), eMX! (nice to see you back in town) 9) and the ppl in #cracking/#crackers.. hii pals.. A) watch out for my sentinel, fast-eye (hardlock) docs.. soon.. Until next time, have fun! Zafer/BSCA End of part C, added 19 October1997
1.0 InCall 2.0 VxD


TIPS AND TRICKS



1.0 Tip1: Hardware



 Until i finish this doc, here is a quick tip. When you do a "bpio 378"

to see the dongle checking you may find yourself very deep in the code.

then you must trace back to find the call etc.



 But instead of this breakpoint usage, here is what i use for the dongles

i haven't seen before. I've built a hardware to plug the parallel port.

it's just a series of "led" (i recommend red ones) which are connected

to parallel port's d0-d7 (you may also put leds to other pins but d0-d7

are enough). So when i trace through the code, when bypass'ing a call

i see the leds flashing. (ahaa!! this call checked for dongle) :)) *evil grin*



 then you can act accordingly. (real check can be another call in that call

so go in that call to find it out)




Zafer's GREETINGS

                                Until next time, have fun!  -Zafer/BSCA



GreETz for this doc:

        FatalicA, eMX!, Razzia, xOANON, Rasel, Bonito, Cophiber, Section Jaguar

        and my partners in reversing.      



GreETz for part C:

 FatalicA, eMX!, Razzia, Animadeus, The Owl, xOANON, Rasel, Bonito, 

Cophiber

 Mad Jester, LordByte, Doc-Man and my partners in reverse enginering.







(c) Zafer, 1997. All rights reversed.

		

You are deep inside fravia's page of reverse

engineering, choose your way out:





Back to project 3
homepage links red anonymity +ORC students' essays tools cocktails
academy database antismut search_forms mail_fravia
is reverse engineering legal?