XingLo SkillSearch

.NET恶意程序逆向分析

用于.NET恶意程序集分析,重点检查元数据、IL代码、混淆器、字符串与资源、反射加载、配置解密和网络通信逻辑,并结合反编译工具还原高层代码。适合C#远控、窃密、Loader等样本,可较快定位配置对象、C2地址、加密参数、插件体系和关键业务函数。

在 AI 中使用此 Skill将本页链接复制给 AI,即可让 AI 获取完整 Skill 内容并按此执行
安全提示: 本站 Skill 均经 ChatGPT 最新模型扫描,未发现恶意脚本及危险指令、未检出已知恶意行为特征,但不保证绝对安全,使用即表示接受此风险

Skill 文件

版本 20260301 · 0ff90e4c4dc25065c2b7606d36b67fbe

scripts/
SKILL.md
---
name: dotnet-malware-analysis
description: >
  Analyze .NET (managed-code) malware — identify obfuscators, deobfuscate
  with de4dot, decompile to C# with dnSpy/ILSpy, inspect IL metadata tables,
  extract embedded resources and staged payloads, map capabilities via P/Invoke
  and reflection patterns, and extract configurations and IOCs.  Covers pure IL
  assemblies, mixed-mode binaries, and single-file .NET deployments across
  .NET Framework 2.0–4.8 and .NET 5–8.
---

# .NET Malware Analysis

Analyze Windows malware written in C#, VB.NET, or F# targeting the Common
Language Runtime.  .NET malware is the dominant platform for commodity threats
— AgentTesla, AsyncRAT, RedLine, NjRAT, QuasarRAT, and many more — because
it compiles to high-level Intermediate Language (IL) that is trivially
decompilable unless protected by an obfuscator.  This skill provides the
foundational .NET reverse-engineering workflow that family-specific skills
(infostealer-analysis, rat-analysis, etc.) build on.

## Prerequisites

- **de4dot** — .NET deobfuscator/unpacker
  ```bash
  # Pre-built release or build from source
  git clone https://github.com/de4dot/de4dot && cd de4dot && dotnet build
  ```
- **dnSpy** (or dnSpyEx fork) — .NET debugger and assembly editor (GUI)
  ```bash
  # Download from https://github.com/dnSpyEx/dnSpy/releases
  ```
- **ILSpy** / **ilspycmd** — .NET decompiler (CLI-friendly)
  ```bash
  dotnet tool install -g ilspycmd
  ```
- **Python 3.10+** with optional packages:
  ```bash
  pip install pefile dnfile
  ```
- **monodis** (Mono) or **ildasm** (.NET SDK) — IL disassembler for raw IL
  inspection
- **7-Zip** or **binwalk** — for extracting resources from single-file bundles
- **YARA / YARA-X** — for obfuscator signature scanning (optional)

## Step-by-Step Instructions

### Step 1: Confirm .NET Assembly and Classify Binary Type

Before applying .NET-specific tools, verify the sample is actually a managed
assembly and determine its variant:

1. **Check for mscoree.dll import** — all .NET executables import
   `_CorExeMain` from `mscoree.dll` (or `_CorDllMain` for DLLs):
   ```bash
   python scripts/dotnet_analyzer.py --input sample.exe --format json
   ```
   The script checks the PE import table for the `mscoree.dll` reference and
   parses the CLI header.

2. **Identify the .NET version**:
   - **.NET Framework 2.0–4.8**: `TargetFramework` attribute or metadata
     version string (`v4.0.30319`)
   - **.NET 5+/Core**: `System.Runtime` assembly reference, deps.json bundle
   - **Mixed-mode**: Contains both IL and native code sections (C++/CLI)

3. **Detect single-file bundles** — .NET 5+ can bundle all dependencies into
   one executable.  Look for the bundle signature (`\x00\x64\x6E\x00`) near
   the end of the file.  Extract with `dotnet-bundle-extract` or 7-Zip.

4. **Record key metadata** from the CLI header:
   - Entry point token (e.g., `0x06000001`)
   - Metadata RVA and size
   - Flags: `ILONLY`, `32BITREQUIRED`, `STRONGNAMESIGNED`
   - Target CPU: AnyCPU, x86, x64

