// DefenderRuleParser // Author: Andrea Cristaldi 2025 - https://github.com/andreacristaldi/DefenderRuleParser // This project is licensed under the Apache 2.0 License. using System; using System.Diagnostics; using System.IO; using DefenderRuleParser2.Models; namespace DefenderRuleParser2 { public static class SignatureReader { public static void ExtractSignatures(BinaryReader reader, string filePath) { long fileLength = reader.BaseStream.Length; uint currentThreatId = 0; while (reader.BaseStream.Position < fileLength) { long position = reader.BaseStream.Position; try { byte typeByte = reader.ReadByte(); byte sizeLow = reader.ReadByte(); ushort sizeHigh = reader.ReadUInt16(); int size = sizeLow + (sizeHigh << 8); string sigType = SignatureTypeMapper.GetSignatureType(typeByte); long endPosition = reader.BaseStream.Position + size; //debug long signatureStart = position; long dataStart = reader.BaseStream.Position; byte[] signatureData = reader.ReadBytes(size); byte sizeHighLo = (byte)(sizeHigh & 0xFF); byte sizeHighHi = (byte)((sizeHigh >> 8) & 0xFF); Logger.Verbose($"\n[HDR] type=0x{typeByte:X2} ({typeByte}) sizeLow=0x{sizeLow:X2} sizeHigh=0x{sizeHigh:X4} -> size={size}"); Logger.Verbose($"[HDR-HEX] @0x{position:X}: {typeByte:X2} {sizeLow:X2} {sizeHighLo:X2} {sizeHighHi:X2}"); Logger.HexDumpVerbose($"[DBG] Signature at 0x{signatureStart:X} ({sigType}) - Size: {size} bytes", signatureData, signatureStart + (dataStart - signatureStart)); reader.BaseStream.Seek(dataStart, SeekOrigin.Begin); Console.WriteLine($"[>] Found signature: {sigType} @0x{position:X}, Size: {size}"); if (sigType == "SIGNATURE_TYPE_THREAT_BEGIN") { // payload THREAT_BEGIN currentThreatId = reader.ReadUInt32(); // primi 4 byte = ThreatID var threat = ThreatDatabase.CreateOrUpdateThreat(currentThreatId, position); Logger.Info($"[+] Threat Begin: ID={currentThreatId} Name='{threat.ThreatName}'"); // Se il record ha metadati extra oltre ai 4 byte dell’ID, saltali ora: long consumed = reader.BaseStream.Position - (position + 4); // normalmente 0 long remainingInThisRecord = endPosition - reader.BaseStream.Position; if (remainingInThisRecord > 0) { // opzionale: fai un dump per capire che c’è dentro // byte[] meta = reader.ReadBytes((int)remainingInThisRecord); // HexDumper.Print("[DBG] ThreatBegin extra", meta, reader.BaseStream.Position - meta.Length); reader.BaseStream.Seek(remainingInThisRecord, SeekOrigin.Current); } // Fine: il prossimo ReadByte() del while esterno vedrà il type del record successivo } else if (sigType == "SIGNATURE_TYPE_THREAT_END") { uint endThreatId = reader.ReadUInt32(); if (ThreatDatabase.TryUpdateThreatEnd(endThreatId, endPosition)) Logger.Info($"[✓] Threat End: ID={endThreatId} @0x{endPosition:X}"); // Se esistono extra (di solito no), salta comunque al termine del record long left = endPosition - reader.BaseStream.Position; if (left > 0) reader.BaseStream.Seek(left, SeekOrigin.Current); } else if (sigType != "SIGNATURE_TYPE_UNKNOWN") { SignatureDispatcher.Dispatch(sigType, reader, size, currentThreatId); } // Allineamento sicuro if (reader.BaseStream.Position < endPosition) { long remaining = endPosition - reader.BaseStream.Position; Logger.Warn($"[~] Skipping {remaining} byte(s) to align with next signature..."); reader.BaseStream.Seek(remaining, SeekOrigin.Current); } Debug.Assert(reader.BaseStream.Position == endPosition, $"[ASSERT] Parser per {sigType} ha letto {reader.BaseStream.Position - position} byte, " + $"previsti {endPosition - position}"); } catch (EndOfStreamException) { Logger.Warn("[!] Reached unexpected end of stream."); break; } catch (Exception ex) { Logger.Error($"[!] Exception at 0x{position:X}: {ex.Message}"); break; } } } } }