Skip to main content

reverser-dotnet-malware

.NET malware analysis — dnSpy/ILSpy decompilation, de-obfuscation (ConfuserEx, .NET Reactor, Babel, Crypto Obfuscator), behavioral analysis of managed assemblies, PowerShell cradle extraction, and config decryption for common .NET RAT families.

الانتقال إلى التثبيت

معلومات المصدر

المستودع
BitterSecurity/Decepticon
آخر نشاط في المصدر
٢٩ يونيو ٢٠٢٦ في ٠١:٣٨
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٥٬٥٢٢
التفرعات
١٬٠٤٨

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
reverser-dotnet-malware
description
.NET malware analysis — dnSpy/ILSpy decompilation, de-obfuscation (ConfuserEx, .NET Reactor, Babel, Crypto Obfuscator), behavioral analysis of managed assemblies, PowerShell cradle extraction, and config decryption for common .NET RAT families.
allowed-tools
Bash Read Write
metadata
{"when_to_use":"dotnet .net malware dnspy ilspy de4dot deobfuscate confuserex reactor obfuscation managed assembly csharp vbnet msil cil rat stealer loader","subdomain":"reverser","tags":".NET, malware, deobfuscation, dnSpy, ILSpy, de4dot","mitre_attack":"T1027.002, T1140, T1059.001"}
# .NET Malware Analysis Analyze .NET malware from initial triage through full decompilation, de-obfuscation, config extraction, and behavioral mapping. ## Quick Reference ```bash # Identify .NET assembly file <TARGET> python3 -c "import pefile; pe=pefile.PE('<TARGET>'); print('CLR:', pe.OPTIONAL_HEADER.DATA_DIRECTORY[14].VirtualAddress)" # Fast metadata check monodis --assembly <TARGET> strings -n 10 <TARGET> | grep -iE 'System\.Reflection|Assembly\.Load|FromBase64|Invoke|WebClient|DownloadString' # De-obfuscate with de4dot de4dot <TARGET> -o <TARGET>.cleaned.exe # Decompile to C# project ilspycmd -p -o ./decompiled/ <TARGET> # Extract embedded resources python3 -c " import dnfile dn = dnfile.dnPE('<TARGET>') for r in dn.net.resources: print(f'{r.name} offset={r.offset} size={r.size}') " ``` ## MITRE ATT&CK Mapping | Technique | ID | How It Appears | |---|---|---| | Software Packing | T1027.002 | ConfuserEx, .NET Reactor, SmartAssembly, Babel packing | | Deobfuscate/Decode | T1140 | Base64 decode + Assembly.Load, XOR decryption of payloads | | PowerShell | T1059.001 | Cradle execution: `powershell -enc <base64>` from managed code | | Obfuscated Files | T1027 | String encryption, control flow flattening, anti-tamper | | Reflective Code Loading | T1620 | Assembly.Load(byte[]) for in-memory stage loading | ## 1. Identify .NET Assembly Confirm the sample is managed code before committing to .NET tooling. ```bash # Check PE headers for CLR data directory (index 14) python3 << 'EOF' import pefile, sys pe = pefile.PE("<TARGET>") clr_dir = pe.OPTIONAL_HEADER.DATA_DIRECTORY[14] if clr_dir.VirtualAddress > 0: print(f"[+] .NET assembly confirmed — CLR RVA: {hex(clr_dir.VirtualAddress)}") # Check runtime version import struct clr_offset = pe.get_offset_from_rva(clr_dir.VirtualAddress) pe.__data__.seek(clr_offset + 8) major, minor = struct.unpack('<HH', pe.__data__.read(4)) print(f" Runtime: v{major}.{minor}") else: print("[-] Not a .NET assembly") sys.exit(1) EOF # Alternative quick checks file <TARGET> # Look for "Mono/.Net assembly" exiftool <TARGET> | grep -i "assembly\|\.net\|framework" ``` ## 2. Detect Obfuscator Identify what protection was applied before attempting decompilation. ```bash # de4dot auto-detects most obfuscators de4dot --detect-only <TARGET> # Output example: "Detected .NET Reactor 6.x" # Detect It Easy (DIE) for packer/protector identification diec <TARGET> # Manual signature checks strings <TARGET> | grep -iE 'ConfuserEx|Reactor|SmartAssembly|Babel|Crypto Obfuscator|Dotfuscator|Eazfuscator|AgileDotNet' # Check for anti-tamper / anti-debug module initializers monodis --method <TARGET> | grep -i "cctor\|InitializeComponent\|Module" # Entropy per section — high entropy in .text = packed/encrypted python3 << 'EOF' import pefile, math pe = pefile.PE("<TARGET>") for s in pe.sections: data = s.get_data() if len(data) == 0: continue counts = [data.count(bytes([b])) for b in range(256)] total = len(data) ent = -sum((c/total)*math.log2(c/total) for c in counts if c) name = s.Name.decode().rstrip('\x00') print(f" {name:10s} entropy={ent:.2f} {'PACKED' if ent > 7.2 else 'normal'}") EOF ``` ## 3. De-obfuscate Strip protections layer by layer. ```bash # de4dot — handles ConfuserEx, .NET Reactor, SmartAssembly, Babel, etc. de4dot <TARGET> -o <TARGET>.cleaned.exe # If de4dot detects "Unknown obfuscator", try force mode: de4dot <TARGET> --strtyp delegate --strtok 0x06000042 -o <TARGET>.cleaned.exe # For ConfuserEx specifically: # 1. Remove anti-tamper first (patches module cctor) de4dot <TARGET> --un-name "!^<Module>$&!^<" -o step1.exe # 2. Then full clean de4dot step1.exe -o <TARGET>.cleaned.exe # For .NET Reactor: # Use .NET Reactor Slayer or NETReactorSlayer NETReactorSlayer.CLI <TARGET> # Verify result decompiles cleanly ilspycmd <TARGET>.cleaned.exe | head -50 ``` ## 4. Decompile and Analyze Full source recovery from cleaned assembly. ```bash # ILSpy command-line — full project decompilation ilspycmd -p -o ./decompiled/ <TARGET>.cleaned.exe # Search decompiled source for key behaviors grep -rn "WebClient\|HttpClient\|WebRequest" ./decompiled/ grep -rn "Registry\|RegistryKey\|SetValue" ./decompiled/ grep -rn "Process\.Start\|ProcessStartInfo" ./decompiled/ grep -rn "Assembly\.Load\|Activator\.CreateInstance" ./decompiled/ grep -rn "FromBase64String\|Convert\.FromBase64" ./decompiled/ grep -rn "RijndaelManaged\|AesManaged\|DES\|TripleDES\|RC4" ./decompiled/ grep -rn "Socket\|TcpClient\|NetworkStream" ./decompiled/ grep -rn "Clipboard\|Screenshot\|Keylog\|GetAsyncKeyState" ./decompiled/ # Extract hardcoded C2 / config grep -rn "http://\|https://\|ftp://\|\b[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\b" ./decompiled/ # Dump embedded resources (payloads, configs, second stages) python3 << 'EOF' import dnfile, os dn = dnfile.dnPE("<TARGET>.cleaned.exe") os.makedirs("resources", exist_ok=True) for res in dn.net.resources: if hasattr(res, 'data') and res.data: path = f"resources/{res.name}" open(path, 'wb').write(res.data) print(f"[+] Extracted: {path} ({len(res.data)} bytes)") EOF ``` ## 5. PowerShell Cradle Extraction .NET loaders frequently spawn encoded PowerShell. ```bash # Find encoded PowerShell invocations in decompiled source grep -rn "\-enc\|\-EncodedCommand\|\-e " ./decompiled/ # Decode base64 PowerShell payloads python3 << 'EOF' import base64, sys encoded = "<BASE64_PAYLOAD>" decoded = base64.b64decode(encoded).decode('utf-16-le') print(decoded) # Write to file for further analysis with open("decoded_ps.ps1", "w") as f: f.write(decoded) EOF # Look for staged downloads grep -iE 'DownloadString|DownloadFile|DownloadData|Invoke-Expression|IEX|Net\.WebClient' decoded_ps.ps1 ``` ## 6. Config Extraction for Known Families ```bash # AsyncRAT config extraction python3 << 'EOF' import base64, hashlib from Crypto.Cipher import AES # AsyncRAT stores config as encrypted strings in Settings class # Key is derived from a hardcoded passphrase via PBKDF2 passphrase = "<EXTRACTED_KEY>" # From Settings.Key in decompiled source salt = b"<EXTRACTED_SALT>" # From Settings.aession key = hashlib.pbkdf2_hmac('sha1', passphrase.encode(), salt, 50000, dklen=32) # Each config field is Base64(IV + AES-CBC(data)) config_fields = { "Host": "<ENC_HOST>", "Port": "<ENC_PORT>", "Mutex": "<ENC_MUTEX>", } for name, enc in config_fields.items(): raw = base64.b64decode(enc) iv, ct = raw[:16], raw[16:] cipher = AES.new(key, AES.MODE_CBC, iv) pt = cipher.decrypt(ct) pt = pt[:-pt[-1]] # PKCS7 unpad print(f" {name}: {pt.decode()}") EOF # QuasarRAT — config in Settings class, AES-encrypted # njRAT — config in plain text fields, base64-encoded # AgentTesla — SMTP exfil config in Settings resource ``` ## 7. Behavioral Analysis with dnSpy ``` # dnSpy interactive workflow (Windows GUI): # 1. Load cleaned assembly: File → Open → <TARGET>.cleaned.exe # 2. Set breakpoints on: # - EntryPoint (Main method) # - Any method calling WebClient/HttpClient # - Any method calling Process.Start # - Any method calling Assembly.Load # 3. Debug → Start (F5) — dnSpy hosts the CLR # 4. Step through, watch locals for decrypted strings/URLs # 5. Memory window: watch for in-memory PE headers (4D 5A) # Headless: dump method bodies via Mono.Cecil python3 << 'EOF' # pip install dnfile import dnfile dn = dnfile.dnPE("<TARGET>.cleaned.exe") for row in dn.net.mdtables.MethodDef: if row.ImplFlags.miIL: print(f" Token 0x{row.row_index:08X} {row.Name} RVA={hex(row.RVA)}") EOF ``` ## Tools & Resources | Tool | Purpose | Install | |---|---|---| | dnSpy | .NET debugger + decompiler (GUI) | github.com/dnSpy/dnSpy | | ILSpy / ilspycmd | .NET decompiler (GUI + CLI) | github.com/icsharpcode/ILSpy | | de4dot | .NET de-obfuscator | github.com/de4dot/de4dot | | dotPeek | JetBrains .NET decompiler | jetbrains.com/decompiler | | dnlib / dnfile | .NET metadata parsing (Python/C#) | pip install dnfile | | Mono.Cecil | .NET assembly manipulation | nuget Mono.Cecil | | NETReactorSlayer | .NET Reactor unpacker | github.com/SychicBT/NETReactorSlayer | | Detect It Easy | Packer/protector identification | github.com/horsicq/Detect-It-Easy | | AsmResolver | .NET PE/metadata library | github.com/Washi1337/AsmResolver | ## Detection Signatures | Indicator | Description | Sigma/YARA | |---|---|---| | `Assembly.Load(byte[])` | Reflective loading of in-memory .NET payload | YARA: `$s1 = "Assembly" ascii wide` + `$s2 = "Load" ascii wide` | | `FromBase64String` + `Assembly.Load` | Base64 decode → reflective load chain | Sigma: process_creation with CommandLine containing `-enc` | | `WebClient.DownloadString` | Stage 2 download via .NET HTTP client | Network: HTTP GET to non-standard port | | ConfuserEx metadata | `ConfusedBy` attribute in assembly | YARA: `$conf = "ConfusedByAttribute"` | | High entropy .text section | Packed/encrypted .NET payload | YARA: `math.entropy(0, filesize) > 7.0` | | `csc.exe` compilation at runtime | Dynamic code compilation via CodeDom | Sysmon: Event ID 1, process `csc.exe` with parent not devenv/msbuild | ## Error Handling & Edge Cases | Issue | Resolution | |---|---| | de4dot crashes on sample | Try older de4dot fork, or manually patch anti-tamper (NOP the module cctor) | | Mixed mode assembly (native + managed) | Use dnSpy for managed parts, IDA/Ghidra for native stubs | | AOT/NativeAOT compiled | Not a traditional .NET assembly — treat as native PE, use Ghidra | | .NET 5+ single-file bundle | Extract with `dotnet-dump` or manually parse bundle header at end of PE | | Heavily virtualized (KoiVM/EazVM) | Use specialized devirtualizers: OldRod (KoiVM), EazFixer (Eazfuscator) | | Anti-debug in module initializer | Patch `<Module>.cctor` or use dnSpy's "Edit IL" to NOP checks | | Resource encryption | Dump at runtime with dnSpy breakpoints on `ResourceManager.GetObject` | ## Decision Gate ``` IF sample is .NET assembly (CLR header present): → Run de4dot to identify + strip obfuscation → Decompile with ILSpy/dnSpy → Extract configs for known RAT families → Map behaviors to ATT&CK techniques → Extract IOCs (C2, mutex, registry keys) ELSE IF .NET single-file or AOT: → Extract bundled assemblies first, then proceed above ELSE: → Not .NET — use reverser/malware-triage or reverser/ghidra ```
عرض على GitHub