### Step 2: Inspect .NET Metadata Tables

.NET metadata is the richest source of structural information — far more
descriptive than native PE imports:

1. **Assembly-level metadata**:
   - `Assembly` table: name, version, culture, public key token
   - `AssemblyRef` table: referenced assemblies (reveals framework targets and
     third-party dependencies)
   - `Module` table: MVID (Module Version ID, useful as a tracking hash)

2. **Type system**:
   - `TypeDef` table: all classes/structs/enums defined in the assembly —
     enumerate namespaces and class names for reconnaissance
   - `TypeRef` table: external types referenced — reveals API surface used
   - `MethodDef` table: all methods with signatures — look for suspicious
     names, P/Invoke entry points, and the module entry point

3. **Special tables to inspect**:
   - `ImplMap` (P/Invoke): native function imports — `VirtualAlloc`,
     `WriteProcessMemory`, `CreateRemoteThread` indicate injection
   - `ManifestResource`: embedded resources with names and offsets
   - `CustomAttribute`: obfuscator watermarks, `DebuggerHidden`,
     `SuppressUnmanagedCodeSecurity` attributes

Use `dnfile` in Python for programmatic access:
```python
import dnfile
dn = dnfile.dnPE("sample.exe")
for row in dn.net.mdtables.ImplMap:
    print(f"P/Invoke: {row.ImportName} from {row.ImportScope.row.Name}")
```

Or use `monodis --typedef sample.exe` for quick CLI enumeration.

### Step 3: Detect Obfuscator and Protection

Most .NET malware uses commercial or open-source obfuscators.  Identifying the
protector determines which deobfuscation approach to use:

1. **Automated detection** with de4dot:
   ```bash
   de4dot --detect-only sample.exe
   ```
   This prints the detected obfuscator name and confidence.

2. **Common obfuscators and their signatures**:

   | Obfuscator | Telltale Signs |
   |-----------|----------------|
   | **ConfuserEx** | `ConfuserEx` in module attributes, `koi` resource name pattern, control flow with `switch` on computed index |
   | **.NET Reactor** | `__` prefixed type names, `{GUID}` resource names, embedded native stub in `.rsrc` |
   | **SmartAssembly** | `SmartAssembly.Attributes` namespace, `{GUID}.resources` entries, PoweredBy attribute |
   | **Crypto Obfuscator** | `CryptoObfuscator` attribute, `costura` or guid-named resources |
   | **Eazfuscator.NET** | Single class with many static fields of type `Dictionary<int,string>`, eval-stack based string decryption |
   | **Babel Obfuscator** | `Babel.Licensing` attribute, scrambled metadata tokens |
   | **Dotfuscator** | Preserved type names but renamed members to `a`, `b`, `c`; `DotfuscatorAttribute` |
   | **Agile.NET (CliSecure)** | `<AgileDotNetRT>` or `AgileDotNet.Licenser` attribute |

3. **Manual indicators** when automated detection fails:
   - Module-level `CustomAttribute` entries with obfuscator names
   - Abnormally large `#Strings` or `#Blob` heap sizes
   - Methods with no meaningful names (single chars or unicode garbage)
   - Delegate-based proxy calls replacing direct method calls
   - `Module.cctor` (module initializer) with decryption/unpacking logic

### Step 4: Deobfuscate

Apply the appropriate deobfuscation strategy based on Step 3:

1. **de4dot automated cleaning** (handles most common obfuscators):
   ```bash
   # Auto-detect and clean
   de4dot sample.exe -o sample_clean.exe

   # Force a specific obfuscator if auto-detect is wrong
   de4dot sample.exe -p cr -o sample_clean.exe  # Crypto Obfuscator
   de4dot sample.exe -p cf -o sample_clean.exe  # ConfuserEx
   de4dot sample.exe -p sa -o sample_clean.exe  # SmartAssembly
   de4dot sample.exe -p dr -o sample_clean.exe  # .NET Reactor
   ```

