// DefenderRuleParser // Author: Andrea Cristaldi 2025 - https://github.com/andreacristaldi/DefenderRuleParser // This project is licensed under the Apache 2.0 License. /* * Summary: Minimal/default handler for unknown or trivial records. * Origin: dump-driven; acts as a conservative sink when structure is unclear. * Role: Logs hex safely without interpretation drift. */ using System; using System.Collections.Generic; using System.IO; using System.Text; using DefenderRuleParser2.Models; namespace DefenderRuleParser2.Parsers { public class DefaultsParser : ISignatureParser { public void Parse(BinaryReader reader, int size, uint threatId) { long offset = reader.BaseStream.Position; try { byte[] raw = reader.ReadBytes(size); string hexDump = BitConverter.ToString(raw).Replace("-", " "); string ascii = Encoding.UTF8.GetString(raw).Trim('\0'); List unicodeStrings = new List(); for (int i = 0; i < raw.Length - 1; i += 2) { int start = i; var sb = new StringBuilder(); while (i + 1 < raw.Length) { ushort codeUnit = BitConverter.ToUInt16(raw, i); if (codeUnit == 0x0000) { if (sb.Length >= 2) unicodeStrings.Add(sb.ToString()); break; } if (codeUnit < 32 || codeUnit > 126) break; sb.Append((char)codeUnit); i += 2; } } Logger.Info($"[DEFAULTS] Threat ID: {threatId}, Size: {size} bytes"); if (unicodeStrings.Count > 0) { foreach (var s in unicodeStrings) Logger.Info($" > UTF-16LE String: {s}"); } if (ThreatDatabase.TryGetThreat(threatId, out var threat)) { var patterns = new List { ascii, hexDump }; patterns.AddRange(unicodeStrings); threat.Signatures.Add(new SignatureEntry { Type = "SIGNATURE_TYPE_DEFAULTS", Offset = offset, Pattern = patterns, Parsed = false, ConditionType = "PRESENT", ConditionValue = 1 }); } } catch (Exception ex) { Logger.Error($"[!] DEFAULTS Error parsing at offset 0x{offset:X}: {ex.Message}"); } finally { reader.BaseStream.Seek(offset + size, SeekOrigin.Begin); } } } }