Hyper Lock Dongle/Envelope

by votan , May 2002
Published by +Tsehp

Intro

   I like a sentence from the movie "Gladiator": Man should obey his failure (maybe a bit different, but the meaning is the same).. but dongle producers & programmers seem to be unaware of this.. Little boxes called dongles are still around us. To prove this statement only look at the dongle companies: they are alive:) Yeah, alive because their customers insist on using their products.
   In fact, Hyper Lock is one of these boxes. It is produced by a Turkish company called Guven Bilgisayar Ltd , and according to my search there arent any reversing tutorials about it, so I agreed to write this tutorial. Note that I am not a dongle professional, but I will try to do my best..
   My tutorial has 2 main parts:
  * Part A: The general info about Hyper Lock (dongle services, envelope mechanism, parameters/return values etc.)
  * Part B: A reversing example about Nakkas 2.0 : a program uses Hyper Lock Dongle/Envelope

   Part A : Genaral Info about Hyper Lock

   While searching about Hyper Lock, the only information I found is in the producer's website: h**p://w*w.hyper-lock.com
   These guys are very generous. There you can download full API documentation and files for Hyper Lock 6.0 (currently version). Because the only information resource is this website, I havent any clues for the older versions. But I think they are similar to 6.0, in fact more primitive.
   If you download the documentation and files mentioned above and have time to study them deep, you can skip this part.

   Lets start...

   There are several types of Hyper Lock Security Devices (i.e: dongles) designed for various environments such as LANs. P-02, one type of them, stands for Hyper Lock dongles having 240 bytes data memory.
   Each Hyper Lock Dongles has a unique 8 byte ROM Serial#, a 8 bytes read/write access password (=Device Identification Code). The latter one can be modified, provided that the previous password is known.
   The main features of the dongle can be arranged in order as:
  * Encrypted Communication between dongle and PC : a function of Device ID Code and internal User Code; this feature is against analysing the dongle with a logic analyzer, I havent an original dongle, so I cant try to break into it, but probably almost impossible
  * Pseudo Random Function Generator: It provides a number for random functions which can be used to check dongle presence. The random number generated is a function of a 4 bytes initial value (known as Seed), Device ID Code and internal User Code.
  * Envelope Protection: an encryption applied to the program, if right dongle is present, the protection decrypts the program into memory, if not, simply the program gives an error message: "HYPER-LOCK Security Device not found!". Hyper Lock supports multiple envelope protection, that is: you can envelope an enveloped program again and again. (note: the envelope utils can be obtained from the url above, my knowledge isnt enough right now to code an envelope decryptor, sure however some of the people around you can do this.)

   Hyper Lock Device Drivers:
  * hlwin9x.vxd
  * hlw16_9x.dll
  * hlw32_9x.dll
  * hldos.sys
  * hlwinnt.sys
  * hlwin16_nt.dll
  * hlw32_nt.dll
   note that for example if OS is Win9x, programs call dongle services (=API functions) in hlw16_9x. dll (for 16 bit NE) or hlw32_9x.dll (for 32 bit PE), then this dlls call hlwin9x.vxd which chats with the dongle. i.e:

   program <=> hlwXX_9x.dll <=> hlwin9x.vxd <=> dongle
   Hyper Lock API Functions (Single-User)

  Service    Name           Operation
    -------------------------------------------------------------------------
     1    HL_Inport 	 
    -------------------------------------------------------------------------
     2    HL_Outport	 	
    -------------------------------------------------------------------------
     3    HL_Reset         to reset the Hyper Lock 

                               parameter: none
                               return value: none
    -------------------------------------------------------------------------
     4    HL_Rom           to know the unique 8 bytes content of Hyper Lock Dongle ROM

                  First 4 bytes = serial number
                  Last byte = an 8 bit CRC value added for data integrity check

                               parameter: the buffer area of serial number
                               return value: 0  (Hyper Lock is connected to a parallel port)
                                             non-zero a zero value (no Hyper Lock Dongle connected)

                 * this function can be used to check the presence of the dongle 
    -------------------------------------------------------------------------
     5    HL_Initialize	   to see if a certain Hyper Lock Dongle connected the PC parallel port or not
                                          to run other HYPER-LOCK functions

                               parameter:  UserCode
                                           Device ID (max. of 8 characters in ASCIIZ format)
                               return value: 0	 (Hyper Lock Dongle is not found) 
                                            -1	 (Hyper Lock Dongle is not installed or is not responding)
                                             1-4 (Hyper Lock Dongle is found at LPT #)

                 * this function can be used to check the presence of the dongle 
    -------------------------------------------------------------------------
     6    HL_Exit	   to remove the connection between dongle and API functions
 
                               parameter: none
                               return value: none
    -------------------------------------------------------------------------
     7    HL_GetStatus	   to know the status (single or multi-user) of the Hyper Lock Dongle
           
                               parameter: none
                               the 7th bit of return value: 1  multi-user type
                                                            otherwise  single user type
    -------------------------------------------------------------------------
     8    HL_Read	   to read a block of data from the dongle's memory area

                               parameter: address (the starting address of the memory to be read)
                                          buffer  (the address of buffer where the data read into) 
                                          length  (the data length to be read; max 240 bytes for a P-02 type dongle)
                               return value: 0    successful operation
                                                    non-zero    error
    -------------------------------------------------------------------------
     9    HL_Write	   to write a block of data into the non-volatile memory area of the dongle 


                               parameter: address (the starting address of the memory where the will be written)
                                          buffer  (the address of buffer where the data is stored) 
                                          length  (the data length to be written; max 240 bytes for a P-02 type dongle)
    -------------------------------------------------------------------------
    10    HL_GetMaxLogin   to determine the maximum number of users for a multi-user type

                               parameter: none 
                               return value: 0  single user type
                                             1-255 max. # of users
    -------------------------------------------------------------------------
     A    HL_GetRandom     to fetch a 2 byte random integer value from the dongle random number generator
                                    to terminate the pseudo-random series

                               parameter: none
                               return value: 2-byte random integer value
    -------------------------------------------------------------------------
     B    HL_RepeatRandom  to repeat the last value returned by HL_GetRandom or HL_NextRandom functions

                               parameter: none
                               return value: the same value returned by the last call to 
                                             HL_GetRandom or HL_NextRandom functions
    -------------------------------------------------------------------------
     C    HL_SetRandom	   to initialize pseudo random generator

                               parameter: Seed (Pseudo random series' initialization value of 4 bytes integer) 
                               return value: 2-byte integer number (the first element of the activated pseudo random series)
    -------------------------------------------------------------------------
     D    HL_NextRandom	   to fetch consecutive values from dongle's pseudo random generator

                               parameter: none
                               return value: 2-byte integer  (next term of pseudo random series)
    -------------------------------------------------------------------------
     E    HL_StopDebug	   to start dongle's internal reset counter. 

                               parameter: none
                               return value: none
        
        * If none of API functions is invoked within about 18 ms, Device Reset operation takes place.
        * This function has been designed to prevent the users from viewing the program code using debuggers. 
    -------------------------------------------------------------------------
     F    HL_StartDebug	   to stop the internal reset counter of dongle.
         
                               parameter: none
                               return value: none

        * The other API functions stop the reset counter as well. However, this function runs faster.
    -------------------------------------------------------------------------
   Hyper Lock API Functions (Multi-User) & Error Codes

   I dont give them here, cos I dont wanna a too long tutorial. But if you wonder, you can reach them from the documentation mentioned above.

   Final Notes for Part A:
  * Target programs maybe use only HL_Rom and/or HL_Initialize to check dongle presence without using memory functions (HL_Read etc.). If they do, use this advantage.
  * As you will see in the example below, the envelope mechanism is weak, weaker than Hasp's one. In addition, there is no CRC or encryption in the API dll files. This makes emulation easier.

   Part B : Reversing A Hyper Lock Dongle/Envelope Protected File: Nakkas 2.0

   The reason why I dealt with Hyper Lock is this program. I read a help request in a forum about a Hyper Lock protected program called Nakkas, I havent heard of this dongle before and was interested in it. Then an excited adventure started:)
   Nakkas 2.0 is one program of the embroidery program series produced by BEST LTD. ( h**p://w*w.best.com.tr ) On the page, only nakkas' link works (2.58mb). In fact, some of the other programs use probably HASP, because there is a dead link for some HASP files.

   Tools: Softice, Hiew, w32dasm (IDA is the best, but w32dasm is enough today)

   After installation we have hlw16.dll, hlw32.dll , hlwin9x.vxd in /windows/system/ (note that hlw16.dll = hlw16_9x.dll, hlw32.dll = hlw32_9x.dll)
   Our main exe, efwmain.exe (/Efw20/) is a NE file. When we try to run it, we get an error message: "HYPER-LOCK Security Device not found!"
   I opened the file with SI loader and traced. After a while, I recognized that the program decrypted itself. Ooopps Hyper Lock's envelope protection! Program entry point is in the last segment (segment 44). After bpio -h 378, SI popped up, but I couldnt reach the code of API dll and vxd. Moreover, although I found how to direct efwmain.exe to the right way in the memory ( I played with some conditional jumps and the program jumps to the segment 1 instead of giving error msg), but the program crashed again and again then. You maybe notice that I didnt give any details here because I recognized something that changed the direction of my reverse effort.
   I looked into the subfolders of /Efw20/ for some useful info. In the setup subdirectory I found some files related to Hyper Lock Driver Setup.. and one more thing: Nefwmain.exe .. Aha! It has almost the same size with efwmain.exe, only 2-byte less. Why are 2 copies of the same file? Actually, I have some idea about this, but still dont know exactly why. After reversing the second file, yes it uses envelope protection too, but I saw after decryption that the code are a bit different until the jump to segment 1. I think efwmain.exe is a one more enveloped form of Nefwmain.exe. But only an idea. Then another question occurs naturally: why do the guys at BEST want to install both of them? A stupid behaviour, isnt it? I call it stupid because after my reverse for Nefwmain.exe finished (read details below), Nefwmain.exe ran. In conclusion, they do the same job. then what's up?:)
   Ok, after this discovery I copied Nefwmain.exe from /Efw20/setup/ to /Efw20/ and focused on it. At first I use a bpio -h 378 . SI popped up. After clearing bpio, I make 4 p ret ( why 4? it is only an observation:) When I did 5th p ret, simply I got error msg) I did p ret to see where Nefwmain.exe calls dongle check.


xxxx:01C1   E8AE02   call 0472   <-- call to dongle check
xxxx:01C4   0BC0       or ax,ax    <-- after 4 p ret, we are here
xxxx:01C6   7402       jz 01CA     <-- if ax=0 jmp 01ca, then we have error msg; if ax=1 jmp thru 01c8 to xxxx:0242, then segment 1
xxxx:01C8   EB78       jmp 0242
   After faking the first check and jumping to segment 1, we have a call series. I went on tracing with F10, then the program logo opened, I went still on, after a call boooomm the program crashed. At least we understood that we are on the right way.
   I did the same above again, but after jump segment 1, I enabled bpio -h 378 and then exited SI and SI popped up: this is hlwin9x.vxd codes. Some p ret'ing: hlw16.dll codes.. Here I saw this codes:
...............................
xxxx:019E ....     mov ax, 0005  <-- ax= service 5 = HL_Initialize
xxxx:01A1 ....     push ax
xxxx:.........................   <-- I removed some unnecessary parts for convenient
xxxx:01a5 ....     xor ax,ax
xxxx:.........................
xxxx:01a9          call 004E     <-- we will take a closer look at this in the hlw16.dll
..............................
   After some more p ret, I reached Nefwmain.exe codes. Program compares the values ax,[bp-02] with 0 etc.. I mean program calls service 5 many times while running, and check the return values, if bad value returned, program just crashed. Now stop here, what do we know? -Program checks dongle with HL_Initialize. Where is this API function? -In the hlw16.dll Which value should return if dongle connected? -any integer value from 1 to 4. Then we know everything to emulate HL_Initialize.
   Open hlw16.dll located in /windows/system/ with w32dasm (IDA is also ok) From exported functions list select _HL_Initialize. We recognize the code we saw in SI window above. Lets click other exported functions too. All of them have a call 004E. Very suspicious! Take a look at this call:

0001:004E   55         push bp
0001:004F   8BEC       mov bp,sp
0001:0051   83EC02     sub sp,0002
0001:0054   8B460A     mov ax,[bp+0A]
0001:0057   8B5E08     mov bx,[bp+08]
0001:005A   8B4E06     mov cx,[bp+06]
0001:005D   FF1E0000   call far word ptr [0000]  <-- call to hlwin9x.vxd
0001:0061   8946FE     mov [bp-02],ax   <-- return value is in ax, here move this value to [bp-02] 
0001:0064   8B46FE     mov ax,[bp-02]
0001:0067   8BE5       mov sp,bp
0001:0069   5D         pop bp
0001:006A   CA0600     retf 0006
   Now, we should find which Hyper Lock API functions our program use. We can find the answer from a string search in Nefwmain.exe by opening it in Hiew's text mode or IDA will show them at the end of the Nefwmain.exe's disassembly. They are: HL_Initialize,HL_Reset,HL_Read,HL_Write. Among them, HL_Reset doesnt have any parameters/return values; we know about HL_Initialize. On the other hand, HL_Read an HL_Write can be bitches if program uses them, uses for obtaining critical data from dongle. If it does, without dongle we will have difficulties. But wait.. lets emulate HL_Initialize and see what will happen.
   My emulation is very simple:
Before emulation:
0001:005D   FF1E0000   call far word ptr [0000]  <-- call vxd
After emulation:
0001:005D   B80100    mov ax,0001   <--I removed the call vxd, and made ax 1,so 
0001:0060   90        nop              program will think dongle connected at LPT#1
   I know this emulation is brutal. For HL_Initialize everything is ok, HL_Reset isnt affected by emulation. However, if HL_Read and HL_Write are really used and bitches, we will have problems. What I did? I gave my emulation a chance and observed what happened... I click every menus,no problem, everything seemed to be ok:)
   We stop here the HL_Read/HL_Write paranoia and restart the application.
   Oops at the beginning we still get error. Each time we should patch the first check in memory, then program opens and runs perfectly.. The first check at the beginning needs 1 in ax and our emulation makes this possible, so the first check uses stg different. I found nothing about this at first. Then I thought a solution: what is envelope? -a decryptor.. Then if we patch the code after decyrpting finished, the problem will be fixed.
   I opened the program with SI loader again and discovered the decryptor function, traced until the decryption finished and jumped thru our check at 002C:01C6 (segment 44 offset 01c6) which we wanna patch. I give you the details in w32dasm

