| |
Developing Applications Using The SoftwareShield System
> Anti-Hacker
Guide > Anti-Hacker Standard Practices
Anti-Hacker Standard Practices
There
are two specific areas of interest to you as a developer using the SoftwareShield
System.
- What can you, as a developer, do
to make you implementation of SoftwareShield licensing as secure as possible?
- What can you, as a developer, do
on an ongoing basis, in order to make your software as secure as possible?
Anti-hacker standard
practices are just that - standard. They should not be limited solely
to your implementation of the SoftwareShield System and the code around
it. So, in fact, the two concerns above are one and the same. Below are
several simple "tricks" you should consider, that when used
together, will force crackers trying to defeat your system to invest incrementally
more time in doing so. When used in conjunction with the SoftwareShield
System, their job will be unpleasant to say the least. Please be sure
you understand that the purpose of playing the "game" is an
impasse. (see: Anti-Hacker Guide).
Here are several standard things you should do in any
software you wish to protect to slow down crackers:
- Never
give any registration or protection testing function a self describing
name. Never use a function name like "IsActivated".
Crackers will quickly locate these names (in most high level languages)
and simply remove or rewrite them.
- Use
return values from the ClientProtector somehow in your processing of a
standard program function. This can be particularly effective
to slow down crackers. You might implement this by using a pre-set parameter
value inside one of the Authorization Definitions as an XOR "key"
to be used with a stored value in your binary. When you XOR them together,
it produces a value that must be used by (for example) the "save"
or "print" function. If the value is not computed correctly,
your program will not save or print correctly. Don't put up an error message
if the value isn't correct, instead, simply make the programs output incorrect.
It can be difficult for a cracker to detect this, regardless of whether
he can even determine if this is simply an error or a protection.
- Avoid
unnecessary error messages. If your program gives an error message
after an unsuccessful activation attempt, the crackers will be able to
quickly locate the error message and know that at some point in the call
stack immediately before it - a protection or activation-test function
call failed.
- Wait
using a timer in a separate thread to provide error messages.
When an error message is unavoidable, you may wish to set a timer in a
separate thread that will fire several seconds or minutes later to warn
the user and take action. This makes tracing back to the protection call
that caused the timer to start up more difficult and will slow the cracker
down.
- Encrypt
any and all protection strings. When an error message in unavoidable,
be sure to dynamically generate the message string itself. The best way
to do this is to store it in encrypted form in the binary and decrypt
only immediately before you need it. This makes searching for the string
very difficult. Better yet - encrypt all your programs strings.
- Use
random tests for activation. Test that the program is correctly
activated at random time intervals; hours, days or even weeks after it
was first installed and run. Possibly test only after certain key functions
(unrelated to activation) are used. This will often be missed by crackers
and again will slow them down or make their crack worthless.
- Don't
start the activation test for several seconds (or even minutes) after
the activation. This applies to a few different scenarios where
the ClientProtector is not solely responsible for activation. IE:
Where your program interprets the value of parameters or it must inspect
activation of individual Authorization Definitions. Alternatively, you
may wish to store any Activation Codes input by the user temporarily in
memory and after a brief pause try to activate them using the ClientProtector
interface. You may even wish to require the user to restart the program
before you input the value. This makes it difficult to trace and will
slow the cracker down.
- Use
CRC checksums in your application and dlls. Be sure you have
read the CRC Checking section for more
information. Have your EXEs
check themselves, check other DLLs,
or even have them check each other. Consider computing a checksum on just
a small section of the file itself instead of the whole thing - this makes
the crackers job more difficult.
- Use
Anti-Debugging tricks. Be sure you have read the Anti-Debugging
section for more information on how to slow down crackers by having your
software resist debuggers.
- Use
Anti-Disassembling tricks. Be sure you have read the Anti-Disassembling
section for more information on how to slow down crackers by having your
software resist disassembling.
- Use
more activation checking routines than the minimum necessary.
You should test in several places, and in places where the crackers might
not expect it. Check at random time intervals too (see above). One routine
requires a time investment from the cracker to remove, then more routines
will require even more time to break.
- Use
Honey Pots. A "Honey Pot" is a fake or decoy routine
(or set of routines) you code into your program that seem to check activation,
but in fact - does nothing. Have it write and read registry keys, manipulate
files, jump all over in memory computing useless values and doing meaningless
comparisons. Use your imagination here. Name honey pots to draw the crackers
attention (like "CheckReg").
The point is to waste their time with a ruse.
- Wrap Activation testing routines in ridiculously long code.
Consider using several long procedures which do a huge
amount of unnecessary (but seemingly meaningful) processing. At some point
during this useless processing, legitimately check the activation. Consider
even checking it two or three times in different ways. This make the crackers
job of tracing through this giant jumble of assembly looking for the "real"
code a more frustrating experience. This will slow them down. Your testing
routines can safely take 5 to 20 seconds to execute on a reasonably fast
machine.
- If
you use a demo version of your software with limited features, make sure
you don't have "grayed out" buttons or menu options.
A cracker can simply change the enabled property of these controls which
will effectively make your features visible again. It is always preferable
to dynamically create these controls only when they are available.
- If
you use a demo version of your software with limited features, consider
not distributing the actual binary code to execute those functions.
The simplest way to do this is to include the "paid version only
code" inside a DLL which is called from your program when it is legitimately
purchased. Then when a customer purchases your software, give them an
Activation Code to release your SoftwareShield protections as well as
the required DLL containing the code for the missing features.
- If
your program has been cracked, release a new version. This
is probably the most important principle which makes all the above tricks
worth while. Once you have wasted the crackers time as much as possible,
slowing them down with all these tricks (and others you may think up yourself),
you must immediately make all their hard work go to waste - release a
new version fast. Change a few things around, re-organize the code, update
the version number, test - and re-release. The cracker will have to start
all over again. Reaction time is important too. Expect to move quickly
if a crack is released. Try and release a new version as rapidly as possible
to maximize the frustration effect.
|