Home / Documentation / Obfuscating Applications Using JSON and XML Serialization
4.5 out of 5 (2 reviews on Visual Studio Marketplace)
Production Security Guide

How to Obfuscate .NET Applications That Use JSON and XML Serialization

Protect C# and VB.NET codebases utilizing System.Text.Json, Newtonsoft.Json, or XmlSerializer without corrupting DTO property bindings or polymorphic payloads.

Rustemsoft Technical Team • SEO Targets: .NET JSON obfuscation, Newtonsoft.Json obfuscate DTO, System.Text.Json reflection

Direct Answer

To protect .NET applications that use JSON or XML serialization, un-attributed Data Transfer Object (DTO) property names and polymorphic type discriminators must be explicitly excluded from identifier scrambling so runtime string keys match serialized payloads. Alternatively, decorate properties with explicit contract attributes (such as [JsonPropertyName] or [JsonProperty]), which allows Opaquer .NET Obfuscator to scramble the C# property symbols while preserving the string metadata required by serializers. Meanwhile, all internal engines, custom converters, and business logic retain maximum string encryption and control-flow protection.

1 The Problem

Modern .NET serialization engines-including System.Text.Json, Newtonsoft.Json (Json.NET), and System.Xml.Serialization.XmlSerializer-rely directly on metadata reflection to read and write object graphs.

The Disconnect Between Source Symbols and Payload Keys

Consider a simple C# property declaration versus what a JSON parser looks for at runtime:

// C# Source Code Identifier public string CustomerName { get; set; }
// Runtime Expected JSON Key { "CustomerName": "Acme Corp" }

When an obfuscator naively scrambles metadata symbols without rules targeting DTO properties, it renames CustomerName in assembly metadata to a non-descriptive token like a.

  • Un-attributed Properties: The serializer reflects over the class, finds property a, and searches incoming JSON for key "a". Because the JSON payload contains "CustomerName", the parser skips binding. The property remains null or default.
  • Polymorphic Types: Polymorphic inheritance mechanisms-such as JsonDerivedType in System.Text.Json, $type in Newtonsoft.Json, or [XmlInclude] in XML-rely on exact type names or explicit discriminator strings. Scrambling class names breaks polymorphic type instantiation.

Runtime JSON Deserialization Pipeline

Stable Contract / Explicit Attribute BOUND
JSON Key: "customer_name"
Metadata Binding Target: [JsonPropertyName("customer_name")]
Result: Property CustomerName = "Acme Corp"
Naive Scrambling (Un-attributed) SILENT DATA LOSS
JSON Key: "CustomerName"
Metadata Target: Property a
Result: Property a = null (Skipped)

2 Serialization DTO Code Examples

The following practical scenario demonstrates DTO contracts using System.Text.Json, Newtonsoft.Json, and System.Xml.Serialization, including polymorphic inheritance.

SerializationContracts.cs
using System;
using System.Text.Json.Serialization;
using System.Xml.Serialization;
using Newtonsoft.Json;

namespace MyApp.Contracts
{
    // 1. System.Text.Json Polymorphic Base Contract
    [JsonPolymorphic(TypeDiscriminatorPropertyName = "$type")]
    [JsonDerivedType(typeof(StandardCustomerDto), typeDiscriminator: "standard")]
    [JsonDerivedType(typeof(PremiumCustomerDto), typeDiscriminator: "premium")]
    public abstract class CustomerBaseDto
    {
        // Explicit attribute allows C# symbol renaming without breaking JSON key "customer_id"
        [JsonPropertyName("customer_id")]
        [JsonProperty("customer_id")]
        [XmlElement("CustomerID")]
        public int CustomerId { get; set; }

        // Un-attributed property: MUST remain stable if JSON key is "CustomerName"
        public string CustomerName { get; set; }
    }

    public class StandardCustomerDto : CustomerBaseDto
    {
        public double MonthlyCreditLimit { get; set; }
    }

    public class PremiumCustomerDto : CustomerBaseDto
    {
        [JsonPropertyName("vip_support_level")]
        public int VipSupportLevel { get; set; }
    }

    // 2. System.Xml.Serialization Contract
    [XmlRoot("OrderEnvelope")]
    [XmlInclude(typeof(StandardCustomerDto))]
    [XmlInclude(typeof(PremiumCustomerDto))]
    public class OrderEnvelope
    {
        [XmlAttribute("OrderId")]
        public string OrderId { get; set; }

        [XmlElement("CustomerPayload")]
        public CustomerBaseDto Customer { get; set; }
    }
}

3 What Happens Under Naive Obfuscation

Applying default, indiscriminate symbol renaming across DTO assemblies causes severe runtime failures:

1. Silent Data Loss

Un-attributed properties renamed to a or b fail key lookup during deserialization. Values default silently to null or 0 without throwing exceptions.

