This article illustrates these contents in detail:
Download Visual Studio Community, Professional, and Enterprise. Try Visual Studio IDE, Code or Mac for free today. Compare editions.
- Abstract
- Obfuscation
- The .NET Application
- Anti-Reversing Implementation
- Obfuscated Code Analysis
- MSIL Code Analysis
- Final Note
Abstract
The purpose of this paper is to demystify the .NET assembly obfuscation as a way to deter reverse engineering. The primary concern for organizations is typically protecting their source code (as intellectual property) from reverse engineering. Obfuscation is a tactic that provides unified retitling of symbols in assemblies as well as other tricks in order to foil decompilers. Properly applied obfuscation increases protection against disassembling and decompilation by orders of magnitude, while leaving the application undamaged. A cracker can utilize the sensitive information from decompiled or disassembled code easily, so this article given a detail analysis of both obfuscated and de-obfuscated code.
Prerequisite
It is supposed that the following software and tools have been installed on the security researcher’s machine:
- Dotfuscator Professional Edition
- Red Gate Reflector
- Ildasm.exe
- Visual Studio 2010 or later version IDE
- .NET built assembly ( The target Software)
Obfuscation
Obfuscation is a distinctive anti-reverse engineering approach to cipher the actual source code by making it harder to comprehend because, as we have seen in earlier reverse engineering papers, the .NET written assembly could be decompiled or disassembled to the full source code very easily by employing various tools, such as Reflector, ILSPY, and Ildasm. The .NET code that executes under CLR is typically compiled into platform-independent intermediated code and such MSIL code is observable through reverse engineering. The hacker or reverse engineer can analyze almost the entire software mechanism and subvert the built-in security mechanism by obtaining sensitive information, such as copy protection mechanisms, and by exposing software licensing code, proprietary business logic and much more. Attackers can inspect the details of a software application for security flaws to exploit unique ideas to steal or crack the program information.
The goal of obfuscation is to create misperceptions about the actual source during decompilation. The interpretation analysis skill declines as the confusion builds. The source code is replaced with symbols and bizarre specifications in an obfuscated code, while the executable is preserved. As a result, attempts to reverse engineer the instructions fail because the translation is ambiguous. Thus, we can say that any obfuscator that confuses a decompiler poses even more deterrence to a human attempting the reverse engineering undertaking.
The .NET Application (Target)
This paper is committed to demonstrating or implementing obfuscation, usually referred to as an anti-reverse engineering approach. Hence, we have developed a custom C# windows form application that requires a license to register the user before activation. Such a mechanism, however, can be defeated through decompilation and disassembling and sensitive information, such as serial keys (here in this scenario), can be revealed easily.
Figure 1.1
So we shall execute the obfuscation tactics on the aforesaid application in order to make it secure in order that the hacker or reverse engineer cannot easily comprehend the source code of this application.
Anti- Reversing (Obfuscation) Implementation
Dotfuscation analyzes applications and makes them smaller, faster, and harder to reverse engineer and is a post-development recompilation system for .NET applications. The following section explaining the merits of obfuscation in synopsis view:
- Dotfuscator decreases the .NET executable program size by removing unneeded segments of an assembly. It is proven to be a performance-oriented process.
- It protects the .NET application from reverse engineering by mean of securing the source code so-called intellectual property.
- Dotfuscator dramatically increase the execution speed of the program by remove superfluous elements.
- It can integrate many assemblies into one by linking them and can implement the watermarking over source code to claim ownership.
- Dotfuscator verifies your application integrity at run time. If it detects some kind of tampering, then one of its notification services informs the corresponding organization about this misdeed.
- All the assembly names, classes, methods, and fields are renamed via the overload induction (patented algorithm) mechanism in obfuscated code.
- The Dotfuscator allows us to hide a user’s sensitive strings that are present in your assembly so that the reverse engineer could not utilize them for cracking.
- It detaches senseless metadata or unused code, compression, duplicate elimination.
Getting Started
Dotfuscator comes in a community edition and a professional edition. Some features are enabled and disabled in both of versions. There are typically three ways to run the dotfuscator projects:
- Standalone GUI
- Visual Studio integrated GUI
- Command line
We demonstrate obfuscation implementation via the Standalone GUI method. First, download the dotfuscator software from its vendor website (preemptive), and then install it properly. Launch the dotfuscator; when it runs, it prompts to select a project type as follows:
Figure 1.2
After selecting New Project, just give a meaningful name to the project and go to the Input tab. Here open the .NET target file:
Figure 1.3
After loading the .NET assembly, dotfuscator loads the corresponding files of the executable into IDE and displays a couple of obfuscation options. Here choose the contents that you want to protect:
Figure 1.4
Now we come to the Settings tab, where we can make some significant configurations for the impending obfuscated code. Here, we have to enable the control flow, smart obfuscation, and instrumentation options and leave the rest as the default. But one of the essential options is String Encryption, which enables or disables the encryption of the in-built strings in the assembly code, as follows:
Figure 1.5
Apart from the aforesaid setting, configure the “Rename” and “Control Flow” configuration, as follows:
Figure 1.6
After enabling the string encryption option from the general setting, you can configure the rest of the settings related to string encryption, because an attacker can locate sensitive code sections by looking for string references inside the binary. As per this assembly reference, the attackers can search for the serial key inside the disassembled or decompiled output. Dotfuscator addresses this problem by allowing you to encrypt strings in these critical segments of the .NET binary, providing an effective barrier against this type of attack, as follows:
Figure 1.7
After finishing with the necessary settings, build the projects in order to obfuscate the code by pressing the Ctrl +B button or hitting the “Build” button, as follows:
Figure 1.8
The build process usually consumes some time. After successfully obfuscating, you can see the build output in the form of logs showing what exactly happened behind the scenes, as follows:
Figure 1.9
You can refer to the Output tab in order to confirm whether the source code’s sensitive segments are encrypted or not. You can see in that tab that entire critical members, such as method name, property, and fields are renamed with a strange string name (eval), as follows:
Figure 1.10
So the aforesaid figure proves that the assembly code is obfuscated and it is relatively hard to analyze the source code even if you apply disassembling via reflector.
When the build process is over, a new version of this assembly is created in the project directory under the Dotfuscated folder, as in the following figure. The amazing thing about obfuscation is that the new version of this target executable is still intact and produces all the functionality as the previous version.
Figure 1.11
Obfuscated Code Analysis
It is time to determine to what extent the obfuscated code provides protection to the existing sensitive information in the assembly code. We can accomplish this objective through Reflector because it decompile the entire source code, as a reverse engineer usually does, in order to obtain or analyze critical data from the target executable.
So, launch the Reflector IDE and first open the original assembly (deobfuscated code). Here, it produces raw C# code but, as we know, the method getValidate is our prime interest because it has the serial key validation implementation. We can observe that this application would be registered if we enter the code #ABC12@ as the serial key.
Figure 1.12
Now, consider the effect of the obfuscated source by opening the executable in Reflector from the previously created Obfuscated folder. Here, the following figure first displays the encrypted code, which has some strange name as members of the RegisterUser class and later, in the second column, its deobfuscated counterpart code is the following:
Figure 1.13
The obfuscated code in the RegisterUser class creates a great amount of confusion for reverse engineers, because they cannot easily figure out the members of this class due to having the members in encrypted form. Take another sample code from the Button Register, which is basically calling the getValidate() method as defined in the original assembly, but in the obfuscated code it has a different name and is calling a strange method which does not exist in the assembly:
Figure 1.14
Finally, we move on to the most sensitive segment of the source code. As we have seen earlier, by decompiling the actual logic behind the serial key implementation in the original code, one can easily obtain the serial key information. But as the getValidate() method underwent obfuscation, it shows each and every sensitive string in a bizarre form that is almost impossible for a reverse engineer to guess:
Figure 1.15
So we conclude that the obfuscation process makes the reverse engineering job very hard in terms of guessing or obtaining sensitive information from the aforesaid decompiled figures both in obfuscated and de-obfuscated form. By applying proper obfuscation techniques, we can prevent the critical information from being revealed and thus justify the anti-reverse engineering.
MSIL Code Analysis
This section demonstrates the disassembled MSIL code of the corresponding source code in Ildasm. As we know, Ildasm is the key interest for reverse engineers in terms of getting sensitive information from the IL code itself, and even a target executable can be crafted to new specifications by modifying the bytes, rather than relying on the actual source code. So we have done much research on obfuscated code by decompiling it through Reflector and we are firmly convinced that this binary is not revealing any sensitive information. All in all, the binary intellectual property is protected from the hacker.
But reverse engineering can be advantageous with MSIL code, as we have seen in the previous reverse engineering papers, so we also have to ensure that the obfuscation is implemented on the MSIL code through dotfuscator. Either such .NET byte code exposes critical data or obfuscation is applied on both source code and MSIL code. Thus, we will first examine the de-obfuscated MSIL code by Ildasm.exe:
Original Code (De-obfuscated)
As we can see from the aforesaid MSIL, especially in the colored line, it reveals the serial key along with another reference string’s value.
IL_0029: ldstr “#ABC12@”
So the reverse engineer could easily manipulate cracking to expose such critical information. It is not secure yet. Now open the obfuscated executable and analyze the effects, as follows:
Obfuscated Code
We can see that this time the sensitive string is not showing in the MSIL and, especially, the hard-coded serial key in the source code is encrypted in the byte array:
IL_004d: ldstr bytearray (F2 A1 F4 90 F6 90 F8 90 FA 88 FC 89 FE 8D 00 60
02 77 04 6C 06 68 08 67 0A 2B 0C 5E 0E 7A 10 72
12 70 14 70 16 64 18 6A 1A 7D 1C 68 1E 73 )
02 77 04 6C 06 68 08 67 0A 2B 0C 5E 0E 7A 10 72
12 70 14 70 16 64 18 6A 1A 7D 1C 68 1E 73 )
One of the splendid features of dotfuscator is that it even prevents disassembling the MSIL in Ildasm so that the cracker cannot view any .NET byte code. To do so, just enable the Suppress IIdasm feature in the setting tab, as follows:
Figure 1.16
This special option would not allow the MSIL to be disassembled in any editor, such as Ildasm or Reflector. After obfuscating the targets with the Suppress Ildasm option enabled, open the target in the Ildasm. This time, we can observe that Ildasm denies opening the MSIL code:
Figure 1.17
Obfuscation Drawbacks
There is no doubt that the obfuscated code thwarts reverse engineering, but this mechanism is not reliable in the developer community because it has some pitfalls. The obfuscated code is especially subject to dependence on the platform and compiler characteristics. This creates many problems if either the platform or the compiler is changed. Code obfuscation just makes the process of reverse engineering a time-consuming and resource-consuming exercise; the cracker even can bypass the application from the obfuscated code by employing special approaches and obfuscated code might make debugging more difficult. So, finally, obfuscation makes the job complicated for cracker and reverse engineer but it does not claim 100% full-proof protection. There are a lot of ways to bypass the application from the obfuscated code and we will explain these tactics in the next paper soon.
Final Note
This paper illustrates the protection mechanism for intellectual property by implementing the obfuscation techniques over the .NET source code. We have achieved this process through Dotfuscator software and we have explained its various features, such as assembly member renaming, linking, pruning, and string encryption. This artifact applies the obfuscation in step-by-step fashion over a simple .NET application that asks a serial key to register the software so that a cracker cannot easily manipulate the disassembled or decompiled code through Reflector or the Ildasm utility. Finally, this article analyzed the obfuscated code with its counterpart original code and explained the special feature of dotfuscator of not allowing the disassembling of the MSIL code in Ildasm.
MASM is maintained by Microsoft and is an x86 assembler that consumes Windows and Intel syntax to produce a COFF executable. It is compatible for both 16 bit and 32 bit sources. Fortunately, Microsoft’s Visual Studio IDE endorses MASM programming tasks just by making a couple of project property changes. The prime objective behind this article is to introduce the power of assembly code in terms of speed and full control over programs which are typically not seen in other programming languages. Even though there are numerous editors and software available to do such a task in a standalone way, the aspirant system or security programmers who are only limited to .NET software IDE so far can enter into the real system programming world by using none other than visual studio IDE.
Prerequisite
In this article, we would get an understanding about creating both EXE and DLL using MASM with Visual Studio. So, the newbies should to have a brief knowledge of these technologies:
- MASM (Microsoft Macro Assembler) SDK Library
- VC++
Developing EXE using MASM
We shall demonstrate assembly programming by creating a simple Windows executable which typically shows “Hello World!” in a message box the moment it is initiated. It is very tricky to do such an implementation because Visual Studio 2010 IDE doesn’t offer any explicit templates for writing assembly code like C#, VC++ and VB.NET programming languages. It in fact has an in-built option to compile or run assembly programs.
Opening New Project
We shall have to create a VC++ project solution which later is accompanied with an assembly code file. Hence, open Visual Studio and choose an Empty Project of VC++ template type. There is no need to create a sub-directory for this empty solution, so uncheck the corresponding check box as follows:
Once the test_masm of VC++ type solution is created, go to the solution explorer and right click to choose Build Customization option as follows:
The Build Customization options open up the MASM compiler options which uncheck by default. This is the key option which must be enabled in order to edit and compile the native assembly code file.
Assembly Coding
As we have stated earlier, VS 2o1o doesn’t provide assembly file templates, however choose a project from the solution explorer and right click to add a text file which will be provided a *.ASM extension as follows:
Now, a blank text.asm file is added to our test_masm solution. Open it and paste the following assembly code, which is responsible for displaying a message box, as follows:
The assembly code file is written, but keep patience, this is not ready to compile or execute because some of important project settings are still remaining.
Ethical Hacking Boot Camp — 93% Exam Pass Rate
Mandatory Project Configurations
Successful execution of an assembly code file with Visual Studio IDE depends on an external library file, which will be available from MASM SDK. Hence, choose project Properties by right clicking it from the solution explorer. Here, choose General by expanding Linker and in the Additional Library Directories, insert the path of include, lib and macros directories as follows:
Next, come to the Input section in the Linker and mention the reference of masm32.lib file as additional dependencies:
It is not required to generate a manifest file for such manipulation, hence disable it as follows:
Now, come to System from the Linker and set Windows in the subsystem section as follows:
Finally configure the code entry point as the start from the Advanced option in the Linker, which determines the code execution flow. We can identify the entry point of the ASM file from the .code section.
Now come to the Microsoft Macro Assembly section from the solution properties which appears the moment when we add an assembly file in solution directory, otherwise it shall be hidden. Here, set the directory name where the MASM SDK was installed earlier as follows:
Finally, everything is ready and the solution is compiled. If the whole configuration is correct, then a test_masm.exe file is created in the Debug folder of the solution.
Testing and Debugging
It is time to test the executable. When the exe is clicked, a “Hello World!” message box would appear as follows:
We can even debug the assembly code by inserting a breaking point as a specific location, and through the Register window in the Debug menu, we can observe all the CPU registers with corresponding flags as follows:
We shall cover the advanced debugging of an application in later articles. The following image shows the assembly code in debug mode which helps us to understand what is happening behind the scenes.
Although this section is not relevant to this article, but just for knowledge point view, we can disassemble any C++ file to its corresponding ASM code. The Visual Studio IDE is inbuilt with a Disassembly option, which is very helpful to detect a run time bug such as buffer overflow in the code via converting the source code file to an assembly code file as follows:
Developing DLL using MASM
In the previous section, we have seen how to create an EXE file using MASM with VS 2o10. We can also develop a library (DLL) by using MASM programming much like other technologies such as C#, VB, and C++. Therefore, the method can be utilized in the other client application in that created DLL. The procedure of generating a DLL is almost the same as EXE but requires some subtle configuration. First of we have to set Configuration type as DLL in the General section because now we are dealing with DLL. Such modification can happen from solution properties as:
And as we all know, DLL files are libraries which contain method definitions. Entry point is typically absent in the DLL file. Hence we have to change this setting as follows:
Finally, add a text file as masmlib with ASM extension in the solution like earlier and place the following code, which typically contains a testing method which will show some alert during the load and unload of DLL in the client program as follows:
Finally, compile this program and test_masm_dll. The DLL file would be created in the Debug folder which can referenced in the C++ program or in the MASM client program itself.
Final Note
So, we have seen how to create both EXE and DLL files using MASM programming languages employed with visual studio IDE. In fact, such a task could be achieved by hard-core MASM SDK but .NET programmers typically fear assembly programming due to strange syntax and platforms. Assembly language programming opens a new horizon of advance coding in terms of faster code executing, exploit writing and shell-coding. Programmers are often comfortable with Visual Studio due to having numerous in-built features and functionality. Hence, this article is dedicated to those professionals who are planning to shift towards system programming without leaving the .NET framework.