Code Encryption
Babel Obfuscator’s Code Encryption feature allows users to encrypt their entire code to protect it from reverse engineering.
Babel Obfuscator transforms the original method IL instruction into a new set of custom instructions that can include various obfuscation techniques that it makes more difficult to reverse engineer or modify the code. Once the new representation of the code has been constructed, it is encrypted using the chosen encryption algorithm (such as AES) to make it even more difficult to understand or modify.
At runtime, when the protected assembly is loaded into memory, the Babel Virtual Machine (BVM) is used to decrypt and execute the protected code. The BVM is a lightweight runtime engine included with the obfuscated assembly and provides the necessary functionality to decrypt the code, execute it, and ensure it runs correctly.
Deploying on FIPS-enabled hosts? Because Code Encryption decrypts method bodies at runtime through the platform crypto provider, a container running on a FIPS-enabled host without a certified OpenSSL FIPS provider can fail to start. See FIPS Compliance for the cause and the fix.
Code Encryption offers a strong level of protection against reverse engineering and intellectual property theft, but they also come with trade-offs in terms of application performance and complexity, so it is not recommended to apply it to the entire codebase. Instead, it is better to selectively apply this obfuscation technique to the most sensitive parts of the code that require protection while using other obfuscation techniques for the rest of the code. This way, you can strike a balance between security and performance.
Before Code Encryption
After Code Encryption
The Babel Code Encryption is a completely managed solution. This means that the encrypted methods are not replaced by native code targeting a specific platform. This managed method solution ensures that the cross-platform nature of the .NET Framework is not compromised and allows the Just-In-Time (JIT) compiler to optimize code for the target CPU.
Code Encryption Limits
The Babel Code Encryption feature is not supported on .NET MAUI and Blazor assemblies due to the following key reasons:
Platform Constraints
• Ahead-of-Time (AOT) Compilation: Platforms like iOS, which are central to .NET MAUI, rely on AOT compilation. This process compiles code into native binaries ahead of time, eliminating the possibility of dynamic code generation or modification at runtime, which is essential for code encryption and decryption.
Limited Support for System.Reflection.Emit Namespace
• Restricted IL Generation: The System.Reflection.Emit namespace, which is used for generating IL dynamically, has limited or no support on key platforms like iOS and WebAssembly (used by Blazor). Since code encryption often relies on dynamic IL manipulation, this limitation further hinders the implementation of encryption features in MAUI and Blazor.
Security Restrictions
• Sandboxed Environments: Both MAUI and Blazor operate in environments where apps are sandboxed for security. Platforms like iOS impose strict security measures that prevent any form of runtime code modification to protect against malicious code execution, making dynamic encryption impractical.
• Risk of Code Injection: The dynamic code generation required for encryption and decryption poses significant security risks, including potential code injection vulnerabilities. MAUI and Blazor frameworks prioritize security by avoiding such risks.
Due to these constraints, .NET MAUI and Blazor do not support the Code Encryption feature, focusing instead on secure, portable, and platform-consistent development practices.
Methods That Cannot Be Encrypted
Within a supported target, Code Encryption is applied on a per-method basis, and a few methods are automatically left unencrypted:
• Instance constructors (.ctor) are never encrypted. This is by design: an instance must be fully initialized through its base constructor chain before it is used, and that guarantee cannot be preserved if the constructor body is relocated by Code Encryption. Note that this applies to instance constructors only — static constructors (.cctor) are not affected and are encrypted like any other method.
• Methods with an unsupported signature are skipped automatically. Code Encryption relocates a method body into the Babel Virtual Machine (BVM) and calls it back through a uniform argument marshaller, so a few signature shapes cannot be expressed and are left unencrypted:
- Generic methods — reported as
EM0003. - Unsupported return types — a
ref(by-reference) return, a pointer return, a function-pointer return, or aref struct(by-reference-like) return such asSpan<T>/ReadOnlySpan<T>. Reported asEM0001. - Pointer or function-pointer parameters — reported as
EM0002. ref struct(by-reference-like) parameters such asSpan<T>/ReadOnlySpan<T>— reported asEM0013.
These limits are inherent to the .NET runtime: a pointer or a ref struct cannot be boxed, so the BVM’s argument marshaller cannot carry it. Everything else is supported, including ref/out/in parameters (of every element type, including structs, enums and by-reference reference types), value-type and generic-instance returns, exception handling, iterators and async methods. See the Warnings and Errors appendix for the full EM list.
Methods excluded for these reasons are reported during the build and do not cause the obfuscation to fail — they are simply emitted unencrypted.
Performance Considerations
An encrypted method’s body still runs as JIT-compiled code, so its internal work runs at close to native speed. What Code Encryption adds is a small per-call dispatch cost each time an encrypted method is entered (the arguments are marshalled to the BVM and the result marshalled back). That overhead is negligible for methods that do real work, but it can dominate for very small methods called in extremely hot loops (millions of calls). For this reason — and to keep the assembly small and fast — apply Code Encryption selectively to the sensitive methods that need protection rather than to the whole codebase, and avoid encrypting tiny, hot helper methods on a critical path.
Enabling Code Encryption
Babel Obfuscator allows the user to selectively apply code encryption to specific methods in the codebase instead of encrypting the entire codebase. This is done to avoid the performance issues that can arise from encrypting large amounts of code.
To indicate which methods should be encrypted, the user can either use an XML rule or the Obfuscation attribute. With an XML rule, the user can specify the names of the methods that should be encrypted.
<Rule name="encrypt code" feature="msil encryption" exclude="false">
<Target>Methods</Target>
<Pattern>ACME.Algorithms::*</Pattern>
<Description>Encrypt all methods of Algorithm class.</Description>
</Rule>Alternatively, the Obfuscation attribute can be used to mark individual methods for encryption by setting the “Feature” parameter to “msil encryption”.
[Obfuscation(Feature = "msil encryption", Exclude = false)]
public void ProcessData()
{
// Encrypted code
}By enabling Code Encryption, the selected methods will be encrypted during the obfuscation process.
Command Line
babel myapp.exe --msilencryptionRather than using XML rules or attributes, the switch command --msilencryption can optionally accept regular expressions to select the methods or types where code encryption should be enabled. For example, the following command:
babel myapp.exe --msilencryption ACME.LicenseManager::.*Will configure Babel to encrypt all the methods belonging to LicenseManager class in the ACME namespace.
MSBuild Babel Task
<PropertyGroup>
<MsilEncryption>true</MsilEncryption>
</PropertyGroup>
​
<Babel MsilEncryption="$(MsilEncryption)" />Babel Desktop
Select the assembly on the project canvas and, in the properties panel, enable MsilEncryption in the Code encryption group. Optionally, add a list of regular expressions to filter the namespaces or classes where code encryption should be applied. Leave the list empty if you selected the methods to encrypt using XML rules or the Obfuscation attribute. See Obfuscation Projects for how to work with projects in Babel Desktop.
After the run, the Results view lists the encrypted methods, so you can check that code encryption was applied.
The code encryption statistics also appear in the output log (the Activity panel in Babel Desktop), which records each phase of the obfuscation, code encryption included.
Encrypt Msil phase, elapsed time 00.579s
Embedded resource: omJYi
size : 13170 bytes
Method statistics:
194/[ 252] resources: 76.98 %
194/[ 252] overall: 76.98 %
Number of encrypted methods: 194By examining the code encryption statistics in the output log, you can easily verify if code encryption has been applied to your code and gain insights into the level of protection it provides. It allows you to confirm that your sensitive code has been successfully encrypted, ensuring that it remains secure and resistant to unauthorized access.