Techniques for Automating Obfuscation

[This documentation is for preview only, and is subject to change in later releases. Blank topics are included as placeholders.]

Summary: This article explains how to automate the obfuscation process.

Applies to: .NET technologies

by Naga Santhosh Reddy.V and Nidhi Khetarpal

Introduction

The rich Microsoft intermediate language (MSIL) of the .NET Framework is focused on application flexibility and inherently provides significant information about how an application was written. Obfuscation technology helps to secure the intellectual property contained in .NET Framework applications. Obfuscation tools rename symbols and rearrange code blocks to complicate decompiling. They also might encrypt strings that contain sensitive data.

These tools also determine exactly which parts of your program you're really using (down to the method level). From there, the tools can parse out unneeded pieces, leaving you with the smallest possible executable. By removing unnecessary program elements and renaming identifiers to shorter names, an obfuscator can actually speed up programs. And when combined with obfuscation and pruning, assembly linking provides a powerful packaging solution for .NET Framework applications.You need automation not only for obfuscation but to cover related tasks, such as extraction, re-signing, and uploading. Automating obfuscation in such scenarios will save effort and time.

Note

For more information about obfuscation, see Thwart Reverse Engineering of Your Visual Basic .NET or C# Code.

There are mainly two ways to automate obfuscation:

  • Post-build commands

  • Batch files

Overview of Obfuscation Automation by Using Post-Build Commands

By using post-build commands, you can obfuscate an assembly into a temporary directory, copy the obfuscated assembly over the original, and then clean up your temporary files. The effect is almost as though the IDE and compiler performed the obfuscation automatically.

Here are the post-build action commands that make this happen:

  1. Obfuscate the assembly into a temporary directory:

    "C:\Program Files\Microsoft Visual Studio 11.0\PreEmptive Solutions\Dotfuscator and Analytics Community Edition \dotfuscator.exe" /q /p=SourceDirectory=$(TargetDir),SourceFile=$(TargetFileName) $(ProjectDir)Dotfuscator.xml
    

    This command will depend on the type of obfuscator you use. Here, for example, the code uses Dotfuscator Community Edition, which is provided free with Visual Studio tools. After you run this command, the obfuscator gets the file from the target directory and puts the obfuscated version of it in a newly created folder named "dotfuscator" in the target directory.

  2. Copy the obfuscated assembly over the original:

    copy $(TargetDir)Dotfuscator\$(TargetFileName) $(TargetDir)$(TargetFileName)
    
  3. Clean up the temporary files:

    rmdir /S /Q $(TargetDir)Dotfuscator
    

    You need to create a Dotfuscator.xml file similar to the following in the root of your project folder:

    <?xml version="1.0" encoding="utf-8" standalone="no"?>
    <!DOCTYPE dotfuscator SYSTEM "http://www.preemptive.com/dotfuscator/dtd/dotfuscator_v1.1.dtd">
    <dotfuscator version="1.1">
       <propertylist>
          <property name="SourceDirectory" value="This Path Will Be Replaced By Visual Studio" />
          <property name="SourceFile" value="This Filename Will Be Replaced By Visual Studio" />
       </propertylist>
       <trigger>
          <filelist>
             <file dir="${SourceDirectory}\" name="${SourceFile}" />
          </filelist>
       </trigger>
       <output>
          <file dir="${SourceDirectory}\Dotfuscator\" />
       </output>
    </dotfuscator>
    

Overview of Obfuscation Automation by Using a Batch File

Another alternative to achieve the same result is to create a batch file. The automated obfuscation process performs four main functions: extraction, obfuscation, re-signing, and uploading:

  1. Extractor extracts/copies files to a temporary folder.

  2. Obfuscator obfuscates the files.

  3. Re-signer signs the files.

  4. Uploader organizes the files in the output structure required by the installer.

1. Extraction:

All files that need to be obfuscated are extracted or copied to temporary folder Unobfuscated. Whether to extract or copy will depend on your project requirements.

Command to extract

msiexec  /a " D:\Obfuscated\VSBuild\xyz.msi"  /qb TARGETDIR=" D:\Obfuscated \UnObfuscated" >>" D:\Obfuscated \output.txt"