2. JsonException Crashes

Scrambling concrete polymorphic class names breaks JsonDerivedType or Newtonsoft's $type resolver, throwing NotSupportedException or JsonException.

3. XmlException Failures

XmlSerializer generates dynamic C# code at runtime. Scrambled type names inside [XmlInclude] cause schema validation and deserialization crashes.

4 Step-by-Step Opaquer Configuration

Follow this workflow in Opaquer .NET Obfuscator to protect serialization-heavy assemblies while ensuring 100% contract stability.

1

Audit DTOs, Contracts, and Polymorphic Types

Categorize your serialization models into two groups:
• Explicit Contracts: Properties with explicit attributes ([JsonPropertyName], [JsonProperty], [XmlElement]).
• Un-attributed Contracts: DTOs relying on direct property symbol names for key matching.

2

Open Assembly in Opaquer .NET Obfuscator

Launch Opaquer. Click Open File and select your assembly. Opaquer parses metadata and constructs an interactive tree under the Settings Tab.

3

Locate DTO Namespaces in Assembly Tree

Expand namespace nodes (e.g., MyApp.Contracts). If all DTOs reside in a dedicated contract namespace, you can manage renaming exemptions globally at the namespace level.

4

Configure Member Rename Exemptions

Apply exemptions based on attribute usage:

• Un-attributed DTOs:

Uncheck Rename Properties and Rename Types for DTO classes to keep symbol metadata intact.

• Explicit Attribute DTOs:

Leave symbol renaming Enabled. Opaquer will scramble the C# property names, but the attribute string metadata ("customer_id") remains intact for the serializer.

5

Keep String Encryption and Control Flow Active for Internal Engines

Excluding DTO names does not compromise security. Enable Strings Encryption and High-Intensity Control Flow in Opaquer. Business logic, custom JsonConverter implementations, and core processing algorithms receive maximum protection.

5 Before/After Visual Decompiler View (ILSpy)

Observe how decompilers view protected DTO models and processing engines when using Opaquer's selective controls:

Naive Obfuscation (Breaks Serialization) Data Loss
// Un-attributed properties scrambled to meaningless symbols
public class a
{
public string a { get; set; } // Was CustomerName
public int b { get; set; } // Was CustomerId
}
// Serializer searches JSON for "a" and "b" → Returns NULL!
Opaquer Selective Protection Contracts Intact + Engines Shielded
// Contract property preserved for JSON matcher
public class CustomerBaseDto
{
public string CustomerName { get; set; }
}
// Processing Engine (Fully Obfuscated with String Encryption & Control Flow)
internal class c0001 {
public void m0() {
int k = 98123;
while(true) { switch(k ^ 0x1F2E) { ... } }
}
}

6 Testing the Obfuscated Application

Implement automated round-trip testing against protected build artifacts before production deployment:

1. Serialization Round-Trip

Serialize a populated object to JSON/XML, deserialize back into an object instance, and assert that all properties match original values.

2. Contract Payload Mocking

Feed raw JSON strings from external API specifications directly into deserializers to verify contract compliance.

3. Polymorphic Instantiation

Test payloads containing derived types (e.g., "premium") to verify concrete subclass resolution.

7 Common Failures and Fixes Matrix

Symptom / Error Root Cause Solution in Opaquer
CustomerName property is null after deserialization Un-attributed property was renamed by identifier scrambling. Uncheck Rename Properties for DTO class in Opaquer tree view.
JsonException: Could not resolve polymorphic type Concrete subclass class name scrambled; discriminator lookup failed. Specify explicit type discriminator strings in [JsonDerivedType] or exclude subclass names.
XmlException: Type 'a' was not expected XmlSerializer encountered renamed class inside [XmlInclude]. Exclude XML model class names from renaming under assembly tree.
Newtonsoft $type deserialization crash Full assembly qualified name in $type property was mutated. Implement custom SerializationBinder or exclude DTO types.

8 Production Recommendations

✓
Use Explicit Contract Attributes Everywhere:

Decorate properties with [JsonPropertyName("name")] or [JsonProperty("name")]. This enables Opaquer to scramble C# property symbol names while leaving runtime key strings intact.

✓
Isolate Contracts into Dedicated Namespaces:

Place all data transfer contracts into MyApp.Contracts. In Opaquer, exclude this namespace from symbol renaming while applying full string encryption and control flow protection to MyApp.Engine.

✓
Automate CI/CD via Opaquer CLI:

Save exclusion rules in an Opaquer project file (opaquer_rules.opq) and integrate into Azure Pipelines or GitHub Actions:
Opaquer.exe /input:MyApp.dll /output:Protected/MyApp.dll /config:opaquer_rules.opq

9 Frequently Asked Questions

Related Opaquer Guides