2. **Verify deobfuscation succeeded**:
   - Re-run `de4dot --detect-only sample_clean.exe` — should report
     "Unknown/not obfuscated"
   - Compare TypeDef counts before and after — names should be readable
   - Check that string decryption methods have been inlined

3. **Handle deobfuscation failures**:
   - **Anti-tamper protection**: some obfuscators verify assembly integrity
     at runtime — patch the check or use dnSpy's debugger to dump after
     initialization
   - **Control flow flattening**: if de4dot cannot simplify, use
     dnSpy debugger to trace actual execution paths
   - **Virtualized code**: .NET Reactor and Agile.NET can convert IL to a
     custom VM — requires dedicated devirtualizers or dynamic analysis
   - **Native unpacking stubs**: mixed-mode assemblies may unpack the IL at
     runtime — attach dnSpy debugger and dump `Assembly.Load` calls

4. **Iterative cleaning** — run de4dot multiple times if layers of obfuscation
   are nested (common in loaders that unpack a second-stage .NET assembly):
   ```bash
   de4dot stage1.exe -o stage1_clean.exe
   # Extract embedded stage2 from resources (see Step 6)
   de4dot stage2.dll -o stage2_clean.dll
   ```

### Step 5: Decompile and Analyze IL

With a clean (or cleaner) assembly, recover C# source code:

1. **Full project decompilation** with ilspycmd:
   ```bash
   ilspycmd sample_clean.exe -o ./decompiled/ -p
   ```
   This creates a `.csproj` and `.cs` files — open in any editor or IDE.

2. **Interactive analysis** with dnSpy:
   - Load `sample_clean.exe` — navigate the type tree
   - Right-click methods → "Edit IL Instructions" for raw IL view
   - Set breakpoints on interesting methods and debug under dnSpy

3. **Key IL patterns to watch for**:

   - **Reflection-based loading** — `Assembly.Load(byte[])` or
     `Assembly.LoadFrom()` indicate runtime assembly loading (second-stage
     payloads):
     ```csharp
     Assembly asm = Assembly.Load(decryptedBytes);
     asm.EntryPoint.Invoke(null, null);
     ```

   - **P/Invoke declarations** — native API calls for process injection,
     privilege escalation, or anti-analysis:
     ```csharp
     [DllImport("kernel32.dll")]
     static extern IntPtr VirtualAllocEx(IntPtr hProcess, ...);
     ```

   - **Dynamic method generation** — `System.Reflection.Emit` namespace usage
     indicates runtime code generation to evade static analysis

   - **Unsafe code blocks** — `unsafe` keyword with pointer manipulation,
     unusual for managed malware and may indicate shellcode injection

   - **WMI queries** — `ManagementObjectSearcher` with queries like
     `SELECT * FROM Win32_Processor` for VM detection

   - **Delegate/proxy patterns** — obfuscators replace direct calls with
     delegate invocations; trace the delegate initialization in `.cctor`

4. **Compare decompiled output with raw IL** when the decompiler produces
   suspicious or incorrect code — use `ildasm` or `monodis` for ground truth:
   ```bash
   monodis --method "Namespace.Class::MethodName" sample_clean.exe
   ```

### Step 6: Extract Embedded Resources and Payloads

.NET malware frequently stores encrypted payloads, configuration data, or
second-stage assemblies as embedded resources:

1. **Enumerate resources**:
   ```bash
   monodis --manifest sample_clean.exe
   ```
   Or use dnSpy: expand Resources node in the assembly tree.

2. **Common resource patterns**:
   - **Encrypted payloads**: high-entropy resources (> 7.0 bits/byte) named
     with GUIDs or random strings — find the decryption routine by searching
     for `ResourceManager` or `GetManifestResourceStream` calls
   - **Serialized configs**: XML or binary-formatted resources containing C2
     URLs, keys, and options
   - **Embedded DLLs**: Costura.Fody-packed dependencies stored as compressed
     resources prefixed with `costura.`
   - **Icon/bitmap steganography**: payloads hidden in image resources using
     LSB encoding

3. **Extract and analyze**:
   ```python
   import dnfile
   dn = dnfile.dnPE("sample_clean.exe")
   for resource in dn.net.resources:
       print(f"{resource.name}: offset={resource.offset}, size={resource.size}")
       # Dump resource bytes for entropy analysis and decryption
   ```

