Precompiled Assemblies
If you’re willing to sacrifice portability, precompiling your .NET assemblies is
undoubtedly the best way to prevent people from reverse engineering them.
Native code is significantly less readable than IL code, and there isn’t a single
working decompiler currently available for IA-32 code. Even if there were, it is
unlikely that they would produce code that’s nearly as readable as the code
produced by the average IL decompiler.
Before you rush out of this discussion feeling that precompiling .NET
assemblies offers impregnable security for your code, here is one other point to
keep in mind. Precompiled assemblies still retain their metadata—it is
required in order for the CLR to successfully run them. This means that it
might be theoretically possible for a specially crafted native code decompiler
to actually take advantage of this metadata to improve the readability of the
code. If such a decompiler was implemented, it might be able to produce
highly readable output.
Beyond this concept of an advanced decompiler, you must remember that
native code is not that difficult to reverse engineer—it can be done manually,
all it takes is a little determination. The bottom line here is that if you are try-
ing to protect very large amounts of code, precompiling your assemblies is
likely to do the trick. On the other hand, if you have just one tiny method that
contains your precious algorithm, even precompilation wouldn’t prevent
determined reversers from getting to it.
Encrypted Assemblies
For those not willing to sacrifice portability for security, Protector offers
another option that retains the platform-independence offered by the .NET
platform. This mode encrypts the IL code and stores the encrypted code inside
the assembly. In order for Protected assemblies to run in platform-indepen-
dent mode, the Protector also includes a native redistributable DLL which is
responsible for actually decrypting the IL methods and instructing the JIT to
compile the decrypted methods in runtime. This means that encrypted bina-
ries are not 100 percent platform-independent—you still need native decryp-
tion DLLs for each supported platform.
This approach of encrypting the IL code is certainly effective against casual
attacks where a standard decompiler is used for decompiling the assembly
(because the decompiler won’t have access to the plaintext IL code), but not
much more than that. The key that is used for encrypting the IL code is created
by hashing certain sections of the assembly using the MD5 hashing algorithm.
The code is then encrypted using the RC4 stream cipher with the result of the
MD5 used as the encryption key.
Reversing .NET 453