← Back to home

Seven Quiet Years

Demeanor v5 had its last bug report in 2019. Then the .NET world changed.

In 2019, a Demeanor customer filed the last bug report v5 would ever receive. For the seven years that followed, the support inbox stayed quiet. The product kept shipping against every new .NET release without a single new defect surfaced by a customer. I didn’t market it. There wasn’t anything to fix. Then the .NET world changed underneath it, and v5’s job description began to drift away from the world it was working in.

v6 is the answer to that drift. This is the story.

A quiet inbox

I started writing Demeanor in 1999 against Microsoft’s internal “Lightning” .NET alpha builds — before .NET was publicly announced. The first public beta of Demeanor shipped alongside .NET Beta 1 in June 2000. .NET 1.0 itself shipped in February 2002. By the time .NET reached the world, Demeanor was already a mature, production product. There was no second .NET obfuscator yet. There wasn’t even a first one to compare against.

Wise Owl has shipped Demeanor every year since. Same author. Same owner. No acquisitions, no brand changes, no dormant periods, no free-to-paid transitions. By 2019 the product was on its fifth major version and had been shipping continuously against every new .NET generation for two decades. That year, a customer filed a bug report. After they confirmed the fix, the inbox went quiet.

It stayed quiet for seven years.

Through .NET 5, 6, 7, 8, 9, and 10 — every annual cadence Microsoft introduced after Core unification — Demeanor v5 obfuscated customer assemblies without producing a single customer-reported defect. I added support for new target frameworks as they shipped, but those weren’t bug fixes. The bugs simply weren’t there.

A quiet inbox is the strongest endorsement a tool of this category can earn. Obfuscation is a destructive transformation on metadata that the runtime, the DI container, the JSON serializer, and the configuration binder all silently depend on. The failure modes are subtle, late, and load-bearing. The product that doesn’t generate bug reports for seven straight years is the product that has the metadata model right.

So I didn’t market v5. I didn’t need to market a product that didn’t need fixing. Customers who already used Demeanor renewed and kept shipping. The .NET community at large mostly didn’t hear about Demeanor during that stretch — partly because of the silence, mostly because the .NET community at large turns over substantially every five years and the new arrivals had no reason to know.

Some of those customers have been using Demeanor for two decades — companies whose first license predates v5 entirely. Several of them have been among the first to upgrade eagerly to v6. The customers who know the product best, having shipped against it for twenty years, are the ones moving to the new version first.

What changed wasn’t Demeanor

Some time around 2023 a pattern in my support email started showing up that hadn’t in 2019. Customers using newer libraries — libraries that didn’t exist when v5’s framework-awareness was last extended — were running into a familiar shape of problem. They’d obfuscate, the assembly would emit clean, the application would launch, and then deep inside some reflection-driven configuration path it would fail to find a member by name.

The cause was always the same. v5 had a complete picture of which .NET patterns it should leave alone. That picture was complete for the .NET of 2019. The .NET of 2023 had patterns v5 didn’t recognize, because those patterns hadn’t been invented yet when v5 was last updated.

This isn’t a bug. v5 was doing exactly what it was designed to do. The design needed to expand.

A few things changed in the .NET ecosystem during the seven quiet years that mattered for an obfuscator specifically:

  • Reflection-driven configuration proliferated. The convention of binding strongly-typed configuration objects to JSON, environment variables, command-line arguments, and the rest spread from a few popular libraries to nearly every modern .NET app. The runtime matches property names by string. If you obfuscate the property name, the binding silently produces a default value — and you only learn about it when production behaves differently than dev.
  • Source generators reshaped assembly contents. Library authors increasingly emit code at compile time rather than discovering it via reflection at runtime. The shape of a typical compiled assembly in 2026 is materially different from 2019.
  • Conventions over configuration kept winning. More frameworks now look up handlers, registrars, and dependencies by name conventions or by attribute presence. Each new convention is one more pattern an obfuscator must recognize, or break.
  • AI-assisted development became a category. Most working .NET engineers in 2026 routinely drive parts of their workflow through an AI assistant — Claude Code, Copilot, Cursor, others. None of those existed in any meaningful form when v5 was last expanded. They’ve quietly become the surface most engineers prefer to interrogate their tools through.

None of this means v5 was wrong. It means v5 was complete for a world that no longer exists in the same shape. v6 is what happens when you take a tool that was complete for 2019’s .NET and rebuild it complete for today’s.