4. **Trace the loading code** — search decompiled source for:
   - `Assembly.GetManifestResourceStream("resource_name")`
   - `ResourceManager.GetObject("key")`
   - `Properties.Resources.ResourceName`
   - Any method that reads from resources, decrypts, and calls
     `Assembly.Load()`

5. **Single-file .NET bundles** (.NET 5+): use `dotnet-bundle-extract` or
   search for the bundle header signature to extract all bundled assemblies
   and analyze each one individually.

### Step 7: Map Capabilities and Behavior

Enumerate what the malware can do by analyzing API usage patterns unique to
the .NET ecosystem:

1. **Process injection** (via P/Invoke):
   - `VirtualAllocEx` + `WriteProcessMemory` + `CreateRemoteThread`
   - `NtCreateSection` + `NtMapViewOfSection` (process hollowing)
   - `QueueUserAPC` (APC injection)

2. **Credential theft** (managed APIs):
   - `System.Security.Cryptography.ProtectedData.Unprotect()` (DPAPI)
   - `Microsoft.Win32.Registry` reads from browser credential paths
   - `System.Net.NetworkCredential` and `CredentialCache`
   - SQLite database reads (browser password stores)

3. **Persistence mechanisms**:
   - `Microsoft.Win32.Registry.SetValue()` for Run/RunOnce keys
   - `System.IO.File.Copy()` to startup folders
   - `System.ServiceProcess.ServiceInstaller` for service creation
   - `TaskScheduler` COM interop for scheduled tasks

4. **Network communication**:
   - `System.Net.Http.HttpClient` or `WebClient` for C2 beaconing
   - `System.Net.Sockets.TcpClient` for raw TCP
   - `System.Net.Mail.SmtpClient` for SMTP exfiltration (AgentTesla pattern)
   - `System.Net.FtpWebRequest` for FTP exfiltration

5. **Anti-analysis** (.NET-specific patterns):
   - `System.Diagnostics.Debugger.IsAttached` check
   - `Environment.GetEnvironmentVariable("USERNAME")` sandbox detection
   - `ManagementObjectSearcher("SELECT * FROM Win32_ComputerSystem")` for
     VM manufacturer detection
   - `DateTime` comparisons for time-based evasion
   - `Thread.Sleep()` with long delays for sandbox timeout

6. **Data collection**:
   - `System.Windows.Forms.Clipboard` for clipboard monitoring
   - `SetWindowsHookEx` P/Invoke for keylogging
   - `Screen.CaptureScreen()` or GDI+ `Graphics.CopyFromScreen()` for
     screenshots
   - `System.IO.Directory.GetFiles()` recursive scans for document theft

### Step 8: Extract Configuration and IOCs

Most .NET malware families store configuration in predictable locations:

1. **Hardcoded fields** — search decompiled classes for:
   - Static string fields with Base64 or hex-encoded values
   - Classes named `Config`, `Settings`, `Options`, `Vars`, or single-letter
     names with many string fields
   - Constructor methods that initialize connection parameters

2. **Encrypted configuration** — common patterns:
   - **AES/Rijndael**: `RijndaelManaged` or `Aes.Create()` with hardcoded
     key/IV (often derived from a password via `Rfc2898DeriveBytes`)
   - **XOR**: byte array XOR with a single-byte or multi-byte key
   - **Base64 + AES**: `Convert.FromBase64String()` → AES decrypt
   - **DES/3DES**: older families still use `DESCryptoServiceProvider`

3. **Configuration fields to extract**:
   - C2 server URLs/IPs and ports
   - Encryption keys (AES key, XOR key, RSA public key)
   - Mutex names (for single-instance enforcement)
   - Installation paths and filenames
   - Persistence registry keys
   - Campaign ID / bot ID / group tags
   - Exfiltration credentials (SMTP user/pass, FTP credentials, Telegram
     bot tokens)
   - Kill switch domains or dates

4. **Automated extraction** with the included script:
   ```bash
   python scripts/dotnet_analyzer.py --input sample_clean.exe --format json
   ```

