Defense in Depth: Every Layer in One Build
Strong protection does not come from a single trick — it comes from layers. This example turns on every protection of the Babel Obfuscator NuGet package on one small assembly, so you can see the complete Ultimate configuration in a single project file and adapt it to your own application.
To use this example you need a site license for Babel Obfuscator (Ultimate, Server or Data Center editions). The source code is available on GitHub:
git clone https://github.com/babelfornet/defense-in-depth-nuget-example.gitThe application is a small feature gate (src/LicenseGate/FeatureGate.cs) that carries exactly the
kinds of things every layer protects — strings, numeric weights, an array, and branching logic:
internal static class FeatureGate
{
private static readonly int[] Weights = { 3, 7, 11, 13, 17, 19, 23, 29, 31, 37 };
private static readonly string Pepper = "d3f3ns3-1n-d3pth-pepper";
public static GateReport Evaluate(string edition, int tokens, double budget)
{
bool allowed = edition is "PRO" or "ENTERPRISE" && tokens > 0 && budget >= 100.0;
double score = 0.0;
for (int i = 0; i < Weights.Length; i++)
score += Weights[i] * (tokens + 1) * 0.5;
return new GateReport(edition, allowed, Math.Round(score / budget, 4), Digest(edition, tokens));
}
// Digest …
}The LicenseGate console project stacks the layers in Release:
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<!-- Rename & restructure -->
<FlattenNamespaces>true</FlattenNamespaces>
<OverloadedRenaming>true</OverloadedRenaming>
<VirtualFunctions>true</VirtualFunctions>
<!-- Hide data -->
<StringEncryption>stream</StringEncryption>
<ValueEncryption>int32=true;int64=true;single=true;double=true;array=true;true</ValueEncryption>
<ResourceEncryption>true</ResourceEncryption>
<!-- Obscure logic -->
<ControlFlowObfuscation>if=true;switch=true;case=true;chain=true;true</ControlFlowObfuscation>
<ControlFlowIterations>3</ControlFlowIterations>
<DynamicProxy>external=true;true</DynamicProxy>
<!-- Detect & deter runtime attacks -->
<TamperingDetection>true</TamperingDetection>
<DebuggingProtection>true</DebuggingProtection>
<SuppressIldasm>true</SuppressIldasm>
<!-- Strip metadata -->
<CleanAttributes>true</CleanAttributes>
<SealClasses>true</SealClasses>
<BabelWarningsAsErrors>W00000</BabelWarningsAsErrors>
</PropertyGroup>Each property adds a layer: renaming and namespace flattening hide intent; String, Value and Resource
encryption hide data; control flow and dynamic proxy hide logic; tampering detection and anti-debugging
deter runtime attacks; and metadata hygiene removes what the running application does not need. Because
the package is a build-only dependency (PrivateAssets=all), none of this leaks into the app’s own
dependency graph, and the SDK’s later steps work on the already-protected assembly.
Building the sample in Release applies all of the above with identical program output; open the result in a decompiler and compare it with the Debug build to see the difference. This mirrors the guidance in Enhancing Code Security — start from this configuration and drop the layers you do not need.