Why obfuscators break code, in general

Step back from Demeanor for a moment and look at the category. Every commercial .NET obfuscator does the same fundamental thing: it rewrites your assembly so that the metadata names a reverse engineer would read — type names, method names, fields, properties, parameters — become uninformative. That’s the value proposition. It’s also the entire problem.

Your assembly’s metadata names aren’t only consumed by reverse engineers. They’re consumed at runtime by the .NET runtime itself, by every dependency-injection container, by every serializer, by every configuration binder, by every framework that does any kind of convention-based discovery, and by your own code wherever it ever calls typeof, nameof at the wrong layer, GetType().Name, or anything reflective. When the obfuscator rewrites OrderProcessor to a3, the JSON serializer that was happily round-tripping OrderProcessor instances suddenly can’t find the type at all.

Failure surfaces at runtime, not at build time. Often deep in a code path the developer didn’t exercise during their post-obfuscation smoke test. Sometimes weeks after deploy, when a customer’s data flows through that path for the first time.

The category’s standard answer to this is configuration. Every obfuscator on the market lets you exclude specific types, members, or namespaces from renaming. You add an exclusion. You re-obfuscate. You re-test. The build pipeline gets a few more lines of obfuscation config every time something breaks.

That answer has a load-bearing assumption nobody states: that the developer can predict, ahead of time, every place reflection touches metadata in their codebase. Nobody can. Modern .NET is too large a surface, too convention-driven, too assembled out of libraries the developer didn’t write and doesn’t fully understand. The exclusion list grows one outage at a time. Each release ships, breaks, gets patched, ships again. The treadmill never quite ends.

This is the experience every customer who’s ever shipped an obfuscated .NET app recognizes. It is the shared truth of the category. And it is the specific problem v6 was designed to put on a different footing.

What v6 actually changes

Three things, in increasing order of how much they change the customer’s day-to-day. The first two address the breakage problem directly. The third changes how engineers interact with the tool.

1. Broader framework awareness, by default

v6’s out-of-the-box recognition of common .NET reflection patterns is materially broader than v5’s was when v5 stabilized in 2019. The categories of pattern that customers most often had to manually exclude in 2019 — dependency injection registrars, model binders, serializer-targeted types, framework-discovered handlers — are recognized and handled silently in v6. The customer doesn’t have to know in advance which of their types fall into a risky category. Demeanor sees the pattern in the assembly metadata and does the right thing without configuration.

This is not a small detail. The single largest source of post-obfuscation runtime surprise across the category is “a framework I don’t fully understand needed a metadata name I didn’t know to preserve.” The broader the obfuscator’s default pattern recognition, the shorter the customer’s exclusion-by-postmortem treadmill. v6 ships with the picture extended to cover what the customer’s real codebase actually contains today.

2. The pre-obfuscation audit

This is the part no other .NET obfuscator on the market does, in any version, at any price. v6 reads your compiled assembly before it rewrites a single byte and tells you, as a structured report:

  • What the obfuscator will auto-handle — the patterns Demeanor already recognizes and will leave intact without configuration.
  • What needs an exclusion — constructs that would be renamed by default but shouldn’t be, because something at runtime is going to look them up by their original name. The audit names the specific [Obfuscation] attribute to add.
  • What needs a code change — the rare cases where the right answer isn’t to exclude something but to restructure the code itself, with the file and line where the change should happen.

The customer reads the report. The customer applies the recommended fixes — usually a small number of [Obfuscation] attributes on a small number of types. Then the customer obfuscates, knowing in advance what the result will be. The 3am Sentry alert from a release pipeline that obfuscated cleanly but failed at runtime is replaced by a build-time report that names what would have failed and how to prevent it.

Said differently: in every other .NET obfuscator, you obfuscate first and discover the problems by deploying and waiting. In Demeanor v6, you discover the problems first and then obfuscate. That’s the entire difference.

The audit runs as a CLI command. It also runs as an MSBuild target the build pipeline can gate on. Engineers who like to drive their tools by typing get a console report; engineers who like their tools to fail their CI build until the report is clean get that too.

3. Optional AI integration

