Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Protect .NET String values by hiding them into machine code DLL
If you read the article it means we do not need to explain the importance of .NET source code protection. It means you know there are big amount of "whys" for why we must to secure .NET project’s source code. However code protection does not receive from obfuscation, but instead from writing secure code, there are a bunch of conditions where we are simply not able to distribute our source code for various "whys".
Let's talk about .NET String values presented in our source codes. Since Strings can provide useful clues for anyone trying to reverse-engineer our code it makes sense to protect .NET String values from spying eyes. It will not prevent an absolute hacker from deciphering the conversion and seeing your data. However, for example, an attacker trying to break a licensing routine would first focus attention on Strings having to do with licensing to locate the appropriate spot of code. Skater can make this more difficult by encrypting the strings in your .NET assembly. This is done by inserting a decryption routine into the assembly and calling the decryption code at runtime to return the original Strings. Although String values are still located inside obfuscated .NET assembly (dll or exe). Some of the modern decompilers have learned how to decipher the obfuscated Strings. They break the decryption routine and can show the String values presented in decompiled source code.
Strings are vital code parts. It makes sense to create them in native code. Skater generates a C++ written DLL with the protected Strings. This Skater’s option protects algorithms by coding Strings in native code and store them in a separate machine-code DLL. Native code can be reverse engineered but it is a very tough job. Plus, Strings are encrypt-protected in the DLL.
To learn how it works let’s start a small .NET project. We will be creating a simple .NET Console application that includes a single “Hello World!” string that we want to protect.
private string str = "Hello World!";
Private str As String = "Hello World!"
Take a look what we got after the ConsoleApplication1.exe decompilation:
We can see the non-obfuscated "Hello World!" string in the decompiler's interface. Decompilation tools can decompile a .NET assembly directly back to a high level language like C#, VB .NET, or C++. Ok, we are ready to obfuscate the sample ConsoleApplication1.exe executable by using Skater .NET Obfuscator. Open the exe file in . In the Obfuscator interface go to Strings tab and select 'Keep Strings Inside The Output Assembly' under 'Strings Store Location'.
When you run the obfuscated ConsoleApplication1.exe it produces the same result. Take a look what changed inside the simple program. We need to run the decompiler again against the new obfuscated executable and it will give us the following decompilation result:
The “Hello World!” string has been allocated by Skater into a public variable then it was encrypted. We can pretty easily spot the encrypted string inside that decompiled script in the figure above. Should this make it pretty obvious that our code is protected? Is it not simply too easy to decrypt the safe .NET code? Almost. An absolute hacker still can choose a password for the encrypted string and decompile it. It will take more time but it is not impossible. So what can we do more to protect String values in our .NET algorithms?
is using native code to protect vital parts of source code. It protects our algorithm by coding Strings in native code while preserving the user interface in .NET. Skater extracts String values and uploads into C++ source code. Then it compiles the C++ written code and locate the resulting machine-code library (appExtension.dll) file in the output directory. When our final obfuscated assembly runs it will be calling this DLL through platform invoke (Pinvoke Interop) as that is the shortcut way to call the machine-code from .NET app. To see that go to obfuscate the ConsoleApplication1.exe executable again by using Skater .NET Obfuscator. Open the exe file in Skater Obfuscator. But for this time, in the Obfuscator interface go to Strings tab and select 'Strings Stored in Separate DLL (recommended)' under 'Strings Store Location'.
After the obfuscation is done the native-code DLL will be located in the same directory of our output assembly path. Then we need to specify the Separate DLL file name. By default the name is 'appExtension'.
After the obfuscation process done take a look what changed inside the obfuscated ConsoleApplication1.exe program:
As shown in the decompiled script above the "Hello World!" string is now located in the separate appExtension.dll library file. That library is an unmanaged binary machine code COM file. It is not accessible/openable by .NET assembly browsers.
So our source code is reliably stealthy now from the usual means of .NET deciphering. Although it does not imply that our .NET program is totally protected. Of course, this is in some measure much complicated to figure out our algorithm than before, but it is not impossible. Machine code can be reverse engineered but it is a very tough job, particularly when the program gets larger and structurally composite.
A disadvantage with this technique is that we will have to distribute the additional Skater-generated COM DLL to hide our vital code parts in native code. As might be expected, we would prefer to deal with managed code only, but depending on the .NET product, the separated COM library is an opportunity. As a conclusion, no matter what we do, if our code is placed at the end-user's PC, it is not safe. As long as the code is placed at the end-user, all we can do is to make it as unwieldy as possible to get to the original source code, with any luck avoiding most hacker's attempts.
Note. You must include the Separate Strings DLL into your product distribution package and install your final .NET assembly strictly together with that DLL file. Otherwise your .NET assembly will not work. This mechanism is designed to ensure that .NET assembly browsers cannot see and decipher the output assembly’s String objects. It makes String values completely invisible.