Saturday, December 5, 2009

The Basic Types of Software Protection

In this chapter I will describe most types of contemporary software-protection programs, all of which have their pros and cons. Which is best depends only on your opinion of the program code and the creators' preferences.

Registration-Number (Serial-Number) Protection

Programs that use registration-number protection require the user to enter a registration number to register the program. The registration number depends on specific criteria.

Programmers use different types of registration-number protection, including the following:

Registration number is always the same.

Registration number changes in accordance with entered information (company, name, and so on).

Registration number changes in accordance with the user's computer.

Registration-number protection in Visual Basic or Delphi programs.

Registration number is checked online.

Registration Number Is Always the Same

A program protected with this method requires the user to enter a registration number (see Figure 3.1). However, because the registration number is always the same, the cracker only has to find the correct registration number, post it online, and the program can then be registered by anyone.

You can make excellent use of this protection method by encoding several program sections, such as a Save function, with the correct registration number value. If a cracker uses the patch method (directly adjusting conditions in the program code) and the correct registration number hasn't been entered, the

originally blocked functions will still not work correctly.

It isn't a good idea to decode the blocked sections right after the correct registration number has been entered. It is safer to decode these sections only when the program has been started, or better still, only after the blocked function has been called. If the function is encoded again after use, and the program contains many encoded sections, the program will never be decoded in the memory as a whole, which means that a dump from memory will not help the cracker very much.

This software protection should be combined with other types that will be described later on. Registration Number Changes in Accordance with Entered Information

This is the most frequently used type of protection. In this case, before you enter the registration number, you have to enter a user name, company, or other information, and the correct registration number changes according to the information you enter (see Figure 3.2). If you enter a registration number that doesn't match the information entered, the registration won't succeed (see Figure 3.3). The more skilled the programmer, the more difficult he can make it for the cracker to break this protection. However, even though the calculation algorithm may be very complex, once the user has entered the registration number, it is compared with the calculated one, and the cracker only has to trace the program to find the correct registration number.

When this sort of protection is used, the program should contain another hidden algorithm to check whether the entered registration number was really the correct one. It shouldn't tell the user, though, if it finds any inconsistencies. It will be enough if the user is somehow punished. (I will leave this up to the programmer's imagination.)

You can also encode some parts of the program (as mentioned previously) so that they cannot be used in an unregistered version. Then, once you've verified part of the registration number, you can use the unverified part for decoding the parts of the program. If you use good scrambling and a sufficiently long code, it will be almost impossible for the cracker to find the correct value for decoding. ASProtect (described in Chapter 6) works in this way.

Registration Number Changes in Accordance with the User's Computer

This is an unpleasant type of protection for an attacker, and it may even fool an inattentive cracker because, although he will register the program at his computer, it will not be possible to register the pirate version anywhere else. The registration number may change, for example, in response to the hard drive serial number or according to some random sequence. (It is important to hide this registration number carefully, because if it is found, it could easily be changed into a uniform number and the program could be registered at any computer with the same registration number.) Naturally, the registration number should also change in accordance with other data (such as user name, company, and so on) so that it works for only one user (see Figure 3.4).

Figure 3.4: Every computer requires a different registration number

When using this type of protection, it is very important to hide both the code that detects the computer number and the checking code that assesses the correctness of the entered registration number. It is good to combine this method with other types of protection.

Registration-Number Protection in Visual Basic Programs

Protecting a program in Visual Basic (VB) isn't easy, since the programming language itself is a high-level language (the higher the language level, the further the compilation is from assembler). With high-level languages it is difficult to influence the compiled source code.

VB programs fall into the following groups:

VB4

VB5 and higher

VB5 and higher, compiled in p-code We'll look at each of these in turn.

VB4

Although it may not be obvious to most users, the VB4 family of programs has very inadequate protection, and the experienced cracker will find most registration numbers within five minutes (see Figure 3.5). The trouble is that VB4 programs mostly use the same VB40016.dll (VB40032.dll) library call for comparing the entered registration number to the correct registration number.

One advantage of VB4 programs is that they are hard to trace in SoftICE because their code isn't compiled into a machine code but only into pseudoinstructions that will be performed after the program is started. There are decompilers for VB4, but they are rarely used.

How VB4 Programs Are Cracked

How are VB4 programs cracked then? Even though VB4 is only rarely used for programming these days, it is good to know about it to avoid the mistakes in its use.