Here the .dll files are extracted from the .msi that's generated by Visual Studio (using the InstallShield Limited Edition template) or by Windows Installer XML to a common folder that acts as an input folder to the obfuscator.

Command to copy

ROBOCOPY  " D:\Obfuscated\VSBuild "  " D:\Obfuscated \UnObfuscated" *.dll >>" D:\Obfuscated\output.txt"

Here all the .dlls are copied from the VSBuild folder to a common folder that acts as an input folder to the obfuscator.

2. Obfuscation:

This command depends on the type of obfuscator you're using. Here, Dotfuscator 4.9 Professional is used.

Command to navigate to target path

cd "C:\Program Files (x86)\PreEmptive Solutions\Dotfuscator Professional Edition 4.9"

The target path is the location of the obfuscator.

Command to obfuscate and generate output

dotfuscator " D:\Obfuscated\settings.xml" > " D:\Obfuscated\OutputLogs\DotfuscatorOutput.txt"

Dotfuscator.exe uses settings.xml to obfuscate the .dll files present in the input folder and also generates user-friendly output.

3. Re-sign:

The obfuscator might mess up the signatures of the previously signed assemblies, therefore you need to sign the assemblies again (post obfuscation).

Command to navigate to target path

cd "C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin"

Command to re-sign the .dll files and generate signing output

sn.exe -R "D:\Obfuscated\Dotfuscated\xyz.dll" "D:\Workspace\Keys\abc.snk" >> "D:\Obfuscated\OutputLogs\signingOutput.txt"

4. Arrange in output structure:

The output structure is project specific and should be in accordance with the installer.

Command to copy selected files from Dotfuscated to ObfuscatedVSBuild structure

ROBOCOPY " D:\Obfuscated \Dotfuscated" " D:\Obfuscated \ObfuscatedVSBuild\SubFolder" [ abc1.dll abc2.dll abc3.dll]  

Command to copy all files from Dotfuscated to ObfuscatedVSBuild structure

ROBOCOPY " D:\Obfuscated \Dotfuscated " " D:\Obfuscated \ObfuscatedVSBuild \AllObfuscatedAssemblies" *.* >>" D:\Obfuscated \OutputLogs\output.txt"

Note that the previous commands are based on the following folder structure in D:\Obfuscated\:

  • VSBuild: Input folder from which files are extracted and copied to temporary folder Unobfuscated.

  • Unobfuscated: Temporary folder to hold all unobfuscated assemblies copied or extracted from the VSBuild folder. Also acts as input folder to the obfuscator.

  • Dotfuscated: Obfuscator picks assemblies from the Unobfuscated folder and puts obfuscated assemblies in this folder.

  • ObfuscatedVSBuild: Obfuscated signed assemblies in the Dotfuscated folder are rearranged in subfolders in ObfuscatedVSBuild, per installer requirements.

  • OutputLogs: Output Folder to hold all output logs.

  • Settings.xml: This is described in the next paragraph.

Before you start obfuscation by using a batch file, you need to have settings.xml in place. You can create settings.xml manually or from the obfuscator GUI by creating a new project. A sample is shown here:

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE dotfuscator SYSTEM "http://www.preemptive.com/dotfuscator/dtd/dotfuscator_v2.3.dtd">
<dotfuscator version="2.3">
  <input>
    <loadpaths />
  <!—Provide name and location of input assemblies-->

    <asmlist>
      <inputassembly refid="1c6cdd30-c3a7-4739-a01f-1ea44358e758">
        <option>honoroas</option>
        <option>stripoa</option>
        <option>library</option>
        <file dir=" D:\Obfuscated\Unobfuscated" name="abc.dll" />
      </inputassembly>
      </asmlist>
</input>
  
<output>
    <file dir="${configdir}\Dotfuscated" />
</output>
  
