Dongle reverse engineering
Hasp dongles
project3

by Zafer/BSCA
(03 September 1997, slightly edited by Reverser)
(Part C added 19 Oct 1997)


Courtesy of Reverser's page of reverse engineering

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,.class" 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 reverser'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?