| name | analyzing-dotnet-malware-internals |
| description | Reverses .NET/managed malware: decompiling MSIL back to C#, defeating common .NET protectors and string encryptors, and tracing reflection-based loaders to recover the real payload. Activates for requests to analyze a .NET sample, decompile MSIL, or unpack a managed loader. |
| domain | cybersecurity |
| subdomain | reverse-engineering |
| tags | ["reverse-engineering","dotnet","msil","decompilation","deobfuscation","managed-code"] |
| version | 1.0.0 |
| author | analyst-ai-pack |
| license | Apache-2.0 |
| mitre_attack | ["T1027","T1620","T1055"] |
| d3fend | ["D3-FCR","D3-DA"] |
| references | ["ECMA-335 Common Language Infrastructure (CIL/MSIL) — https://ecma-international.org/publications-and-standards/standards/ecma-335/","ILSpy decompiler — https://github.com/icsharpcode/ILSpy"] |
Analyzing .NET Malware Internals
When to Use
- A sample is a managed (.NET) assembly — confirmed by a CLR header /
mscoree import or
BSJB metadata signature.
- You need readable C# from MSIL and want to defeat .NET-specific obfuscation.
- A loader uses reflection (
Assembly.Load) to run an in-memory payload you must recover.
Do not use native disassembly workflows (Ghidra for x86) as the primary tool — managed
code decompiles far more cleanly with a .NET decompiler.
Prerequisites
- ILSpy / dnSpyEx for decompilation and (with dnSpyEx) managed debugging.
- de4dot or equivalent for known protectors; familiarity with common .NET obfuscators.
Workflow
Step 1: Confirm it is managed
Check for the CLR runtime header and the BSJB metadata magic:
python scripts/analyst.py identify sample.exe
Step 2: Decompile
Open in ILSpy/dnSpyEx and review the entry point, Main, and module initializer
(<Module>.cctor), which protectors often abuse.
Step 3: Handle obfuscation
Recognize and undo common schemes:
- String encryption — a decryptor method called everywhere; run/trace it to recover
plaintext (de4dot can often static-decrypt).
- Control-flow flattening — follow the dispatcher state machine.
- Proxy methods / renaming — rely on decompiler analysis rather than names.
Step 4: Trace reflection loaders
Find Assembly.Load(byte[]) / Activator.CreateInstance; dump the byte array argument at
runtime (managed debugger breakpoint) to recover the real second-stage assembly, then recurse.
Step 5: Analyze the payload
Decompile the recovered stage; extract C2, configuration, and capabilities for the report.
Validation
- Decompiled C# is coherent (named or recovered) and the entry path is traced.
- Encrypted strings are recovered to plaintext.
- The reflection-loaded stage is dumped and itself decompiles.
Pitfalls
- Treating the loader as the payload — managed malware is frequently multi-stage.
- Ignoring the module initializer where protectors install hooks.
- Static-decrypting strings when the scheme is runtime-keyed; debug and dump instead.
References