For a 16-bit VB4 program, the cracker has to find something like the following in memory and in the VB40016.dll code:

8BF88EC21EC5760E33C0F3A674 051BC01DFFFF

He then sets a breakpoint to the address where the code was found, and he is able to see the following program instructions in the debugger:

Prefix Instruction

8BF8


mov di,ax

8EC2


mov es,dx

1E


push ds

C5760E


lds si,[bp+0E]

33C0


xor ax,ax

F3A6


repz cmpsb

7405


jz 2667

1BC0


sbb ax,ax

1DFFFF


sbb ax,ffff

Now all the cracker needs to do is to see what he finds at the address where the repz cmpsb instruction compares the entered registration with the correct one. (You have only to look at the addresses es:di and ds:si to find the correct one.) This very simple tactic usually works, which probably isn't good news for most 16-bit VB4 programmers. Fortunately, 16-bit VB4 is used less and less. When it is, I recommend using a good DOS compressor or some other EXE protector for the program itself.

Most 32-bit VB4 programs use the MultiByteToWideChar function in the VB40032.dll library to compare two strings. During registration, all the cracker needs to do is set a breakpoint to the hmemcpy function before clicking OK, and then trace the program until he gets into VB40032.dll and finds the following bytes in the memory:

56578B7C24108B7424 0C8B4C2414

Then, he sets a breakpoint to the address found, and after repeatedly clicking OK, he will see the following code:

Prefix Instruction Explanation

push esi

push edi

8B7C2410 mov edi, [esp + 10] ;es:edi —> registration number should be here

8B74240C mov esi, [esp + 0C] ;esi —> correct registration number

813F70006300 cmp dword ptr [edi], 00630070

7527 jne 0F79B381

803E00 cmp byte ptr [esi], 00

VB5 and Higher

The software protection in VB5 and higher is slightly more difficult for crackers to tackle than that found in VB4. Many crackers are rather disappointed when they find out that they have a VB5 program in their hands, and they often leave it alone, but the experienced ones aren't scared off that easily.

Crackers aren't keen on cracking VB programs (or those written in Delphi) because the code is hard to read and understand, and it takes a lot of time to trace. To crack VB5, they usually use methods for generating a registration number for just one user, or modifying the program code to allow for any registration number. Only rarely does someone create a registrationnumber generator for a VB5 program, and then only the best crackers are able to do so because the code is so difficult to understand. (They may use SmartCheck, since it helps them understand the code.)

The fact that VB5 programs are so unpopular among crackers, and that it's difficult to create registration-number generators for them, is one advantage of using VB5. When a good compression program or protector is used, VB5 programs can be a challenge for any cracker.

It is a good idea to use a registration number that changes on different computers. This involves heavy interference with the program code, but the result is that it is almost impossible to use anti-debugging tricks.

VB5 and Higher, Compiled in P-Code

Programs compiled in p-code (short for packed code) are probably the VB programs least liked by crackers. Unlike VB4 programs, p-code programs are translated into pseudo-instructions, not machine code, and these instructions are performed when the program runs. Programs in p-code can be traced in SmartCheck, but not easily. The most experienced crackers will try to trace such programs in SoftICE, but only a small group of them will be able to do so.

VB programs compiled in p-code combine well with other software protection, and when they are used with a good compression program or protector, they are a challenge for any cracker. As a programmer, you should use registration numbers that change with different computers. Doing so will heavily interfere with the program code, but it will make it nearly impossible to use anti-debugging tricks.

Registration Number Is Checked Online

Some newer programs use the latest in modern technology for testing the correctness of a registration number (see Figure 3.6). Once the registration number is entered, the program sends it via the Internet for verification. A server then tests the number and returns a report which tells the program whether the number is correct (see Figure 3.7). The program processes this report to determine whether the program was properly registered. Despite this online exchange, though, most of these protection programs are very simple, and an experienced cracker can get rid of them quickly and reliably.

Online verification of registration numbers is done more and more often, but it's not appropriate for all software. Before deciding to use it, consider the audience for your program. For example, if your program always uses an Internet connection, the user will have to be connected to the Internet to use the program, and online verification is a reasonable option.

Most current software protection based on the principle of online verification isn't very good and is easy to remove, though there are several very good exceptions. For example, online verification is ideal for sending data to a program that is necessary for the program to function correctly.

