Function Call Obfuscation
Function call obfuscation disguises how functions (static, member, or virtual) are called in code. After decompilation, it's impossible to directly know which function is being executed, effectively protecting code security.
Implementation Principle
For each function call xxx Foo(T1 p1, T2 p2, ...)
:
- Group called functions by their signatures, assigning each function a unique index within its group.
- Use
EncryptionService<Scope>::Encrypt(int value, int ops, int salt)
to calculate an encryptedIndex from the index. - At the function call site, first call
EncryptionService<Scope>::Decrypt(int value, int ops, int salt)
to decrypt and get the original index. - Replace the original function call with
xxx $Dispatch(T1 p1, T2 p2, ..., int index)
The encryptedIndex is decrypted only when executing that code location. After decompilation, it's impossible to directly know which function is called, effectively increasing the difficulty of code cracking!
Settings
ObfuzSettings.CallEncryptSettings
contains settings related to constant encryption. See Configuration for details.
Proxy Mode
There are multiple methods to obfuscate function calls.
Mode | Description |
---|---|
Dispatch | Converts function calls to indirect calls through another dispatch function. The index of the dispatch function determines the actual function called. The index value is encrypted and only decrypted at runtime, effectively preventing attackers from analyzing call relationships. |
Delegate | Converts function calls to precomputed delegates. Delegate objects are bound to elements at specific indexes in a delegate[] array at runtime. The index value is encrypted and only decrypted at runtime, effectively preventing attackers from analyzing call relationships. |
There's no significant difference in obfuscation level or runtime performance between Delegate and Dispatch modes. The advantage of Delegate over Dispatch is that the generated obfuscated code is more stable, with smaller differences when code changes.
Dispatch mode is recommended for most projects. For HybridCLR premium users, reducing code changes can reduce the number of functions switched to interpreted execution, improving DHE performance, so Delegate mode is recommended.
Encryption Level
The encryption level affects the ops
parameter passed to EncryptionService<Scope>::Encrypt
. See Encryption for detailed information about the ops parameter.
The encryption level ranges from [1-4]
. During encryption, the number of ops generated equals the encryption level value. As long as constant encryption is enabled, it effectively prevents cracking. Higher encryption levels provide minimal additional protection against cracking. The default value of 1 is recommended.
The CallEncryptSettings.EncryptionLevel
field can set the global default encryption level.
Rule Files
By default, Obfuz encrypts all function calls, but it also supports rule files to precisely control the scope and effect of constant encryption. The CallEncryptSettings.RuleFiles
option can configure 0-N rule files.
Rule files are relative to the project directory. Valid rule file paths look like: Assets/XXX/YYY.xml
.
Configuration example:
<?xml version="1.0" encoding="UTF-8"?>
<obfuz>
<whitelist>
<assembly name="mscorlib" obfuscate="0"/>
<assembly name="UnityEngine.*" obfuscate="0"/>
<assembly name="Obfus2">
<type name="Banana" obfuscate="0"/>
<type name="*.TestTypeAllMethodNotObfus" obfuscate="0"/>
<type name="*.TestTypeSomeMethodNotObfus">
<method name="NotObfus*"/>
</type>
</assembly>
</whitelist>
<global obfuscationLevel="Basic">
</global>
<assembly name="Obfus2">
<type name="*.TestNotObfusTypeAllMethods" obfuscationLevel="None"/>
<type name="*.TestNotObfusTypeSomeMethods">
<method name="NotObfus*" obfuscationLevel="None"/>
</type>
<type name="Aaaa.TopClass/SubClass" obfuscationLevel="Advanced">
</type>
</assembly>
</obfuz>
- The top-level tag must be
obfuz
- Secondary tags can be
whitelist
,global
, andassembly
whitelist
The whitelist configures functions that won't be encrypted when called. This setting applies to all assemblies.
assembly
Attribute | Optional | Default | Description |
---|---|---|---|
name | Yes | None | Name as a wildcard expression. If empty, matches all assemblies. |
obfuscate | Yes | 1 | Whether to obfuscate calls to functions within this assembly. |
The only child element of assembly
is type
.
type
Attribute | Optional | Default | Description |
---|---|---|---|
name | Yes | None | Name as a wildcard expression. If empty, matches all types. Nested types use / to separate the containing type and nested type, e.g., test.ClassA/ClassB . |
obfuscate | Yes | Inherits from assembly's同名 field | Whether to obfuscate calls to functions within this type. |
The only child element of type
is method
.
method
Attribute | Optional | Default | Description |
---|---|---|---|
name | Yes | None | Name as a wildcard expression. If empty, matches all methods. |
obfuscate | Yes | Inherits from type's同名 field | Whether to obfuscate calls to this method. |
global
The global
tag defines global default encryption parameters.
Attribute | Optional | Default | Description |
---|---|---|---|
obfuscationLevel | Yes | None | Obfuscation level, which can be None, Basic, Advanced, or MostAdvanced. |
assembly
Attribute | Optional | Default | Description |
---|---|---|---|
name | No | Assembly name, which must be in the list of obfuscated assemblies. | |
Others | Yes | Inherits from global同名 options | All options from global can be used. If not defined, inherits values from global . |
The only child element of assembly
is type
.
type
Attribute | Optional | Default | Description |
---|---|---|---|
name | No | Wildcard string for type names. If empty, matches all types. | |
Others | Yes | Inherits from assembly同名 options | All options from global can be used. If not defined, inherits values from assembly . |
Since function calls can only appear in function code, the only child element of type
is method
.
method
Attribute | Optional | Default | Description |
---|---|---|---|
name | No | Wildcard string for method names. If empty, matches all methods. | |
Others | Yes | Inherits from assembly同名 options | All options from global can be used. If not defined, inherits values from assembly . |