mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-16 04:35:18 +03:00
339 lines
13 KiB
Markdown
339 lines
13 KiB
Markdown
---
|
|
name: reverse-engineering-dotnet-malware-with-dnspy
|
|
description: >
|
|
Reverse engineers .NET malware using dnSpy decompiler and debugger to analyze C#/VB.NET
|
|
source code, identify obfuscation techniques, extract configurations, and understand
|
|
malicious functionality including stealers, RATs, and loaders. Activates for requests
|
|
involving .NET malware analysis, C# malware decompilation, managed code reverse
|
|
engineering, or .NET obfuscation analysis.
|
|
domain: cybersecurity
|
|
subdomain: malware-analysis
|
|
tags: [malware, dotnet, reverse-engineering, dnSpy, decompilation]
|
|
version: 1.0.0
|
|
author: mahipal
|
|
license: Apache-2.0
|
|
---
|
|
|
|
# Reverse Engineering .NET Malware with dnSpy
|
|
|
|
## When to Use
|
|
|
|
- A malware sample is identified as a .NET assembly (C#, VB.NET, F#) requiring decompilation
|
|
- Analyzing .NET-based malware families (AgentTesla, AsyncRAT, RedLine Stealer, Quasar RAT)
|
|
- Deobfuscating .NET code protected by ConfuserEx, SmartAssembly, or custom obfuscators
|
|
- Extracting hardcoded C2 configurations, encryption keys, and credentials from managed assemblies
|
|
- Debugging .NET malware at runtime to observe decryption routines and dynamic behavior
|
|
|
|
**Do not use** for native (unmanaged) PE binaries; use Ghidra or IDA for native code analysis.
|
|
|
|
## Prerequisites
|
|
|
|
- dnSpy or dnSpyEx installed (https://github.com/dnSpyEx/dnSpy - community maintained fork)
|
|
- de4dot for automated .NET deobfuscation (`https://github.com/de4dot/de4dot`)
|
|
- ILSpy as an alternative decompiler for cross-validation
|
|
- .NET SDK installed for recompiling modified assemblies during analysis
|
|
- Isolated Windows VM for running dnSpy debugger on live malware
|
|
- Detect It Easy (DIE) for identifying the .NET obfuscator used
|
|
|
|
## Workflow
|
|
|
|
### Step 1: Identify .NET Assembly and Obfuscator
|
|
|
|
Verify the sample is a .NET binary and detect protection:
|
|
|
|
```bash
|
|
# Check if file is .NET assembly
|
|
file suspect.exe
|
|
# Output should contain "PE32 executable" with .NET metadata
|
|
|
|
# Detect obfuscator with Detect It Easy
|
|
diec suspect.exe
|
|
|
|
# Python-based .NET detection
|
|
python3 << 'PYEOF'
|
|
import pefile
|
|
|
|
pe = pefile.PE("suspect.exe")
|
|
|
|
# Check for .NET COM descriptor
|
|
if hasattr(pe, 'DIRECTORY_ENTRY_COM_DESCRIPTOR'):
|
|
print("[*] .NET assembly detected")
|
|
print(f" Runtime version: {pe.DIRECTORY_ENTRY_COM_DESCRIPTOR}")
|
|
else:
|
|
# Check for mscoree.dll import (alternative detection)
|
|
for entry in pe.DIRECTORY_ENTRY_IMPORT:
|
|
if entry.dll.decode().lower() == "mscoree.dll":
|
|
print("[*] .NET assembly detected (mscoree.dll import)")
|
|
break
|
|
else:
|
|
print("[!] Not a .NET assembly")
|
|
|
|
# Check section names for .NET indicators
|
|
for section in pe.sections:
|
|
name = section.Name.decode().rstrip('\x00')
|
|
if name in ['.text', '.rsrc', '.reloc']:
|
|
print(f" Section: {name} (typical .NET)")
|
|
PYEOF
|
|
```
|
|
|
|
### Step 2: Deobfuscate with de4dot
|
|
|
|
Remove common .NET obfuscation before manual analysis:
|
|
|
|
```bash
|
|
# Run de4dot to identify and remove obfuscation
|
|
de4dot suspect.exe -o suspect_cleaned.exe
|
|
|
|
# Force specific deobfuscator
|
|
de4dot suspect.exe -p cf # ConfuserEx
|
|
de4dot suspect.exe -p sa # SmartAssembly
|
|
de4dot suspect.exe -p dr # Dotfuscator
|
|
de4dot suspect.exe -p rv # Reactor
|
|
de4dot suspect.exe -p bl # Babel.NET
|
|
|
|
# Verbose output for debugging
|
|
de4dot -v suspect.exe -o suspect_cleaned.exe
|
|
|
|
# Handle multi-file assemblies
|
|
de4dot suspect.exe suspect_helper.dll -o cleaned/
|
|
```
|
|
|
|
```
|
|
Common .NET Obfuscators:
|
|
━━━━━━━━━━━━━━━━━━━━━━━
|
|
ConfuserEx: String encryption, control flow, anti-debug, anti-tamper
|
|
SmartAssembly: String encoding, flow obfuscation, pruning
|
|
Dotfuscator: Renaming, string encryption, control flow
|
|
.NET Reactor: Native code generation, necrobit, anti-debug
|
|
Babel.NET: String encryption, resource encryption, code virtualization
|
|
Crypto Obfuscator: String encryption, anti-debug, watermarking
|
|
Custom: Malware-specific obfuscation (manual de4dot configuration needed)
|
|
```
|
|
|
|
### Step 3: Open in dnSpy and Analyze Code
|
|
|
|
Load the deobfuscated assembly in dnSpy for source-level analysis:
|
|
|
|
```
|
|
dnSpy Analysis Workflow:
|
|
━━━━━━━━━━━━━━━━━━━━━━━
|
|
1. File -> Open -> Select cleaned assembly
|
|
2. Navigate to the entry point:
|
|
- Assembly Explorer -> <namespace> -> Program class -> Main method
|
|
- Or: Right-click assembly -> Go to Entry Point
|
|
|
|
3. Key areas to examine:
|
|
- Entry point (Main) for initialization and execution flow
|
|
- Form classes for UI-based malware (RATs, stealers)
|
|
- Network/HTTP classes for C2 communication
|
|
- Crypto/encryption classes for data protection
|
|
- Resource access for embedded payloads
|
|
- Timer/Thread classes for persistence and scheduling
|
|
|
|
4. Navigation shortcuts:
|
|
Ctrl+G - Go to token/address
|
|
Ctrl+Shift+K - Search assemblies
|
|
F12 - Go to definition
|
|
Ctrl+R - Analyze (find usages)
|
|
F5 - Start debugging
|
|
F9 - Toggle breakpoint
|
|
```
|
|
|
|
### Step 4: Extract Configuration and C2 Data
|
|
|
|
Locate hardcoded configuration in the decompiled source:
|
|
|
|
```csharp
|
|
// Common .NET malware configuration patterns:
|
|
|
|
// Pattern 1: Static class with hardcoded values
|
|
public static class Config {
|
|
public static string Host = "185.220.101.42";
|
|
public static int Port = 4782;
|
|
public static string Key = "GhOsT_RaT_2025";
|
|
public static string Mutex = "AsyncMutex_6SI8OkPnk";
|
|
public static bool Install = true;
|
|
public static string InstallFolder = "%AppData%";
|
|
}
|
|
|
|
// Pattern 2: Encrypted strings decrypted at runtime
|
|
public static string Decrypt(string input) {
|
|
byte[] data = Convert.FromBase64String(input);
|
|
byte[] key = Encoding.UTF8.GetBytes("SecretKey123");
|
|
for (int i = 0; i < data.Length; i++) {
|
|
data[i] ^= key[i % key.Length];
|
|
}
|
|
return Encoding.UTF8.GetString(data);
|
|
}
|
|
|
|
// Pattern 3: Resource-embedded configuration
|
|
byte[] configData = Properties.Resources.config;
|
|
string config = AES.Decrypt(configData, derivedKey);
|
|
```
|
|
|
|
```python
|
|
# Python script to extract .NET resource strings
|
|
import subprocess
|
|
import re
|
|
import base64
|
|
|
|
# Use monodis (Mono) or ildasm (.NET SDK) to dump IL
|
|
result = subprocess.run(
|
|
["monodis", "--output=il_dump.il", "suspect_cleaned.exe"],
|
|
capture_output=True, text=True
|
|
)
|
|
|
|
# Search for string literals in IL dump
|
|
with open("il_dump.il", errors="ignore") as f:
|
|
il_code = f.read()
|
|
|
|
# Find ldstr (load string) instructions
|
|
strings = re.findall(r'ldstr\s+"([^"]+)"', il_code)
|
|
for s in strings:
|
|
# Check for Base64 encoded strings
|
|
try:
|
|
decoded = base64.b64decode(s).decode('utf-8', errors='ignore')
|
|
if len(decoded) > 3 and decoded.isprintable():
|
|
print(f" Base64: {s[:40]}... -> {decoded[:100]}")
|
|
except:
|
|
pass
|
|
# Check for URLs/IPs
|
|
if re.match(r'https?://', s) or re.match(r'\d+\.\d+\.\d+\.\d+', s):
|
|
print(f" Network: {s}")
|
|
```
|
|
|
|
### Step 5: Debug with dnSpy
|
|
|
|
Set breakpoints and debug the malware to observe runtime behavior:
|
|
|
|
```
|
|
dnSpy Debugging Workflow:
|
|
━━━━━━━━━━━━━━━━━━━━━━━
|
|
1. Set breakpoints on key methods:
|
|
- String decryption functions (to capture decrypted values)
|
|
- Network connection methods (to capture C2 URLs)
|
|
- File write operations (to see what is dropped)
|
|
- Registry modification methods (to see persistence)
|
|
|
|
2. Debug -> Start Debugging (F5)
|
|
- Select the assembly to debug
|
|
- Set command-line arguments if needed
|
|
- Configure exception handling (break on all CLR exceptions)
|
|
|
|
3. At each breakpoint:
|
|
- Inspect local variables (Locals window)
|
|
- Evaluate expressions (Immediate window)
|
|
- View call stack to understand execution context
|
|
- Step over (F10) / Step into (F11) / Step out (Shift+F11)
|
|
|
|
4. Capture decrypted strings:
|
|
- Set breakpoint after decryption function returns
|
|
- Read the return value from the Locals window
|
|
- Document all decrypted configuration values
|
|
```
|
|
|
|
### Step 6: Document Findings
|
|
|
|
Compile analysis results into a structured report:
|
|
|
|
```
|
|
Analysis documentation should include:
|
|
- .NET assembly metadata (CLR version, target framework, compilation info)
|
|
- Obfuscator identified and deobfuscation method used
|
|
- Complete C2 configuration (hosts, ports, encryption keys, mutex names)
|
|
- Malware capabilities (keylogging, screen capture, file theft, etc.)
|
|
- Persistence mechanisms (registry, scheduled tasks, startup folder)
|
|
- Anti-analysis techniques (VM detection, debugger detection, sandbox evasion)
|
|
- Extracted IOCs (C2 IPs/domains, file hashes, mutex names, registry keys)
|
|
- YARA rule based on unique code patterns or strings
|
|
```
|
|
|
|
## Key Concepts
|
|
|
|
| Term | Definition |
|
|
|------|------------|
|
|
| **CIL/MSIL** | Common Intermediate Language; the bytecode format .NET assemblies compile to, which can be decompiled back to high-level C#/VB.NET |
|
|
| **Metadata Token** | Unique identifier for .NET types, methods, and fields within the assembly metadata tables; used for navigation in dnSpy |
|
|
| **de4dot** | Open-source .NET deobfuscator that identifies and removes protection from many commercial and malware-specific obfuscators |
|
|
| **ConfuserEx** | Popular open-source .NET obfuscator frequently used by malware authors for string encryption and control flow obfuscation |
|
|
| **String Encryption** | Obfuscation technique replacing string literals with encrypted data and runtime decryption calls to hide IOCs from static analysis |
|
|
| **Resource Embedding** | Storing configuration, payloads, or additional assemblies in .NET embedded resources, often encrypted with a key derived from assembly metadata |
|
|
| **Assembly.Load** | .NET method loading assemblies from byte arrays in memory, enabling fileless execution of embedded payloads |
|
|
|
|
## Tools & Systems
|
|
|
|
- **dnSpy/dnSpyEx**: Open-source .NET assembly editor, decompiler, and debugger supporting C# and VB.NET decompilation
|
|
- **de4dot**: Automated .NET deobfuscator supporting ConfuserEx, SmartAssembly, Dotfuscator, Reactor, and many other protectors
|
|
- **ILSpy**: Open-source .NET decompiler providing C#, VB.NET, and IL views of assembly code
|
|
- **dotPeek**: JetBrains' free .NET decompiler with symbol server and cross-reference navigation
|
|
- **Detect It Easy (DIE)**: Multi-format file analyzer identifying .NET framework version, obfuscator, and compiler information
|
|
|
|
## Common Scenarios
|
|
|
|
### Scenario: Analyzing an AgentTesla Information Stealer
|
|
|
|
**Context**: A phishing email delivers a .NET executable identified as AgentTesla. The sample needs analysis to determine what credentials it steals, how it exfiltrates data, and its C2 configuration.
|
|
|
|
**Approach**:
|
|
1. Run Detect It Easy to identify the obfuscator (commonly ConfuserEx or custom)
|
|
2. Deobfuscate with de4dot to restore readable class/method names and decrypt strings
|
|
3. Open in dnSpy and navigate to the entry point to understand initialization
|
|
4. Locate the credential harvesting modules (browser, email, FTP, VPN password theft classes)
|
|
5. Find the exfiltration method (SMTP email, FTP upload, HTTP POST, Telegram bot API)
|
|
6. Extract C2 configuration (SMTP server, credentials, recipient email, or HTTP URL)
|
|
7. Set debugger breakpoints on the decryption function to capture all decrypted strings at once
|
|
|
|
**Pitfalls**:
|
|
- Analyzing without de4dot first (ConfuserEx makes manual analysis extremely difficult)
|
|
- Not checking for multi-stage loading (initial .NET executable may load additional assemblies from resources)
|
|
- Missing configuration stored in .NET resources rather than hardcoded strings
|
|
- Running the debugger without network isolation (AgentTesla will attempt to exfiltrate immediately)
|
|
|
|
## Output Format
|
|
|
|
```
|
|
.NET MALWARE ANALYSIS REPORT
|
|
================================
|
|
Sample: invoice_scanner.exe
|
|
SHA-256: e3b0c44298fc1c149afbf4c8996fb924...
|
|
Type: .NET Assembly (C#)
|
|
Framework: .NET Framework 4.8
|
|
Obfuscator: ConfuserEx v1.6
|
|
Deobfuscated: Yes (de4dot -p cf)
|
|
|
|
CLASSIFICATION
|
|
Family: AgentTesla v3
|
|
Type: Information Stealer / Keylogger
|
|
Compile Date: 2025-09-10
|
|
|
|
C2 CONFIGURATION
|
|
Exfil Method: SMTP (Email)
|
|
SMTP Server: smtp.yandex[.]com:587
|
|
SMTP User: exfil.account@yandex[.]com
|
|
SMTP Pass: Str0ngP@ssw0rd2025
|
|
Recipient: operator@protonmail[.]com
|
|
Interval: 30 minutes
|
|
Encryption: AES-256 with key "AgentTesla_2025_key"
|
|
|
|
CAPABILITIES
|
|
[*] Browser credential theft (Chrome, Firefox, Edge, Opera)
|
|
[*] Email client passwords (Outlook, Thunderbird)
|
|
[*] FTP client credentials (FileZilla, WinSCP)
|
|
[*] VPN credentials (NordVPN, OpenVPN)
|
|
[*] Keylogging (SetWindowsHookEx)
|
|
[*] Screenshot capture (every 30 seconds)
|
|
[*] Clipboard monitoring
|
|
|
|
PERSISTENCE
|
|
Method: Registry Run key + Scheduled Task
|
|
Registry: HKCU\Software\Microsoft\Windows\CurrentVersion\Run\WindowsUpdate
|
|
Task: \Microsoft\Windows\WindowsUpdate\Updater
|
|
|
|
EXTRACTED IOCs
|
|
SMTP Server: smtp.yandex[.]com
|
|
Exfil Email: exfil.account@yandex[.]com
|
|
Recipient: operator@protonmail[.]com
|
|
Mutex: AgentTesla_2025_Q3_MUTEX
|
|
Install Path: %AppData%\Microsoft\Windows\svchost.exe
|
|
```
|