Consider a program that has the Save function disabled in the unregistered version. When a user enters a registration number, that number is sent to a checking server. If the registration number is correct, the server will send a report confirming program registration, together with a short data bundle that could unblock the Save function. The server might, for example, send a parameter to decode a previously encoded function.

With this protection scheme in use, it would not be enough for a cracker to fool the program into thinking that the server confirmed a registration number. Even if the cracker were to succeed at fooling the server, the Save function would not function.

For this protection to work properly, the decoding key must be rather long so that it can withstand an attack. Also, the problem of a cracker using a correct registration number from a legally registered copy still remains, since with a correct registration number in hand, a cracker could decode the Save function correctly. Therefore, when using this protection scheme, it's very important to make the registration number different for each computer, thus making its illegal use difficult.

Note It is also possible to allow only one use of the registration number, or to limit its future use to the IP address of the computer where the program was originally registered.

Time-Limited Programs

Time-limited programs try to ensure that a program will not be used once the trial period has expired (see Figure 3.8). This is not usually a very effective method of protection, though, because once the time limit is cracked, the entire program is available to the cracker. It is much better to disable some functions in a program's unregistered version, thus forcing the user to buy the registered version if they want to use all of the program's features.

The time limit is removed once the correct registration number is entered.

The time limit is removed once a registration file is entered.

The time limit cannot be removed; the user's only option is to buy the full program without the time limit.

The time limit is contained in a Visual Basic program.

• The time limit applies to a certain number of starts, after which the program can no longer be used. Time Limit Is Removed Once the Correct Registration Number Is Entered

This approach has the same problem as registration-number techniques described previously in this chapter. The only difference is that if the correct registration number isn't entered, the program will not be registered, and it will refuse to run after a certain period of time.

When adopting this approach, the quality of the registration number must be high, since crackers do not focus on the time limit when removing this protection. Your program should use only a simple check when testing to see how long the program will be allowed to run. The program might, for example, detect a date during its first use and write that date into registers or a file. The program could then check after each start to see whether the time limit has been exceeded and, if so, refuse to run (see Figure 3.9).

This is a wonderful type of protection that isn't used very often. When using this protection, you might consider sending the registration file via the Internet. The registration file could, for example, contain a substantial part of the program code, which would unblock the time limit.

But beware: Crackers will focus on the routine that tests whether the time limit has already expired, so you must secure this routine against an attack. A cracker will rarely create a correct registration file to counter this protection because it is rather difficult to do so; it's much easier for him to cancel the time limit right in the program.

Do not use a checking method that tests to see whether a registration file is in the program directory and whether it contains correct data. It is much more effective to place the protected application's code right into the registration file. Of course, this isn't easy to do, and it's a method reserved for good programmers only.

Should you decide to use this type of protection, take the time to carefully test the result and make sure that the time limit test is as inconspicuous as possible. Consider using several separate tests together that will cause errors if the protection is not removed correctly. (Many antivirus programs use this kind of protection—see Figure 3.10.) And, as is often the case, it is a good idea to combine this protection with other types.

Figure 3.10: This is a registration key file for Kaspersky's antivirus program, AVP Time Limit Cannot Be Removed; User Must Buy the Full Program

Program demos often use this type of protection, which prevents the program from being starting once the time limit expires. There is no registration code to be entered (see Figure 3.11).

Time Limit Is Contained in a Visual Basic Program

