Reversing .NET Binaries
Decompile CIL back to readable C#, strip ConfuserEx with de4dot, patch and debug live in dnSpyEx, and tackle single-file, AOT, and Unity IL2CPP builds.
Reversing .NET Binaries
.NET reversing is, most of the time, the easiest category in this section — and occasionally one of the most annoying, depending entirely on whether the author obfuscated the assembly. A normal .NET executable does not contain native machine code. It contains CIL (Common Intermediate Language, also called MSIL/IL), a stack-based bytecode that carries full metadata: type names, method names, field names, and signatures. A decompiler reads that metadata and reconstructs near-original C#.
That means the default case is not "read disassembly and infer logic" — it is "open the decompiler and read the source." The work shifts to recognizing what is happening (is this even .NET? is it obfuscated? is it a single-file or AOT build? is it Unity?) and reacting accordingly.
A managed .NET assembly decompiles back to readable C# because the IL keeps method and type names. The flag is often sitting in plain source. The hard part is almost always obfuscation or an unusual publish mode — not the IL itself.
IL vs Native: Identify the Build First
Before picking a tool, work out which kind of .NET binary you have. They look similar but need completely different approaches.
file ./chal.exe
# PE32 executable ... Mono/.Net assembly ← managed: decompile it
# PE32+ executable (console) x86-64 ← could be native AOT or a single-file host
# A managed assembly has a CLR header. Check for it:
strings ./chal.exe | grep -m1 "mscoree\|System.Private.CoreLib\|BSJB"
# "BSJB" is the metadata stream signature; mscoree.dll = classic .NET Framework loaderThe common case: a .dll/.exe of pure CIL plus metadata. Decompiles cleanly to C#. Open it in dnSpyEx or ILSpy and read.
Core Tools
dnSpyEx is the community-maintained fork of the (archived) original dnSpy and the default tool for CTF .NET work. It is a decompiler, assembly editor, and debugger in one. You can read decompiled C#, edit a method body and recompile it, set breakpoints, and step through managed code live.
File → Open → chal.exe
Assembly Explorer → expand namespaces → read decompiled C#
Right-click a method → "Edit Method (C#)" to patch, then File → Save ModuleObfuscation
If names look like Class1.method0 or unprintable Unicode garbage, the assembly is obfuscated. Identify the protector, then deobfuscate.
Detect the obfuscator
Look at namespace/type names, an injected ConfusedByAttribute, weird module initializers, or unprintable identifier strings. Tools like de4dot will name the obfuscator on detection. ConfuserEx / ConfuserEx2 is by far the most common in CTF because it is free and open source.
Run de4dot
de4dot chal.exe # detect and clean
de4dot-cex chal.exe # ConfuserEx2-aware fork for control flowThis typically restores names, decrypts the string table, and flattens the bogus control flow.
Re-open the cleaned assembly
Load chal-cleaned.exe in dnSpyEx. If strings are still encrypted, find the decryptor method, and either let dnSpyEx run it (debug to the call site and read the result) or invoke it manually.
ConfuserEx targets .NET Framework 4.x and is not maintained for modern .NET — many challenges still use it precisely because it is easy to drop in. Commercial obfuscators (SmartAssembly, .NET Reactor, Eazfuscator) are tougher and may need obfuscator-specific de4dot forks or manual work, but the CTF default is ConfuserEx/ConfuserEx2.
Runtime Patching and Debugging in dnSpyEx
dnSpyEx's killer feature is that you can debug managed code as comfortably as in an IDE — and that often beats static analysis entirely.
Publish-Mode Complications
Modern .NET publishing options change where the IL actually lives, and a naive "open in dnSpyEx" fails on them.
Single-file publish wraps all managed assemblies inside one native host executable (often compressed). dnSpyEx/ILSpy cannot read them until extracted. Use a bundle extractor to pull the embedded .dlls, then decompile those:
# ILSpy can open many single-file bundles directly; otherwise extract first.
# The classic helper is the .NET single-file bundle extractor.Once extracted you have ordinary managed DLLs — decompile as usual.
Decision rule: if dnSpyEx/ILSpy shows no types, check the publish mode before assuming heavy obfuscation. Single-file → extract the bundle. Native AOT → switch to native tooling. Only when readable IL exists but names are garbage are you actually dealing with an obfuscator.
Mono and Unity (IL2CPP)
Unity games are a common CTF source and split into two very different cases.
With the Mono scripting backend, all game C# lives in managed IL inside Assembly-CSharp.dll (under *_Data/Managed/). This decompiles exactly like any .NET assembly — open it in dnSpyEx, find the relevant MonoBehaviour, and read or patch it. You can even hot-patch and re-save to change game logic.
IL2CPP global-metadata.dat is sometimes encrypted or has its header stripped to defeat dumpers, and very new Unity versions bump the metadata version beyond what a given Il2CppDumper release supports. If the dump fails, check the metadata version, update the tool, or locate CodeRegistration/MetadataRegistration manually.
Checklist
-
file+ check for theBSJB/mscoreeCLR header → managed vs native - Identify publish mode: managed IL, single-file, self-contained, ReadyToRun, or Native AOT
- Managed → open in dnSpyEx; cross-check with ILSpy
- Names look garbled → identify obfuscator and run de4dot (
de4dot-cexfor ConfuserEx2) - Strings encrypted → breakpoint after the decryptor in dnSpyEx instead of reversing it
- Anti-debug / license checks → patch the method body in dnSpyEx and save the module
- No types shown → extract a single-file bundle, or switch to Ghidra/IDA for Native AOT
- Unity Mono → read
Assembly-CSharp.dlldirectly - Unity IL2CPP → dump with Il2CppDumper +
global-metadata.dat, then run its Ghidra/IDA script
See Also
Last updated on
Reversing Rust Binaries
Cut through monomorphization bloat, demangle v0 symbols, and read Rust's fat pointers, enums, and panic landmarks when reversing stripped Rust binaries for CTF.
Decompilers for CTF Reversing
Compare and use Ghidra, IDA Free, Binary Ninja, and specialized decompilers for CTF reversing.