5. **Map findings to MITRE ATT&CK**:
   - Process injection → T1055
   - Registry Run keys → T1547.001
   - Credentials from browsers → T1555.003
   - Keylogging → T1056.001
   - Screen capture → T1113
   - SMTP exfiltration → T1048.003
   - Scheduled task → T1053.005

## Output Format

The `dotnet_analyzer.py` script produces a structured JSON report:

```json
{
  "sample": "/samples/sample.exe",
  "hashes": {
    "md5": "d41d8cd98f00b204e9800998ecf8427e",
    "sha1": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
    "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
  },
  "is_dotnet": true,
  "dotnet_info": {
    "clr_version": "v4.0.30319",
    "target_framework": ".NETFramework,Version=v4.8",
    "flags": ["ILONLY", "32BITREQUIRED"],
    "entry_point_token": "0x06000001",
    "mvid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "is_mixed_mode": false
  },
  "obfuscator": {
    "name": "ConfuserEx",
    "confidence": 0.95,
    "indicators": [
      "ConfuserEx watermark in module attributes",
      "Control flow flattening in entry point"
    ]
  },
  "metadata": {
    "assembly_name": "WindowsService",
    "assembly_version": "1.0.0.0",
    "referenced_assemblies": [
      "mscorlib, Version=4.0.0.0",
      "System.Net.Http, Version=4.0.0.0"
    ],
    "type_count": 42,
    "method_count": 187,
    "pinvoke_imports": [
      {"method": "VirtualAllocEx", "module": "kernel32.dll"},
      {"method": "WriteProcessMemory", "module": "kernel32.dll"}
    ]
  },
  "resources": [
    {
      "name": "payload",
      "size": 45312,
      "entropy": 7.89,
      "likely_encrypted": true
    }
  ],
  "capabilities": {
    "process_injection": true,
    "credential_theft": true,
    "keylogging": false,
    "screen_capture": true,
    "persistence": true,
    "network_communication": true,
    "anti_analysis": true
  },
  "strings_of_interest": [
    "http://evil.example.com/gate.php",
    "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run",
    "smtp.example.com"
  ],
  "mitre_attack": [
    {"technique": "T1055", "name": "Process Injection"},
    {"technique": "T1547.001", "name": "Registry Run Keys"},
    {"technique": "T1113", "name": "Screen Capture"}
  ],
  "timestamp": "2026-03-24T12:00:00Z"
}
```

## Tips

- **Always deobfuscate before decompiling** — readable names and simplified
  control flow make the decompiled C# dramatically easier to understand
- **Check Module.cctor first** — the module initializer (`.cctor` of
  `<Module>`) often contains decryption, anti-tamper, or unpacking logic that
  runs before `Main()`
- **Use MVID for tracking** — the Module Version ID is a unique GUID per
  compilation; it clusters related samples even when hashes differ due to
  minor config changes
- **P/Invoke is the attack surface** — most dangerous capabilities require
  native API calls; enumerate `ImplMap` entries for a quick threat assessment
- **Watch for Assembly.Load** — dynamic assembly loading is the primary
  mechanism for multi-stage .NET malware; set breakpoints on it in dnSpy
- **Resources are payloads until proven otherwise** — high-entropy embedded
  resources in .NET malware are almost always encrypted second-stage payloads
  or configuration blobs
- **De4dot is not perfect** — it struggles with heavily customized ConfuserEx
  forks and .NET Reactor's native code protection; fall back to dnSpy
  debugging for runtime unpacking
- **Single-file bundles need extraction first** — .NET 5+ single-file apps
  look like native executables but contain bundled managed assemblies; extract
  before analyzing
- **Mixed-mode is rare but dangerous** — C++/CLI assemblies combine native and
  managed code; analyze both the IL and native sections
- **Combine with family-specific skills**:
  - `infostealer-analysis` — AgentTesla, RedLine config extraction workflows
  - `rat-analysis` — AsyncRAT, NjRAT, QuasarRAT protocol analysis
  - `string-decryption` — .NET string decryption automation
  - `malware-deobfuscation` — advanced deobfuscation techniques
  - `config-extraction` — standardized config extraction patterns