It is a good idea to protect against this kind of attack/workaround. I
would even obfuscate the code, encrypt the XML string of the public key in a
hardcoded string field using the obfuscator to encrypt the field string.
Then on startup (or other) get the public key string, compare against the
public key bytes of the signed assembly. Now I ~think this proves that your
code has not been modified as the public key on assem matches what you
stored in string at build and also that user/hacker did not mod your code
and/or "re-sign" it with there own key pair. So now you have reasonable
assurance your public key is the one you set and can use it to verify
digital signature of lic file(s). However, all this does not *prevent one
from modifying your code and removing all these checks and just hard coding
"True" from one or more of your test points - hence bypassing all your PKI
stuff and lic files. However nothing can stop that attack. All programs on
a user HD (even native EXE) are vulnerable to this. As it turns out
however, the obfuscation will most likely make this attack not worth the
effort at worst and improbable at best. I recommend XenoCode obfuscator
with conservative settings and to encrypt your required strings and/or
Watermark strings.
Also keep your lic file simple xml and one digital signature signed by the
private key in one of the elements. Require that the lic file exist by name
in the same dir as the EXE or dll. This makes it easier for you and the
user. You have one simple rule and don't need edge logic to test if exists
here or there or in ISO storage etc. Keep it simple with one rule.
"MyAppLic.xml" or similar must exist in exe dir and digital sig must verify
using pub key above - simple. However the same Lic will work on anyone's
machine unless you also use a Machine hash or something unique the Users
machine/sw. You could use a unique Watermark in each exe, but that requires
a new build for each customer (a pain). You could also use a sha1 hash of a
combination of some unique info on the machine such as Machine Name, domain,
bios name/version, etc. However I would not use things like User Name or
IPAddress because if I install product using staceyw, I may want to also run
it when logged in as Admin or other and verify would fail. Domain name is
probably not good either as some users connect to different domains and roam
around. Also I do change IPs and nics at times so IP and MAC is not good
either IMO. Using the Windows GUID as shown in the article did not work on
my Windows 2003 server either (If I remember) so not sure I would trust that
in all cases. So the following are probably ok, but new key would need to be
generated if any of them change:
- Machine Name
- Windows Version
- Windows DIR path
- RAM size
- CPU Name
- BIOS Name & Ver
Unlocking by Product Key (i.e. XXXXX-XXXXX-XXXXX-XXXXX) is another option,
but less secure simply because you have less bytes and brute force attacks
are simpler and need have a secret at client side. Most of the bytes could
be X bytes of the machine hash that is hashed using hmacsha1 or something
using a concat string of all the above machine strings and a shared secret
both sides know. client side secret is encrypted using the Obfuscator
function. You give up some lic security for easy of user to unlock the lic
with simple product key - which can be emailed or given out over the phone.
The down side is more probable to have matching hash for multiple users (as
many can have same machine name, Windows version *and we can't fit the whole
20 byte sha1 hash in 20 or 25 bytes of Base36 format) and the shared secret
can be gotten using a debugger or something while stepping through the code
as runtime. However if you accept the down sides, it can be a nice option
for your sw and users that may be "good enouph".