This kind of protection isn't widely used, and it's also not popular among crackers because it is difficult to remove. As was mentioned earlier in the discussion of registration numbers, a VB program is hard to trace (or nearly impossible if it's a VB4 program) and it is hard to understand.

Note If your program prints a message once the time limit expires, you will make the cracker's job easier.

The more experienced crackers will overcome this type of protection easily, since the method used doesn't vary much. As with other methods, it's a good idea to use several separate, interwoven tests. For example, if the first test is removed, the program might use a hidden test after, say, ten minutes to check whether the time limit has expired, and, if so, close without warning.

It is extremely difficult to locate this kind of protection—if the protection has been made well, it is a very time-consuming job. As always, it's a good idea to combine this method with other protection methods.

Time Limit Applies to a Certain Number of Starts

This is basically the same as other time-limit methods, except that it limits the number of starts rather than a number of days. This can create many problems for a cracker, since the program doesn't have to detect a date but just has to save the actual number of runs somewhere (in registers or a file). Otherwise, the issues are generally the same as those for other time limits.

Registration-File (KEY File) Protection

This sort of software protection creates a registration file, usually in the same directory where the program is installed. The program checks the contents of this file and, if the file is correct, the program will behave like a registered one. If the file is missing or it is not correct, the program will behave like an unregistered version or will not run at all. The registration file may contain information about the user, or constants for decoding encoded program parts that are accessible only in a registered version.

There are two general types of registration-file protection:

Some program functions are blocked without the correct registration file.

The program is time-limited without the correct registration file.

Some Program Functions Are Blocked Without the Correct Registration File

This is a very good type of software protection, and crackers don't like it. Still, like all protection, it can be removed. When this protection is used, some of the program's functions are blocked without the correct registration file. As soon as the registration file is placed into the program directory, the program becomes registered and it functions normally.

There are several ways to implement this protection. The worst, and the one most easily removed, uses a routine that tests to see whether the correct registration file is present. If the program finds the correct file, it will unblock previously blocked functions. In such a case, the cracker need only find this routine and either "persuade" the program (by changing the code so that it believes the registration file is in place) or deduce the registration file's structure through the routine and then generate it.

If you choose to use this method, encode the registration file so that it won't be easy for a cracker to generate (see Figure 3.12). You might also consider inserting additional testing routines into the program that start randomly once an unblocked function has been used. If a routine finds that the registration file isn't in place, the program reacts as the programmer wishes.

While this type of protection is good because it is hard to remove, it is bad for users who aren't connected to the Internet. If your users have to wait to receive their registered software by mail, they may be put off.

Program Is Time-Limited Without the Correct Registration File

Most antivirus companies use this type of protection. The program is unregistered and is time-limited without a correct registration file, as was discussed earlier in the "Time-Limited Programs" section. As with all the software protection in this chapter, the time limit is cancelled once the registration file is loaded.

Hardware-Key (Dongle) Protection

Protecting software with hardware keys is another, less-used alternative for software protection. In this protection scheme, a copy-protection device, called a dongle, is connected to an I/O port on the computer and must be present for the protected program to run.

There are two types of hardware-key protection:

The program cannot be started without the hardware key.

Some functions of the program are limited without the hardware key.

HASP and Sentinel are two of the most widely used hardware keys and are probably the best, so I will describe both of them.

Program Cannot Be Started Without the Hardware Key

Most hardware keys are very simple. The program sends data to the port where the hardware key is supposed to be, and waits for a reply. If the program doesn't receive a reply, it refuses to run and gives an error message (see Figure 3.13).

Figure 3.13: When a hardware key isn't connected, the program cannot be started

More advanced hardware keys encode the data sent to the port. Or the hardware key could include an EPROM, with important parts of the program built into the hardware key itself. In this case, if the cracker has only the program and not the hardware key, it is almost impossible to remove the protection.

There are several ways to locate the routine that tests for the presence of the hardware key. For one, an API hook that tests for the key's presence during each API call is often used. Another method that's commonly used is to call the API by means of a function specific to the particular key. Some more advanced hardware keys use their own drivers.

If a cracker learns to remove a certain type of hardware-key protection, it's often not a problem for him to remove such protection at any time in the future. Of course, companies are continually trying to improve their protection programs by writing better drivers, so removing hardware protection is not always a given. Still, it's easy enough to find software emulators for the most common hardware keys that try to emulate the key's presence.

It is very important when using a hardware key to manage the protection in the program code itself, and not to rely on drivers or API calls from the manufacturer. Crackers often know these drivers and API calls very well, and they don't have much of a problem overcoming them.

When a cracker can't find a suitable emulator for a particular key type, he will try to emulate its behavior directly in the program code. When doing so, he usually will not try to change the driver's code, because it's typically well protected against these attacks. Instead, he will insert the emulation code into the program. The best protection against this crack is to perform a multiple cyclic redundancy check (CRC) against program changes both in the file and in memory.

One major downside to using hardware keys is that because a dongle must be supplied with every copy of the program, the program's price and its cost to manufacture increase, and you may encounter distribution problems. Therefore, hardware keys are mostly used with very expensive programs and not with shareware.

A hardware key may be a good solution for smaller teams developing custom-made programs, but if you choose to go this route, buy the complete protection instead of trying to develop your own because it isn't easy or cheap to do.

Some Functions Are Limited Without the Hardware Key

The principle of this protection is very simple—when no hardware key is connected, some important functions of the program won't work (see Figure 3.15). Once a hardware key is connected, the program is fully functional. When these important functions are contained in the hardware key itself, this type of protection is very good. The key may also contain codes for decoding these functions right in the memory.

It is almost impossible to remove this protection without the key, especially when the encoding is good. However, if these functions are only blocked, and are unblocked once the hardware key is used, the cracker will have a much easier time removing the protection, and can probably do so even without the hardware key.

HASP Hardware Keys

The HASP series of hardware keys (see Figure 3.16), from Aladdin Knowledge Systems (http://www.ealaddin.com), offers several options. HASP installs its own drivers when the software is installed, and this software is used later for communicating with the hardware key. HASP has special drivers for DOS, Windows 9x/NT/2000/XP, and Mac OS X.

Figure 3.16: One version of the HASP hardware key

Program developers wishing to protect their product with HASP must communicate with the hardware key by means of the installed drivers, because everything is secured by HASP API calls. To see where these calls are performed in a HASP-protected program, look for cmp bh, 32:

HASPCall:

cmp bh, 32

;test to see whether this ;is a higher HASP service

jump:

jb jump

mov esi, dword ptr [ebp+28] mov eax, dword ptr [esi] mov esi, dword ptr [ebp+20] mov esi, dword ptr [esi] push ebp call Hasp( ) pop ebp

mov edi, dword ptr [ebp+1C] mov dword ptr [edi], eax mov edi, dword ptr [ebp+20] mov dword ptr [edi], ebx mov edi, dword ptr [ebp+24] mov dword ptr [edi], ecx mov edi, dword ptr [ebp+28] mov dword ptr [edi], edx

;the basic HASP service is called here

;saves the return value

;saves the return value

;saves the return value

;saves the return value

The basic HASP service always consists of the same call. The program makes decisions according to the parameters by which it was called, and then it decides which HASP service to call.

If you look one level higher in the program code, you will see code like the following:

push eax push ecx

push 000047FE push 000015C9 push ebx ;password1 ;password2 ;lptport

push edi

push 00000003 mov [esp+38],

0000001A

;HASP service number 3

call HASPCall

;address

;calls the ReadWord ( ) service

In this case, HASP function no. 3 was called: ReadWord(). All other services will be called in this way. Let's look at the most important and frequently used functions.

Function no. 1: IsHasp()

This function is always called first. It considers whether the hardware key is attached. Simply changing the return value of this service will absolutely not overcome HASP.

Input values:

BH = 01

BL = LPT port

Return values:

EAX = 0 — Hardware key wasn't found

or

EAX = 1 — Hardware key was found Function no. 2: HaspCode ()

This function is usually called right after the IsHasp() function. password1 and password2 are codes that are used for communication with the hardware key. The seed code determines the return values.

Input values:

BH = 02

BL = LPT port

EAX = seed code

ECX = password1

EDX = password2

Return values:

EAX = code1

EBX = code2

ECX = code3

EDX = code4

Developers using HASP often make a mistake when testing the return values. Basically, it is enough to test two values or to perform the test using a more complex mathematical calculation. It is also possible to test more values for each return code, which makes the cracker's life more difficult.

Function no. 3: ReadWord()

This function reads dword (a word) from the HASP memory. The address from which the reading will be performed is located in EDI. You must multiply the address by two to find it.

Input values:

BH = 03

BL = LPT port

ECX = password1

EDX = password2

EDI = address

Return values:

EBX = Read data

ECX = status 0 — Correct, otherwise there was an error (you can find the error description in HASP documentation)

Function no. 4: WriteWord()

This function writes dword (a word) into the HASP memory. The address where the writing will be performed is located in EDI. To find out the address, you must multiply it by two, since it is a word.

Input values:

BH = 04

BL = LPT port

ECX = password1

EDX = password2

EDI = address

Return values:

ECX = status 0 — Correct, otherwise there was an error (you can find the error description in HASP documentation)

Function no. 5: HaspStatus()

Use this function to acquire the following information about HASP: memory size, HASP type, and LPT port. Input values:

BH = 05

BL = LPT port

ECX = password1

EDX = password2

Return values:

EAX = memory size

EBX = HASP type

ECX = LPT port Function no. 6: HaspID()

Use this function to learn the HASP ID. EAX contains the lower part of the ID, and EBX contains the higher part.

Input values:

BH = 06

BL = LPT port

ECX = password1

EDX = password2

Return values:

EAX = ID lower

EBX = ID higher

• ECX = status 0 — Correct, otherwise there was an error (you can find the error description in HASP documentation)

Function no. 50: ReadBlock()

This function reads a memory block from HASP. The address from which the reading will be performed is located in EDI. The block length to be read is located in ESI, and the address where the read data will be saved is located in ES:EAX.

To learn the actual address from which the reading will be performed, multiply the address in EDI by two, since the data is read by words.

Input values:

BH = 50 or 32h

BL = LPT port

ECX = password1

EDX = password2

EDI = start address

ESI = data block length

ES = buffer segment

EAX = buffer offset

Return values:

ECX = status 0 — Correct, otherwise there was an error (you can find the error description in HASP documentation)

Function no. 51: WriteBlock()

This function writes a memory block into HASP. The address from which the reading will be performed is located in EDI. The block length to be written is located in ESI, and the address from which the data to be written will be read is located in ES:EAX.

To learn the actual address into which the writing will be performed, you must multiply the address in EDI by two, since the data is written by words.

Input values:

BH = 51 or 33

BL = LPT port

ECX = password1

EDX = password2

EDI = start address

ESI = data block length

ES = buffer segment

EAX = buffer offset

Return values:

ECX = status 0 — Correct, otherwise there was an error (you can find the error description in HASP documentation)

Naturally, HASP uses other functions besides the ones just discussed, including functions such as: SetTime(), GetTime(), SetDate(), GetDate(), Writebyte(), and Readbyte(). I will not describe these here, however, since they are easy to understand if you have the HASP documentation. The HASP documentation is really wonderful, and it is absolutely essential for all developers.

HASP needs only about 128 bytes of memory, and a skilled programmer can use even this small amount well. For example, he might use the read data to decode a certain part of the program.

To avoid testing to see whether each byte was read correctly, it is possible to use a CRC test for the read data. This will confirm that the data was read correctly without revealing to a cracker the data that was to be read.

Another good way to use HASP is to write important data into the hardware key to be read and used later. This works because, when dealing with HASP, crackers have to write an emulator that emulates HASP drivers. Probably the most difficult part is writing into HASP memory, because the emulator mostly runs in a code area where writing isn't allowed. Crackers, therefore, ignore this function and don't emulate writing at all; they only return a 0 value in ECX to show that the service was successful.

Finally I'm coming to the HASP Envelope treat. HASP Envelope is a PE file encoder that encodes the original EXE file. When started, it will decode the original EXE in real time and run it. I don't want to deprecate its functionality at all, but removing the HASP Envelope is no problem unless correct decoding depends upon the connected hardware key. In this case, the return values aren't tested but are decoded directly, which is a cracker's nightmare. Of course, this protection can also be removed with a correct key, though in most cases the HASP Envelope will not be removed because of possible related problems (CRC

test).

HASP drivers, themselves, are well programmed, and it is difficult to debug them. They contain many anti-debugging tricks and other finesses against curious individuals. Still, even with all these measures in place, several crackers have managed to get through them to write an almost 100 percent functional emulator. Of course, this is the problem we continue to encounter with all commercial software protection. Naturally, a new version of HASP drivers appeared soon after that emulator was released, but you can be sure that it won't take long before a new emulator appears, too.

HASP is definitely an excellent protection program when correctly used. However, if program developers simply rely on HASP, and after calling a function only test the correctness of the return values, it won't really be difficult for a cracker to remove the protection from the program. HASP's biggest disadvantage comes from the added costs connected with selling a HASP-protected program. Therefore, HASP protection is really only worth considering for expensive programs that will not be distributed via the Internet.

Sentinel Hardware Keys

Sentinel, from Rainbow Technologies (http://www.rainbow.com), is the other popular hardware key option (see Figure 3.17). Because Sentinel is very similar to HASP, I will not describe it in detail. Sentinel documentation is as good and detailed as HASP documentation, making it easy to use.

cmp word ptr [esi], 7242 is correct

mov ax, 0002 ;sets the error number

pop edi pop esi

ret 000C

Value 7242 is a packet marker. If it is not found at the beginning, error 2, Invalid Packet, will be set.

You can easily find each API call for the hardware key service simply by looking for this test. The protection essentials are the same as for HASP, and it is again necessary to prevent emulation in the program memory.

No comments:

Post a Comment