Anti-Tampering Guidelines

The more malicious programmer can defeat any system given enough time. The goal here is to make that effort as reasonably difficult as possible. Defeating the mechanism should not be as simple as doing a one byte patch to the application which calls the license system. Rather, it should be much more confounding.

Below are a few basic guidelines which the software publisher might follow while developing their application. Note that these guidelines may go against certain accepted coding practices. The software publisher will have to decide if the tradeoff is worth making. Additional guidelines may be available from license system vendors.

Do not compare the challenge result immediately after calling a License Service API function. Rather, save the result and compare later. This is security by obscurity.

Incorporate an internal and obscure checksum over the code which deals with the license system and with the challenge verification. Even obscure the checksum code if you can.

If applicable, take over any debug and single-step vectors which might be used by debuggers. Great care should be taken when doing such an advanced measure.

Do unique things with the challenge result before doing a final compare. Touch the result often without doing anything with it (i.e., do meaningless reads, compares, subtractions, etc.). In situations where a hardware monitor is being used, this may increase the number of hardware breakpoints which occur, thereby further confusing the intruder.

Verify the challenge result more than once. Provide a faux compare immediately after the LSRequest() and LSUpdate(). This will confuse any intruder.

Don't do the comparison with a simple compare. Rather, perform some mathematical operations on the result, computing another result which is verified later in the code.

For platforms which permit self-modifying code, and if the actual challenge algorithms are included in the code, hide them through encryption of the code. Decrypt only long enough to verify a challenge and then re-encrypt it. Checksum the code which calls the encrypt/decrypt routines to prevent alteration. Have the entry point in the challenge algorithms verify the code offset (if applicable) from which it was called. Encrypting the algorithms makes them more difficult to locate in the code. Also encrypt the actual secrets if you choose to include them into your code.

If the host operating system permits, place most of the challenge code and data into discardable overlays.

Use different challenge values for LSUpdate() than that used in LSRequest().

Choose unique sets of secrets for each different application produced by your company. Thus, if one set of secrets is compromised, then only one application is compromised.

Choose a subset of unique secrets for each application version. Thus, if a set of secrets is compromised for a particular version, those secrets are useless on the next version.

Call LSUpdate() periodically, as recommended by the LSQuery() function. If no recommendation is provided, a guideline of once every 24 hours can be used.

These are just a few of the possibilities which the software publisher can consider. Think about anti-virus techniques and the measures taken to prevent code modification. Those same anti-tampering techniques are applicable here.