0044.0000   50          push ax   <-- program entry point
..................................
0044.000A   E95301      jmp 0160  <-- jump 0160
..................................
0044.0158   EB01        jmp 015B  <-- after decrypt finished program comes here, everything
                     decrypted. From here, jump 015B, after decryption
                     at 015B the instruction is jmp bx where bx is 0180,
                     that is: program jumps 0180 at the final.
..................................
0044.0160 ........................
..................................
0044.0163   2EFF1E8400  call far word ptr cs:[0084] <-- Decrypt routine starts
0044.0168   0BC0        or ax,ax
0044.016A   7506        jne 0172
0044.016C   B8014C      mov ax,4C01  
0044.016F   CD21        int 21      <- int 21 service 4C=exit exitcode=01
0044.0171   90          nop
.....................................
0044.0180............................
.....................................
0044:01c6............................ <- after decryption the instruction is jz 01CA
   My inline patching is like this:
0044.0158  EB12       jmp 016C   <- jump 016C instead of 015B
0044.016A  EB07       jmp 0173   <- we dont need a conditional,change it to jmp
0044.016C  C606C60175 mov byte ptr [01C6],75 <- we change the conditional from je to jne at 01C6
0044.0171  EB0D       jmp 0180   <- jump 0180 , so program goes on without error.
   Now, Nakkas 2.0 runs very well. I have tested it for a while, I havent had any problems with HL_Read,HL_write yet. THE END:)

   Greetings & Final Notes :

For any suggestions,corrections,problems,questions about the tutorial
send an email to votanmail(at)yahoo(dot)com (no crack request please!)
To programmers: Use your own protections!
To Hyper Lock producers: Try to make your dlls of API functions more secure,
add at least a CRC instead of dealing with protection against logic analyzer:)
Thanx 2: +orc and all +HCU family, all reverse engineers who share their knowledge with others.
Thanx 4 music: Death & Control Denied (Chuck R.I.P)
Special Tnx & Hello: CYDONIA/BSCA (you, coder god!), all my friends in BSCA forums, Terliksi/Anatolian

votan , May 2002