Skip to main content

Field Encryption

Encrypting field values can effectively prevent malicious attackers from using memory modification techniques to protect code security.

Supported Variable Types

Currently supports encryption of class static variables and member variables, but does not support encryption of ordinary temporary variables within functions. Supported field types for encryption are:

  • int, uint
  • long, ulong
  • IntPtr, UIntPtr
  • float
  • double

Implementation Principle

  • Before writing to a field, the value is encrypted using EncryptionService<Scope>::Encrypt
  • Before reading from a field, the value is decrypted using EncryptionService<Scope>::Decrypt

Obfuz modifies all read and write operations to the encrypted field in the assembly, and this encryption process is completely transparent to the assembly. Obfuz's field encryption algorithm ensures that a value of 0 maps to 0, so no additional initialization is required for zero values.

warning

Note that Obfuz only guarantees that encryption and decryption operations are performed when reading from or writing to encrypted fields in the code. If reflection is used, the encrypted values are accessed directly.

Compatibility with Serialization Libraries

For serialization libraries, the following scenarios exist:

  • If code generation is used to serialize fields, both read and write operations will go through decryption and encryption, just like manually written code, so there will be no issues.
  • If reflection is used to read Property-type fields, since the Property functions also perform decryption and encryption on the underlying data, there will be no issues.
  • If reflection is used to save encrypted field data and then read the encrypted field data back via reflection, there will also be no issues.
  • If reflection is used to save the original field values and then the fields are accessed directly in the code, the fields will not be encrypted, and the decryption operation during reading will result in incorrect data.

Taking Newtonsoft.Json as an example:

  • If Newtonsoft.Json is first used to save object data to a JSON file and then deserialize the JSON file back into the object, there will be no issues.
  • If a JSON file is manually written with unencrypted field values and then deserialized into an object, these unencrypted fields will be incorrectly decrypted, resulting in errors.

The same applies to MonoBehaviour and similar cases. If you set a field value in the inspector, since Unity uses reflection to obtain the field value, it saves and loads the original value. When you access the field in code, you will incorrectly get the decrypted value.

Settings

ObfuzSettings.FieldEncryptSettings contains constant encryption related settings, detailed documentation can be found in Configuration.

Encryption Level

The encryption level affects the ops parameter passed when calling EncryptionService<Scope>::Encrypt. For detailed introduction to the ops parameter, see the documentation Encryption.

The encryption level value range is [1-4]. During encryption, the number of ops generated equals the encryption level value. Simply enabling constant encryption can effectively prevent cracking. The encryption level size does not significantly improve the difficulty of anti-cracking, so it is recommended to default to 1.

The FieldEncryptSettings.EncryptionLevel field can set the global default encryption level.

EncryptFieldAttribute

EncryptFieldAttribute provides a convenient way to mark fields as encrypted fields in code. For detailed documentation, see Obfuz CustomAttributes.

It has higher priority than Obfuscation Pass rules and [ObfuzIgnore]. As long as a field has the [EncryptField] attribute, it will still be encrypted even if the field and its containing type have the [ObfuzIgnore] attribute.

Example code:


[ObfuzIgnore]
class A
{
[EncryptField]
public int x1; // Variable x1 will still be encrypted, ignoring [ObfuzIgnore] on the type

[ObfuzIgnore]
[EncryptField]
public int x2; // Variable x2 will still be encrypted, ignoring [ObfuzIgnore] on the field

public int y; // Variable y will not be encrypted, nor will it be subject to any obfuscation or encryption passes
}

Rule Files

Since field encryption affects field read/write performance, no fields are encrypted by default.

Since encrypted fields are generally very few, by design it has higher priority than Obfuscation Pass rules, but lower than [ObfuzIgnore].

Supports fine-grained control of field encryption scope and effects through rule files. The FieldEncryptSettings.RuleFiles option can configure 0-N rule files. Rule file relative paths are from the project directory, valid rule file paths look like: Assets/XXX/YYY.xml.

Configuration example:


<?xml version="1.0" encoding="UTF-8"?>

<obfuz>
<assembly name="Obfus1">
<type name="*">
<field name="a"/>
<field name="b"/>
</type>
</assembly>
</obfuz>
  • Top-level tag must be obfuz
  • Second-level tags must be assembly

assembly

AttributeNullableDefaultDescription
nameNoAssembly name, must be in the obfuscated assembly list

Assembly's child elements can only be type.

type

AttributeNullableDefaultDescription
nameNoType name wildcard string, if empty means match all types. Nested types use / to separate the declaring type and enclosed subtype, like test.ClassA/ClassB.

Since field encryption can only act on fields, type's child elements can only be field.

field

AttributeNullableDefaultDescription
nameNoName of the field to be encrypted. Field name wildcard string, if empty means match all types