// DefenderRuleParser // Author: Andrea Cristaldi 2025 - https://github.com/andreacristaldi/DefenderRuleParser // This project is licensed under the Apache 2.0 License. /* * Summary: NSCRIPT “cure” variant parser (clean-up/remediation recipes). * Origin: dump-driven; step codes and parameters inferred from dumps. * Role: Presents steps as readable pseudo-operations without execution semantics. */ using System; using System.Collections.Generic; using System.IO; using System.Text; using DefenderRuleParser2.Models; namespace DefenderRuleParser2.Parsers { public class NscriptCureParser : ISignatureParser { public void Parse(BinaryReader reader, int size, uint threatId) { long offset = reader.BaseStream.Position; try { byte[] buffer = reader.ReadBytes(size); string asciiPreview = Encoding.ASCII.GetString(buffer); string extractedText = ExtractAsciiStrings(asciiPreview, 4); var hexDump = new List(); for (int i = 0; i < buffer.Length; i += 16) { string line = $"{(offset + i):X8} "; for (int j = 0; j < 16; j++) { if (i + j < buffer.Length) line += $"{buffer[i + j]:X2} "; else line += " "; } hexDump.Add(line.TrimEnd()); } Logger.Info($"[NSCRIPT_CURE] Threat ID: {threatId}, Size: {size} bytes"); if (!string.IsNullOrWhiteSpace(extractedText)) Logger.Info(" > Embedded text: " + extractedText); Logger.Info(" > Hex:\n" + string.Join(Environment.NewLine, hexDump)); var hexExport = new List(); for (int i = 0; i < buffer.Length; i += 16) { string line = ""; for (int j = 0; j < 16 && i + j < buffer.Length; j++) line += $"{buffer[i + j]:X2} "; hexExport.Add(line.TrimEnd()); } if (ThreatDatabase.TryGetThreat(threatId, out var threat)) { var pattern = new List(); if (!string.IsNullOrWhiteSpace(extractedText)) pattern.Add(extractedText); pattern.AddRange(hexExport); threat.Signatures.Add(new SignatureEntry { Type = "SIGNATURE_TYPE_NSCRIPT_CURE", Offset = offset, Pattern = pattern, Parsed = false, ConditionType = "PRESENT", ConditionValue = 1 }); } } catch (Exception ex) { Logger.Error($"[!] NSCRIPT_CURE Error parsing at offset 0x{offset:X}: {ex.Message}"); } finally { reader.BaseStream.Seek(offset + size, SeekOrigin.Begin); } } private string ExtractAsciiStrings(string input, int minLen) { var output = new StringBuilder(); var buffer = new StringBuilder(); foreach (char c in input) { if (c >= 32 && c <= 126) { buffer.Append(c); } else { if (buffer.Length >= minLen) { output.AppendLine(buffer.ToString()); } buffer.Clear(); } } if (buffer.Length >= minLen) { output.AppendLine(buffer.ToString()); } return output.ToString().Trim(); } } }