reverse-skills-max: initial public release (restored, redacted, hardened)

This commit is contained in:
baradok609hecl1pq6qi
2026-10-20 02:17:15 +03:00
commit da24c2bd20
2227 changed files with 443931 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
Apache License 2.0 — see the repository root LICENSE file for the full text.
Copyright the AnalystAIPack contributors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0

View File

@@ -0,0 +1,96 @@
---
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:
```bash
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
- See [`references/api-reference.md`](references/api-reference.md) for the CLR identifier.
- ECMA-335 and ILSpy (linked in frontmatter).

View File

@@ -0,0 +1,39 @@
# API Reference: Reverse Engineering .NET Malware
## Overview
`scripts/analyst.py` parses a PE to detect the CLR runtime header (COM descriptor data directory
index 14) and the `BSJB` metadata-root signature, confirming whether a sample is managed. It
parses bytes only and never executes the sample.
## Dependencies
| Package | Version | Purpose |
|---------|---------|---------|
| (stdlib) | — | struct parsing, file IO |
## External tools
| Tool | Purpose |
|------|---------|
| ILSpy / dnSpyEx | Decompile MSIL to C#; managed debugging |
| de4dot | Static deobfuscation of known protectors |
## Core functions
### `identify(path)`
Returns whether the sample is managed, whether the `BSJB` metadata signature is present, and
diagnostic notes (mscoree/_CorExeMain references).
## Usage
```bash
python scripts/analyst.py identify sample.exe
```
## Sources
- ECMA-335 Common Language Infrastructure (CIL/MSIL metadata, BSJB root) —
https://ecma-international.org/publications-and-standards/standards/ecma-335/
- PE COM descriptor data directory (index 14) — PE/COFF specification
- ILSpy decompiler — https://github.com/icsharpcode/ILSpy

View File

@@ -0,0 +1,64 @@
#!/usr/bin/env python3
"""Identify a .NET/managed assembly and surface basic CLR metadata signals.
Parses the PE far enough to detect the COM descriptor (CLR) data directory and searches for
the ``BSJB`` metadata-root signature. Static parsing only; the sample is never executed.
"""
from __future__ import annotations
import argparse
import json
import struct
import sys
from pathlib import Path
def identify(path: str) -> dict:
data = Path(path).read_bytes()
result = {"managed": False, "bsjb_metadata": False, "notes": []}
if data[:2] != b"MZ":
result["notes"].append("not a PE (no MZ)")
return result
e_lfanew = struct.unpack_from("<I", data, 0x3C)[0]
if data[e_lfanew:e_lfanew + 4] != b"PE\x00\x00":
result["notes"].append("no PE signature")
return result
coff = e_lfanew + 4
opt = coff + 20
magic = struct.unpack_from("<H", data, opt)[0]
pe32_plus = magic == 0x20B
# data directories start after the standard+windows optional header fields
dd_offset = opt + (112 if pe32_plus else 96)
# COM descriptor is data directory index 14
com_dir = dd_offset + 14 * 8
rva, size = struct.unpack_from("<II", data, com_dir)
if rva and size:
result["managed"] = True
result["notes"].append("CLR runtime header (COM descriptor) present")
if b"BSJB" in data:
result["bsjb_metadata"] = True
result["notes"].append("BSJB metadata root signature found")
if b"mscoree.dll" in data or b"_CorExeMain" in data:
result["notes"].append("mscoree / _CorExeMain reference")
result["managed"] = result["managed"] or result["bsjb_metadata"]
return result
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description="Identify managed .NET assembly")
sub = parser.add_subparsers(dest="cmd", required=True)
p = sub.add_parser("identify")
p.add_argument("file")
args = parser.parse_args(argv)
print(json.dumps(identify(args.file), indent=2))
return 0
if __name__ == "__main__":
sys.exit(main())