The Model Context Protocol (MCP) is an open standard, introduced by Anthropic in late 2024 and now supported by most major AI assistants, that gives an AI assistant a uniform way to call external tools and read external data. Demeanor v6 ships its own MCP server. AI assistants — Claude, GitHub Copilot, Cursor, and others — connect to it as MCP clients, which lets your favorite AI assistant ask Demeanor about potential obfuscation problems and the fixes for them, before you ship your application.

In practice: an engineer asks Demeanor questions in conversation — “audit this assembly,” “explain why this type would break,” “what attribute should I add to fix this?” — and gets the same audit and the same recommendations the CLI produces, just driven through the surface the engineer already prefers.

This is genuinely optional. The CLI runs the same audit unattended in CI without any AI dependency. If your team doesn’t use AI assistants, ignore this paragraph entirely — everything that matters about Demeanor works without it. If your team does use them, the integration removes a context switch.

During v6’s MCP integration work, Claude’s default safeguards initially flagged Demeanor’s metadata analysis as potentially-malicious cyber tooling — the kind of false positive most legitimate dual-use security tools eventually trip. After review, Anthropic approved Wise Owl Software’s specific Anthropic organization into their Cyber Verification Program: the formal vetting process for legitimate dual-use security work. The practical consequence for customers: when your engineers drive Demeanor through Claude — using their own Anthropic account, with Wise Owl’s MCP server — the vendor-side piece has been examined and approved. The integration is real plumbing, not a marketing decoration that may or may not still work next quarter.

The MCP server connects to your AI assistant of choice and uses your existing AI subscription — a Claude or Anthropic plan, or whatever your team already runs. The subscription is yours, not bundled with Demeanor. The CVP approval applies to Wise Owl Software’s organization, not to your separate Anthropic account — your account’s usual safeguards still apply to your usage.

What hasn’t changed and won’t

Until 2021, Demeanor was licensed the same way most commercial obfuscators still are: per-seat, with license servers, phone-home checks, and machine locking. Customers told us for years that they disliked the apparatus but tolerated it as the cost of doing business in this kind of tooling. We listened, ripped the whole mechanism out, and replaced it with per-company self-validating keys.

The model hasn’t changed since, and the principles aren’t going to. A Demeanor license is per company — not per developer, not per build agent, not per machine. Unlimited engineers can build with it. Unlimited CI runners can run it. There is no seat counting because there is nothing on either end of the wire that knows how many seats there are.

There is no phone-home. There is no activation server. The license key is self-validating — it carries its own signature, the obfuscator verifies it locally, and that is the entire transaction. Builds work offline. Builds work at 3am when the VPN is down. Builds work in 2030 if Wise Owl Software is somehow off the internet that day, because there is nothing for the build to phone home to.

And the engineering hand on Demeanor hasn’t changed in 27 years. It is the same person who started writing it on Lightning bits in 1999. The product hasn’t been acquired, rolled into a private-equity portfolio, or handed off to a successor team. For a buyer whose procurement timeline extends past the next vendor consolidation cycle — the kind of buyer who wants the vendor on their PO today to still exist when they renew in 2030 — this is the cleanest commercial-continuity record in the .NET obfuscation category.

These aren’t features. They’re values. They’ve been the values since 2021 and they’ll be the values in 2030.

What you can do today

Demeanor Community is free and includes real symbol renaming — types, methods, fields, properties, events, parameters — on a single assembly. Commercial use is permitted. It is not a crippled demo; it is the obfuscator I would have given you in 2005, available now at no charge, indefinitely.

Demeanor Enterprise adds the audit, broader framework awareness, the optional AI integration, whole-application protection across all your assemblies together, the deeper protections (string encryption, control-flow obfuscation, anti-tamper, anti-debug), and everything else listed on the pricing page. One annual license per company. Unlimited everything.

If you’re shipping a .NET application that contains business logic you’d rather not see decompiled, the suggested path is:

  1. Install Community free, run it on a published copy of your app, see what symbol renaming alone does to the metadata.
  2. If you need more — the audit, framework awareness, the deeper protections — buy Enterprise. Run the audit. Apply the handful of [Obfuscation] attributes the audit recommends. Obfuscate. Ship.
  3. Wire it into your build only after you’ve seen the obfuscated app run.

That’s the workflow. It’s the same workflow Demeanor customers have been using for 27 years, with one significant change: in 2026, you can find out what would break before you ship, instead of finding out after.

View pricing Get started Compare About Wise Owl