// DefenderRuleParser // Author: Andrea Cristaldi 2025 - https://github.com/andreacristaldi/DefenderRuleParser // This project is licensed under the Apache 2.0 License. using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; namespace DefenderRuleParser2 { internal class Program { static void Main(string[] args) { Logger.Info("DefenderRuleParser\nhttps://github.com/andreacristaldi/DefenderRuleParser\n\n"); if (args.Length < 1) { Logger.Info("Usage:"); Logger.Info(" DefenderRuleParser [--recursive] [--skip-existing] [--debug] [--debug-hex] [--quiet]"); Logger.Info(""); Logger.Info("Options:"); Logger.Info(" --recursive Process folders recursively"); //Logger.Info(" --skip-existing Skip .json if already present"); Logger.Info(" --debug Enable verbose logs"); //Logger.Info(" --quiet Suppress console logs (modules can still check Logger flags)"); return; } string inputPath = args[0]; bool recursive = args.Contains("--recursive", StringComparer.OrdinalIgnoreCase); bool skipExisting = args.Contains("--skip-existing", StringComparer.OrdinalIgnoreCase); bool debug = args.Contains("--debug", StringComparer.OrdinalIgnoreCase); bool quiet = args.Contains("--quiet", StringComparer.OrdinalIgnoreCase); Logger.DebugEnabled = debug; Logger.Verbose($"[cfg] recursive={recursive} skipExisting={skipExisting} debug={debug} quiet={quiet}"); Logger.Info("[+] Loading threat dictionary from 'defender.csv'..."); string filePath = "defender.csv"; if (!File.Exists(filePath)) { Logger.Warn("Threat dictionary not found. Attempting to retrieve using PowerShell..."); try { var psi = new ProcessStartInfo() { FileName = "powershell.exe", Arguments = "Get-MpThreatCatalog | Export-Csv -Path ./defender.csv -NoTypeInformation", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true }; using (var process = new Process()) { process.StartInfo = psi; process.Start(); string output = process.StandardOutput.ReadToEnd(); string error = process.StandardError.ReadToEnd(); process.WaitForExit(); if (process.ExitCode != 0 || !File.Exists(filePath)) { Logger.Error("PowerShell execution failed or defender.csv not created."); Logger.Verbose(error); Logger.Info("Ensure PowerShell is available, Windows Defender is installed, and you have sufficient permissions."); return; } Logger.Info("Threat catalog successfully retrieved."); } } catch (Exception ex) { Logger.Error("Error executing PowerShell: " + ex.Message); Logger.Info("Make sure PowerShell is installed and accessible, and that script execution is not restricted."); return; } } ThreatDatabase.Load(filePath); var binFiles = new List(); if (File.Exists(inputPath) && inputPath.EndsWith(".bin", StringComparison.OrdinalIgnoreCase)) { binFiles.Add(inputPath); } else if (Directory.Exists(inputPath)) { var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; var allBins = Directory.GetFiles(inputPath, "*.bin", searchOption); foreach (var bin in allBins) { string jsonPath = Path.ChangeExtension(bin, ".json"); if (skipExisting && File.Exists(jsonPath)) { Logger.Info($"[>] Skipping {Path.GetFileName(bin)} (JSON already exists)"); continue; } binFiles.Add(bin); } } else { Logger.Error("[!] Invalid file or folder path."); return; } foreach (string binPath in binFiles) { Logger.Info($"\n[+] Processing: {binPath}"); Logger.OutputFolder = Path.GetFullPath(binPath); try { using (var fs = new FileStream(binPath, FileMode.Open, FileAccess.Read)) using (var reader = new BinaryReader(fs)) { SignatureReader.ExtractSignatures(reader, binPath); } string outputJson = Path.Combine( Path.GetDirectoryName(binPath), Path.GetFileNameWithoutExtension(binPath) + ".json" ); //Exporter.SaveAllThreats(Path.GetDirectoryName(outputJson), Path.GetFileNameWithoutExtension(outputJson)); //Logger.Info($"[V] Exported: {outputJson}"); //File.Delete(binPath); } catch (Exception ex) { Logger.Error($"[!] Failed to process {binPath}: {ex.Message}"); } } Logger.Info("\n[V] Parsing completed. Press any key to exit."); Console.ReadKey(); } } }