Skip to content
← All posts
· Delta1 Labs .NETObfuscationSecurity

Auto-Hardening Your License Checks

The method that verifies your license is the single highest-value target in your app — crack it and everything else is moot. Nebula.NET can find the methods that call your licensing SDK and automatically apply the strongest protection your edition allows to exactly those methods, so the gate is hardened without you hand-listing it. Here is how auto-protect works.

Every feature flag, every “is this licensed?” branch, every seat check ultimately funnels through a small amount of code: the method that verifies the license and returns a yes or no. That method is the single highest-value target in your whole application. An attacker doesn’t need to understand your business logic — they need to find that one method and make it always return true. Harden everything else and leave the gate readable, and you’ve locked every door but the front one.

So the license check is exactly the code that deserves your strongest protection. The problem is remembering to apply it there — by name, as you refactor, across every method that touches licensing. Nebula.NET’s autoProtectLicensing does that targeting for you.

Turn it on

It is one flag:

{
  "rename": true,
  "controlFlowObfuscation": true,
  "autoProtectLicensing": true
}

With that set, Nebula finds the methods in your assembly that call your licensing SDK and automatically adds them to the strongest protection your edition allows — aggressive control-flow obfuscation, and on Enterprise, method virtualization — without you listing a single method name.

How it finds the licensing code

The targeting is call-site analysis, not guesswork on names. Before the protection passes run, Nebula walks each method body and inspects every call, callvirt and newobj. If the member being invoked belongs to one of the configured licensing namespaces — Keyright by default — that method is flagged as licensing code:

// This method calls into Keyright, so auto-protect flags it:
public bool CanExport()
{
    var lease = Keyright.License.Current;          // ← call into the Keyright namespace
    return lease.IsValid && lease.Entitlements.Has("export");
}

Nebula records the method’s fully-qualified identity and folds it into the include set for control-flow obfuscation (and virtualization, where licensed) alongside anything you listed explicitly. The result is that CanExport — and every other method that reaches into licensing — is flattened into a dispatcher state machine (or compiled to VM bytecode on Enterprise), while the rest of your app keeps the lighter default protection.

If your licensing lives behind your own thin wrapper, point the detector at that namespace too:

{
  "autoProtectLicensing": true,
  "licensingNamespaces": ["Keyright", "MyApp.Licensing"]
}

Now a method that calls MyApp.Licensing.Gate.Check() is caught even if it never names Keyright directly — so a single internal licensing layer is fully covered, and you don’t have to re-list methods as you add them.

Why target instead of protecting everything

The natural question is: why not just virtualize the whole app? Because the heavy transforms cost something. Aggressive control-flow flattening and virtualization add size and run slower than the original IL — negligible on a method that runs once at startup, but not something you want multiplied across every hot method in a large codebase. So the realistic strategy is always to target the strong protection, and the license check is the textbook thing to target:

  • It is small — a handful of methods, so the cost is trivial.
  • It runs rarely — at startup or at a feature boundary, not in a tight loop.
  • It is decisive — defeating it unlocks the entire product, so it is where an attacker spends their time.

autoProtectLicensing makes “spend the protection budget on the licensing code” automatic and refactor-proof. You never ship a build where a newly-added license-check method slipped through because nobody updated the include list.

It composes with the other layers

Auto-protect decides what to protect; it stacks with the transforms that decide how. The license check benefits most when several layers land on it at once:

  • Control-flow obfuscation / virtualization (what auto-protect applies) hides the logic of the check — the branches, the comparison that returns the verdict.
  • Reference obfuscation hides the call graph, so even the fact that this method calls into a licensing API isn’t legible at the call site.
  • String encryption hides the entitlement names and messages the check consumes.
  • Anti-tamper means patching the verdict after the fact trips an integrity check.

Each closes a different shortcut. Renaming alone would leave the gate’s logic readable; auto-protect guarantees the gate is in the strong-protection set; the other layers remove the surrounding tells. Together they turn “find the method and flip the boolean” into real, slow, manual work — which is the entire point.

A license is only as strong as the code that checks it. For the background on why that is and the common .NET approaches, see protecting your license checks; auto-protect is how Nebula makes sure that protection actually lands on the right methods, every build, without a hand-maintained list. If you’re choosing a licensing system to pair it with, Keyright is the one Nebula recognizes out of the box.

Try Nebula.NET

Harden your .NET code in minutes — start with the free edition.