<renaming>
<!—Exclude resources and overloaded methods from obfuscation-->
    <option>xmlserialization</option>
     <excludelist>
       <type name="MyCompany.MyProduct.Outlook.OutlookRibbon" excludetype="false">
        <method name="&lt;GetActiveOutlookWrapperItem&gt;b__3e" signature="bool(MyCompany.MyProduct.Outlook.Wrappers.ExplorerWrapper)" />
        <method name="&lt;GetActiveOutlookWrapperItem&gt;b__3f" signature="bool(MyCompany.MyProduct.Outlook.Wrappers.InspectorWrapper)" />
        <method name="GetActiveOutlookWrapperItem" signature="object(object)" />
       </type>
    </excludelist>
    <mapping>
      <mapoutput overwrite="false">
        <file dir="${configdir}\Dotfuscated" name="Map.xml" />
      </mapoutput>
    </mapping>
    </renaming>
  <controlflow level="high">
    <!—Exclude overloaded methods, similar to renaming-->
    <excludelist>
         <type name="MyCompany.MyProduct.Outlook.OutlookRibbon">
        <method name="&lt;GetActiveOutlookWrapperItem&gt;b__3e" signature="bool(MyCompany.MyProduct.Outlook.Wrappers.ExplorerWrapper)" />
        <method name="&lt;GetActiveOutlookWrapperItem&gt;b__3f" signature="bool(MyCompany.MyProduct.Outlook.Wrappers.InspectorWrapper)" />
        <method name="GetActiveOutlookWrapperItem" signature="object(object)" />
     </type>
    </excludelist>
  </controlflow>
  <sos mergeruntime="true">
    <option>dontsendtamper</option>
  </sos>
  <smartobfuscation>
    <smartobfuscationreport verbosity="all" overwrite="false" />
  </smartobfuscation>
</dotfuscator>

Other Considerations

Following are some considerations to be aware of:

  • Resources that are related to textual content or graphics should be kept out of scope for the obfuscation process. Otherwise the mapping with the main application might get corrupted as they are encrypted by obfuscation, and this might cause problems.

  • Exclude overloaded functions and even functions that call overloaded functions. If you don't exclude them, mapping to the correct overload of the function might fail. This again depends on the type of obfuscator used. (In Dotfuscator, you can exclude resources or overloaded functions from renaming on the Renaming or Control Flow tab.)

  • The obfuscator prompts for any missing required .dll files that are used internally and not present in the global assembly cache. You need to add these .dll files to the Unobfuscated folder because Dotfuscator searches for them in the global assembly cache if they aren't found in the local folder.

How to Verify Obfuscation

You can verify obfuscation by running Ildasm.exe from the Visual Studio command prompt and opening the assembly in it. For an obfuscated assembly, it will show the dotfuscator attribute and the names of functions will be replaced with literals like "a" and "b."

Also, you can see the output generated.

Tradeoffs and Out of Scope

Following are some tradeoffs and some considerations that are outside the scope of this article:

  • The process is time consuming.

  • You can't completely protect your intellectual property. Because the code is on the client machine, a determined hacker with lots of time can study the code and data structures enough to understand what's going on behind the scenes. Obfuscators do provide value in defeating most decompiling tools and preventing the casual hacker from stealing your intellectual property. They can make your code as difficult to reverse engineer as optimized native code. 

  • In Java, obfuscation limits the use of the Reflection API on the obfuscated code.

  • Obfuscating your code might make debugging more difficult or impossible. Many of the third-party obfuscators have features that help with debugging, however, such as a file that shows how obfuscated symbol names correspond to original symbol names.

Conclusion

Finally, some concluding considerations:

  • Protecting software is as important as protecting hosts.

  • Watermarking, tamper-proofing, and obfuscation are important tools for protecting software.

  • No technique can prevent all attacks.

  • The goal is to increase the difficulty for the attacker.

About the Authors

Naga Santhosh Reddy.V is a consultant at Microsoft Global Services India who specializes in the .NET Framework, SharePoint 2010, Advanced Algorithms, and Office development in Visual Studio. Nidhi Khetarpal is a consultant at Microsoft Global Services India who specializes in developing solutions for Microsoft Office and SharePoint 2010.

See Also

Other Resources

Thwart Reverse Engineering of Your Visual Basic .NET or C# Code

Obfuscation