Files
Andrea Cristaldi 4a7e9812f3 Update Program.cs
2025-08-27 12:04:59 +02:00

1229 lines
42 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// DefenderRules
// Author: Andrea Cristaldi 2025 - https://github.com/andreacristaldi/DefenderRules
// This project is licensed under the MIT License. The licence does not extend to data generated/derived from Defender definitions.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using System.Text.RegularExpressions;
public class DefenderRules
{
public struct STRUCT_SIG_TYPE_THREAT_BEGIN
{
public byte ui8SignatureType;
public byte ui8SizeLow;
public ushort ui16SizeHigh;
public uint ui32SignatureId;
public byte[] unknownBytes1;
public byte ui8SizeThreatName;
public byte[] unknownBytes2;
public string lpszThreatName;
public byte[] unknownBytes3;
}
public struct STRUCT_SIG_TYPE_THREAT_END
{
public byte ui8SignatureType;
public byte ui8SizeLow;
public ushort ui16SizeHigh;
public byte[] pbRuleContent;
}
public class Threat
{
public string ThreatName { get; set; }
public long BeginPosition { get; set; }
public long EndPosition { get; set; }
public Dictionary<string, long> SignatureStats { get; set; } = new Dictionary<string, long>();
}
private static readonly Dictionary<uint, Threat> Threats = new Dictionary<uint, Threat>();
private static readonly Dictionary<string, string> ThreatDictionary = new Dictionary<string, string>
{
};
public static void Main(string[] args)
{
string filePath = "";
string outputDirectory = "";
Console.WriteLine("DefenderRules\nhttps://github.com/andreacristaldi/DefenderRules\n\n");
if (args.Length != 2)
{
Console.WriteLine("Usage: DefenderRules <FilePath> <OutputDirectory>");
return;
}
filePath = args[0];
outputDirectory = args[1];
if (!File.Exists(filePath))
{
Console.WriteLine($"{filePath} does not exist.");
return;
}
ReadCSV();
ExtractThreatSignatures(filePath, outputDirectory);
}
public static void ExtractThreatSignatures(string filePath, string outputDirectory)
{
Console.WriteLine("You are exporting raw signature chunks(.bin). These are derived from Microsofts proprietary definitions and are for local use only.Do not publish or share these files.");
Console.WriteLine("Searching...");
uint ui32SignatureId = 0;
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
using (BinaryReader reader = new BinaryReader(fs))
{
while (reader.BaseStream.Position != reader.BaseStream.Length)
{
try
{
long beginPosition = reader.BaseStream.Position;
string Signaturetype = GetSignatureType(reader.ReadByte());
if (Signaturetype == "SIGNATURE_TYPE_THREAT_BEGIN")
{
byte ui8SizeLow = reader.ReadByte();
ushort ui16SizeHigh = reader.ReadUInt16();
int Size = ui8SizeLow | (ui16SizeHigh << 8);
long endPosition = reader.BaseStream.Position + Size;
ui32SignatureId = reader.ReadUInt32();
if (ThreatDictionary.ContainsKey(ui32SignatureId.ToString()))
{
byte[] unknownBytes1 = reader.ReadBytes(6);
byte ui8SizeThreatName = reader.ReadByte();
byte[] unknownBytes2 = reader.ReadBytes(1);
string lpszThreatName = Encoding.ASCII.GetString(reader.ReadBytes(ui8SizeThreatName));
byte[] unknownBytes3 = reader.ReadBytes(9);
if (!Threats.ContainsKey(ui32SignatureId))
{
Threats[ui32SignatureId] = new Threat
{
ThreatName = ThreatDictionary[ui32SignatureId.ToString()],
BeginPosition = beginPosition
};
Console.Write(".");
}
}
else
{
}
reader.BaseStream.Position = endPosition;
}
else if (Signaturetype == "SIGNATURE_TYPE_THREAT_END")
{
byte ui8SizeLow = reader.ReadByte();
ushort ui16SizeHigh = reader.ReadUInt16();
int Size = ui8SizeLow | (ui16SizeHigh << 8);
long endPosition = reader.BaseStream.Position + Size;
byte[] pbRuleContent = reader.ReadBytes(4);
uint pbRuleContentId = BitConverter.ToUInt32(pbRuleContent, 0);
string signatureIdStr = pbRuleContentId.ToString();
if (Threats.ContainsKey(pbRuleContentId))
{
if (Threats[pbRuleContentId].EndPosition == 0)
{
Threats[pbRuleContentId].EndPosition = endPosition;
}
}
reader.BaseStream.Position = endPosition;
ui32SignatureId = 0;
}
else if (Signaturetype != "SIGNATURE_TYPE_UNKNOWN")
{
byte ui8SizeLow = reader.ReadByte();
ushort ui16SizeHigh = reader.ReadUInt16();
int Size = ui8SizeLow | (ui16SizeHigh << 8);
long endPosition = reader.BaseStream.Position + Size;
if (Threats.ContainsKey(ui32SignatureId))
{
if (!Threats[ui32SignatureId].SignatureStats.ContainsKey(Signaturetype))
{
Threats[ui32SignatureId].SignatureStats[Signaturetype] = 1;
}
else
{
Threats[ui32SignatureId].SignatureStats[Signaturetype]++;
}
}
reader.BaseStream.Position = endPosition;
}
else
{
reader.BaseStream.Position = reader.BaseStream.Position + 1;
}
}
catch (EndOfStreamException)
{
break;
}
}
}
}
Console.WriteLine("\n\nThreats:");
Console.WriteLine(Threats.Count);
Console.WriteLine("\n\nSaving logs...");
SaveThreatsToFile(Threats, outputDirectory + "\\" + "output.txt");
SaveMissingThreatsToFile(Threats, ThreatDictionary, outputDirectory + "\\" + "missing.txt");
Console.WriteLine("\n\nSaving stats...");
SaveStats(outputDirectory);
Console.WriteLine("\n\nSaving signatures to output path...");
foreach (var threatEntry in Threats)
{
uint key = threatEntry.Key;
Threat threat = threatEntry.Value;
SaveRuleContent(filePath, threat.BeginPosition, threat.EndPosition, outputDirectory + "\\" + threat.ThreatName.Replace("/", "_").Replace(":", "_") + ".bin");
Console.Write(".");
}
}
public static void SaveStats(string outputDirectory)
{
var allKeys = Threats.Values.SelectMany(t => t.SignatureStats.Keys).Distinct().OrderBy(k => k).ToList();
using (var writer = new StreamWriter(outputDirectory + "\\ThreatsStats.csv"))
{
writer.Write("ThreatName");
foreach (var key in allKeys)
{
writer.Write($",{key}");
}
writer.WriteLine();
foreach (var threat in Threats.Values)
{
writer.Write(threat.ThreatName);
foreach (var key in allKeys)
{
writer.Write(",");
if (threat.SignatureStats.ContainsKey(key))
{
writer.Write(threat.SignatureStats[key]);
}
else
{
writer.Write("0");
}
}
writer.WriteLine();
}
}
var globalSums = new Dictionary<string, long>();
foreach (var key in allKeys)
{
globalSums[key] = Threats.Values.Sum(t => t.SignatureStats.ContainsKey(key) ? t.SignatureStats[key] : 0);
}
using (var writer = new StreamWriter(outputDirectory + "\\ThreatsGlobalStats.csv"))
{
writer.WriteLine(string.Join(",", allKeys));
writer.WriteLine(string.Join(",", allKeys.Select(key => globalSums[key])));
}
var top30GlobalSums = globalSums.OrderByDescending(kvp => kvp.Value).Take(30).ToList();
var headers = top30GlobalSums.Select(kvp => kvp.Key).ToList();
var values = top30GlobalSums.Select(kvp => kvp.Value).ToList();
string strHeaders = "[";
foreach (var el in headers)
{
strHeaders = strHeaders + "'" + el + "',";
}
strHeaders = strHeaders.Substring(0, strHeaders.Length - 1) + "]";
string strValues = "[";
foreach (var el in values)
{
strValues = strValues + el + ",";
}
strValues = strValues.Substring(0, strValues.Length - 1) + "]";
var htmlContent = $@"
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<title>DefenderRules Charts</title>
<script src='https://cdn.jsdelivr.net/npm/chart.js'></script>
<style>
body {{
font-family: Arial, sans-serif;
margin: 20px;
}}
canvas {{
margin-top: 20px;
}}
</style>
</head>
<body>
<h1>DefenderRules - Top 30 Global Threats Signatures Stats Chart</h1>
<canvas id='globalSumsChart'></canvas>
<script>
document.addEventListener('DOMContentLoaded', function() {{
const headers = {strHeaders};
const values = {strValues};
function createGlobalSumsChart(headers, values) {{
const ctx = document.getElementById('globalSumsChart').getContext('2d');
new Chart(ctx, {{
type: 'bar',
data: {{
labels: headers,
datasets: [{{
label: 'Global Sums',
data: values,
backgroundColor: getRandomColor()
}}]
}},
options: {{
responsive: true,
scales: {{
y: {{
beginAtZero: true
}}
}}
}}
}});
}}
function getRandomColor() {{
const r = Math.floor(Math.random() * 255);
const g = Math.floor(Math.random() * 255);
const b = Math.floor(Math.random() * 255);
return `rgba(${{r}}, ${{g}}, ${{b}}, 0.6)`;
}}
createGlobalSumsChart(headers, values);
}});
</script>
</body>
</html>";
File.WriteAllText(outputDirectory + "\\Top30GlobalStatsChart.html", htmlContent);
var groupedThreats = Threats.Values.GroupBy(t => t.ThreatName.Split(':')[0])
.OrderBy(g => g.Key)
.ToDictionary(g => g.Key, g => g.ToList());
var groupedSums = new Dictionary<string, Dictionary<string, long>>();
foreach (var group in groupedThreats)
{
var groupName = group.Key;
var signatureStatsSums = new Dictionary<string, long>();
foreach (var threat in group.Value)
{
foreach (var stat in threat.SignatureStats)
{
if (!signatureStatsSums.ContainsKey(stat.Key))
{
signatureStatsSums[stat.Key] = 0;
}
signatureStatsSums[stat.Key] += stat.Value;
}
}
groupedSums[groupName] = signatureStatsSums.OrderByDescending(kvp => kvp.Value)
.Take(10)
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
var htmlContent2 = new StringBuilder();
htmlContent2.AppendLine(@"
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
<title>DefenderRules Charts</title>
<script src='https://cdn.jsdelivr.net/npm/chart.js'></script>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
canvas {
margin-top: 20px;
}
</style>
</head>
<body>
<h1>DefenderRules - Threat Groups Top 10 Signatures Stats Chart</h1>");
foreach (var group in groupedSums)
{
var headers2 = group.Value.Keys.ToList();
var values2 = group.Value.Values.ToList();
var groupName = group.Key;
string strHeaders2 = "[";
foreach (var el in headers2)
{
strHeaders2 = strHeaders2 + "'" + el + "',";
}
strHeaders2 = strHeaders2.Substring(0, strHeaders2.Length - 1) + "]";
string strValues2 = "[";
foreach (var el in values2)
{
strValues2 = strValues2 + el + ",";
}
strValues2 = strValues2.Substring(0, strValues2.Length - 1) + "]";
htmlContent2.AppendLine($@"
<h2>{groupName}</h2>
<canvas id='{groupName}Chart'></canvas>
<script>
document.addEventListener('DOMContentLoaded', function() {{
const headers = {strHeaders2};
const values = {strValues2};
function createChart(ctx, headers, values) {{
new Chart(ctx, {{
type: 'bar',
data: {{
labels: headers,
datasets: [{{
label: '{groupName} Sums',
data: values,
backgroundColor: getRandomColor()
}}]
}},
options: {{
responsive: true,
scales: {{
y: {{
beginAtZero: true
}}
}}
}}
}});
}}
function getRandomColor() {{
const r = Math.floor(Math.random() * 255);
const g = Math.floor(Math.random() * 255);
const b = Math.floor(Math.random() * 255);
return `rgba(${{r}}, ${{g}}, ${{b}}, 0.6)`;
}}
const ctx = document.getElementById('{groupName}Chart').getContext('2d');
createChart(ctx, headers, values);
}});
</script>");
}
htmlContent2.AppendLine(@"
</body>
</html>");
File.WriteAllText(outputDirectory + "\\ThreatGroupStatsCharts.html", htmlContent2.ToString());
}
static string GetSignatureType(uint a1)
{
if (a1 <= 0x9D)
{
if (a1 == 157)
return "SIGNATURE_TYPE_THREAD_X86";
if (a1 > 0x6A)
{
if (a1 > 0x86)
{
if (a1 > 0x90)
{
switch (a1)
{
case 0x91:
return "SIGNATURE_TYPE_VDLL_IA64";
case 0x95:
return "SIGNATURE_TYPE_PEBMPAT";
case 0x96:
return "SIGNATURE_TYPE_AAGGREGATOR";
case 0x97:
return "SIGNATURE_TYPE_SAMPLE_REQUEST_BY_NAME";
case 0x98:
return "SIGNATURE_TYPE_REMOVAL_POLICY_BY_NAME";
case 0x99:
return "SIGNATURE_TYPE_TUNNEL_X86";
case 0x9A:
return "SIGNATURE_TYPE_TUNNEL_X64";
case 0x9B:
return "SIGNATURE_TYPE_TUNNEL_IA64";
case 0x9C:
return "SIGNATURE_TYPE_VDLL_ARM";
}
}
else
{
switch (a1)
{
case 0x90:
return "SIGNATURE_TYPE_TARGET_SCRIPT_PCODE";
case 0x87:
return "SIGNATURE_TYPE_PESTATIC";
case 0x88:
return "SIGNATURE_TYPE_UFSP_DISABLE";
case 0x89:
return "SIGNATURE_TYPE_FOPEX";
case 0x8A:
return "SIGNATURE_TYPE_PEPCODE";
case 0x8B:
return "SIGNATURE_TYPE_IL_PATTERN";
case 0x8C:
return "SIGNATURE_TYPE_ELFHSTR_EXT";
case 0x8D:
return "SIGNATURE_TYPE_MACHOHSTR_EXT";
case 0x8E:
return "SIGNATURE_TYPE_DOSHSTR_EXT";
case 0x8F:
return "SIGNATURE_TYPE_MACROHSTR_EXT";
}
}
}
else
{
if (a1 == 134)
return "SIGNATURE_TYPE_PEMAIN_LOCATOR";
if (a1 > 0x79)
{
switch (a1)
{
case 0x7A:
return "SIGNATURE_TYPE_VERSIONCHECK";
case 0x7B:
return "SIGNATURE_TYPE_SAMPLE_REQUEST";
case 0x7C:
return "SIGNATURE_TYPE_VDLL_X64";
case 0x7E:
return "SIGNATURE_TYPE_SNID";
case 0x7F:
return "SIGNATURE_TYPE_FOP";
case 0x80:
return "SIGNATURE_TYPE_KCRCE";
case 0x83:
return "SIGNATURE_TYPE_VFILE";
case 0x84:
return "SIGNATURE_TYPE_SIGFLAGS";
case 0x85:
return "SIGNATURE_TYPE_PEHSTR_EXT2";
}
}
else
{
switch (a1)
{
case 'y':
return "SIGNATURE_TYPE_VDLL_X86";
case 'k':
return "SIGNATURE_TYPE_WVT_EXCEPTION";
case 'l':
return "SIGNATURE_TYPE_REVOKED_CERTIFICATE";
case 'p':
return "SIGNATURE_TYPE_TRUSTED_PUBLISHER";
case 'q':
return "SIGNATURE_TYPE_ASEP_FILEPATH";
case 's':
return "SIGNATURE_TYPE_DELTA_BLOB";
case 't':
return "SIGNATURE_TYPE_DELTA_BLOB_RECINFO";
case 'u':
return "SIGNATURE_TYPE_ASEP_FOLDERNAME";
case 'w':
return "SIGNATURE_TYPE_PATTMATCH_V2";
case 'x':
return "SIGNATURE_TYPE_PEHSTR_EXT";
}
}
}
}
else
{
if (a1 == 106)
return "SIGNATURE_TYPE_REMOVAL_POLICY";
if (a1 > 0x4A)
{
if (a1 > 0x5D)
{
switch (a1)
{
case '^':
return "SIGNATURE_TYPE_FILENAME";
case '_':
return "SIGNATURE_TYPE_FILEPATH";
case '`':
return "SIGNATURE_TYPE_FOLDERNAME";
case 'a':
return "SIGNATURE_TYPE_PEHSTR";
case 'b':
return "SIGNATURE_TYPE_LOCALHASH";
case 'c':
return "SIGNATURE_TYPE_REGKEY";
case 'd':
return "SIGNATURE_TYPE_HOSTSENTRY";
case 'g':
return "SIGNATURE_TYPE_STATIC";
case 'i':
return "SIGNATURE_TYPE_LATENT_THREAT";
}
}
else
{
switch (a1)
{
case ']':
return "SIGNATURE_TYPE_THREAT_END";
case 'P':
return "SIGNATURE_TYPE_CKSIMPLEREC";
case 'Q':
return "SIGNATURE_TYPE_PATTMATCH";
case 'S':
return "SIGNATURE_TYPE_RPFROUTINE";
case 'U':
return "SIGNATURE_TYPE_NID";
case 'V':
return "SIGNATURE_TYPE_GENSFX";
case 'W':
return "SIGNATURE_TYPE_UNPLIB";
case 'X':
return "SIGNATURE_TYPE_DEFAULTS";
case '[':
return "SIGNATURE_TYPE_DBVAR";
case '\\':
return "SIGNATURE_TYPE_THREAT_BEGIN";
}
}
}
else
{
if (a1 == 74)
return "SIGNATURE_TYPE_TARGET_SCRIPT";
if (a1 > 0x2C)
{
switch (a1)
{
case '0':
return "SIGNATURE_TYPE_TITANFLT";
case '=':
return "SIGNATURE_TYPE_PEFILE_CURE";
case '>':
return "SIGNATURE_TYPE_MAC_CURE";
case '@':
return "SIGNATURE_TYPE_SIGTREE";
case 'A':
return "SIGNATURE_TYPE_SIGTREE_EXT";
case 'B':
return "SIGNATURE_TYPE_MACRO_PCODE";
case 'C':
return "SIGNATURE_TYPE_MACRO_SOURCE";
case 'D':
return "SIGNATURE_TYPE_BOOT";
case 'I':
return "SIGNATURE_TYPE_CLEANSCRIPT";
}
}
else
{
switch (a1)
{
case 0x2C:
return "SIGNATURE_TYPE_NSCRIPT_CURE";
case 1:
return "SIGNATURE_TYPE_RESERVED";
case 2:
return "SIGNATURE_TYPE_VOLATILE_THREAT_INFO";
case 3:
return "SIGNATURE_TYPE_VOLATILE_THREAT_ID";
case 0x11:
return "SIGNATURE_TYPE_CKOLDREC";
case 0x20:
return "SIGNATURE_TYPE_KVIR32";
case 0x21:
return "SIGNATURE_TYPE_POLYVIR32";
case 0x27:
return "SIGNATURE_TYPE_NSCRIPT_NORMAL";
case 0x28:
return "SIGNATURE_TYPE_NSCRIPT_SP";
case 0x29:
return "SIGNATURE_TYPE_NSCRIPT_BRUTE";
}
}
}
}
return "SIGNATURE_TYPE_UNKNOWN";
}
if (a1 <= 0xC6)
{
if (a1 == 198)
return "SIGNATURE_TYPE_MSILFOPEX";
if (a1 > 0xB1)
{
if (a1 > 0xBC)
{
switch (a1)
{
case 0xBD:
return "SIGNATURE_TYPE_LUASTANDALONE";
case 0xBE:
return "SIGNATURE_TYPE_DEXHSTR_EXT";
case 0xBF:
return "SIGNATURE_TYPE_JAVAHSTR_EXT";
case 0xC0:
return "SIGNATURE_TYPE_MAGICCODE";
case 0xC1:
return "SIGNATURE_TYPE_CLEANSTORE_RULE";
case 0xC2:
return "SIGNATURE_TYPE_VDLL_CHECKSUM";
case 0xC3:
return "SIGNATURE_TYPE_THREAT_UPDATE_STATUS";
case 0xC4:
return "SIGNATURE_TYPE_VDLL_MSIL";
case 0xC5:
return "SIGNATURE_TYPE_ARHSTR_EXT";
}
}
else
{
switch (a1)
{
case 0xBC:
return "SIGNATURE_TYPE_KPATEX";
case 0xB2:
return "SIGNATURE_TYPE_VFILEEX";
case 0xB3:
return "SIGNATURE_TYPE_SIGTREE_BM";
case 0xB4:
return "SIGNATURE_TYPE_VBFOP";
case 0xB5:
return "SIGNATURE_TYPE_VDLL_META";
case 0xB6:
return "SIGNATURE_TYPE_TUNNEL_ARM";
case 0xB7:
return "SIGNATURE_TYPE_THREAD_ARM";
case 0xB8:
return "SIGNATURE_TYPE_PCODEVALIDATOR";
case 0xBA:
return "SIGNATURE_TYPE_MSILFOP";
case 0xBB:
return "SIGNATURE_TYPE_KPAT";
}
}
}
else
{
if (a1 == 177)
return "SIGNATURE_TYPE_NISBLOB";
if (a1 > 0xA7)
{
switch (a1)
{
case 0xA8:
return "SIGNATURE_TYPE_BM_INFO";
case 0xA9:
return "SIGNATURE_TYPE_NDAT";
case 0xAA:
return "SIGNATURE_TYPE_FASTPATH_DATA";
case 0xAB:
return "SIGNATURE_TYPE_FASTPATH_SDN";
case 0xAC:
return "SIGNATURE_TYPE_DATABASE_CERT";
case 0xAD:
return "SIGNATURE_TYPE_SOURCE_INFO";
case 0xAE:
return "SIGNATURE_TYPE_HIDDEN_FILE";
case 0xAF:
return "SIGNATURE_TYPE_COMMON_CODE";
case 0xB0:
return "SIGNATURE_TYPE_VREG";
}
}
else
{
switch (a1)
{
case 0xA7:
return "SIGNATURE_TYPE_BM_STATIC";
case 0x9E:
return "SIGNATURE_TYPE_THREAD_X64";
case 0x9F:
return "SIGNATURE_TYPE_THREAD_IA64";
case 0xA0:
return "SIGNATURE_TYPE_FRIENDLYFILE_SHA256";
case 0xA1:
return "SIGNATURE_TYPE_FRIENDLYFILE_SHA512";
case 0xA2:
return "SIGNATURE_TYPE_SHARED_THREAT";
case 0xA3:
return "SIGNATURE_TYPE_VDM_METADATA";
case 0xA4:
return "SIGNATURE_TYPE_VSTORE";
case 0xA5:
return "SIGNATURE_TYPE_VDLL_SYMINFO";
case 0xA6:
return "SIGNATURE_TYPE_IL2_PATTERN";
}
}
}
return "SIGNATURE_TYPE_UNKNOWN";
}
if (a1 <= 0xDA)
{
if (a1 == 218)
return "SIGNATURE_TYPE_FASTPATH_SDN_EX";
if (a1 > 0xD0)
{
switch (a1)
{
case 0xD1:
return "SIGNATURE_TYPE_SWFHSTR_EXT";
case 0xD2:
return "SIGNATURE_TYPE_REWSIGS";
case 0xD3:
return "SIGNATURE_TYPE_AUTOITHSTR_EXT";
case 0xD4:
return "SIGNATURE_TYPE_INNOHSTR_EXT";
case 0xD5:
return "SIGNATURE_TYPE_CERT_STORE_ENTRY";
case 0xD6:
return "SIGNATURE_TYPE_EXPLICITRESOURCE";
case 0xD7:
return "SIGNATURE_TYPE_CMDHSTR_EXT";
case 0xD8:
return "SIGNATURE_TYPE_FASTPATH_TDN";
case 0xD9:
return "SIGNATURE_TYPE_EXPLICITRESOURCEHASH";
}
}
else
{
switch (a1)
{
case 0xD0:
return "SIGNATURE_TYPE_BRUTE";
case 0xC7:
return "SIGNATURE_TYPE_VBFOPEX";
case 0xC8:
return "SIGNATURE_TYPE_FOP64";
case 0xC9:
return "SIGNATURE_TYPE_FOPEX64";
case 0xCA:
return "SIGNATURE_TYPE_JSINIT";
case 0xCB:
return "SIGNATURE_TYPE_PESTATICEX";
case 0xCC:
return "SIGNATURE_TYPE_KCRCEX";
case 0xCD:
return "SIGNATURE_TYPE_FTRIE_POS";
case 0xCE:
return "SIGNATURE_TYPE_NID64";
case 0xCF:
return "SIGNATURE_TYPE_MACRO_PCODE64";
}
}
return "SIGNATURE_TYPE_UNKNOWN";
}
if (a1 <= 0xE5)
{
switch (a1)
{
case 0xE5:
return "SIGNATURE_TYPE_SNIDEX";
case 0xDB:
return "SIGNATURE_TYPE_BLOOM_FILTER";
case 0xDC:
return "SIGNATURE_TYPE_RESEARCH_TAG";
case 0xDE:
return "SIGNATURE_TYPE_ENVELOPE";
case 0xDF:
return "SIGNATURE_TYPE_REMOVAL_POLICY64";
case 0xE0:
return "SIGNATURE_TYPE_REMOVAL_POLICY64_BY_NAME";
case 0xE1:
return "SIGNATURE_TYPE_VDLL_META_X64";
case 0xE2:
return "SIGNATURE_TYPE_VDLL_META_ARM";
case 0xE3:
return "SIGNATURE_TYPE_VDLL_META_MSIL";
case 0xE4:
return "SIGNATURE_TYPE_MDBHSTR_EXT";
}
return "SIGNATURE_TYPE_UNKNOWN";
}
switch (a1)
{
case 0xE6:
return "SIGNATURE_TYPE_SNIDEX2";
case 0xE7:
return "SIGNATURE_TYPE_AAGGREGATOREX";
case 0xE8:
return "SIGNATURE_TYPE_PUA_APPMAP";
case 0xE9:
return "SIGNATURE_TYPE_PROPERTY_BAG";
case 0xEA:
return "SIGNATURE_TYPE_DMGHSTR_EXT";
case 0xEB:
return "SIGNATURE_TYPE_DATABASE_CATALOG";
}
if (a1 != 236)
{
if (a1 == 237)
return "SIGNATURE_TYPE_BM_ENV_VAR_MAP";
return "SIGNATURE_TYPE_UNKNOWN";
}
return "SIGNATURE_TYPE_DATABASE_CERT2";
}
static void SaveThreatsToFile(Dictionary<uint, Threat> dictionary, string filePath)
{
using (StreamWriter writer = new StreamWriter(filePath))
{
foreach (var kvp in dictionary)
{
writer.WriteLine($"Key: {kvp.Key}, ThreatName: {kvp.Value.ThreatName}, BeginPosition: {kvp.Value.BeginPosition}, EndPosition: {kvp.Value.EndPosition}");
}
}
}
static void SaveMissingThreatsToFile(Dictionary<uint, Threat> threats, Dictionary<string, string> threatDictionary, string filePath)
{
using (StreamWriter writer = new StreamWriter(filePath))
{
foreach (var kvp in threatDictionary)
{
uint key;
if (uint.TryParse(kvp.Key, out key) && !threats.ContainsKey(key))
{
writer.WriteLine($"Key: {kvp.Key}, Description: {kvp.Value}");
}
}
}
}
public static void PrintRuleContent(string filePath, long beginPosition, long endPosition)
{
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
using (BinaryReader reader = new BinaryReader(fs))
{
reader.BaseStream.Seek(beginPosition, SeekOrigin.Begin);
byte[] content = reader.ReadBytes((int)(endPosition - beginPosition));
long position = beginPosition;
for (int i = 0; i < content.Length; i += 16)
{
Console.Write($"{position:X8} ");
for (int j = 0; j < 16; j++)
{
if (i + j < content.Length)
{
Console.Write($"{content[i + j]:X2} ");
}
else
{
Console.Write(" ");
}
}
Console.Write(" ");
for (int j = 0; j < 16; j++)
{
if (i + j < content.Length)
{
byte b = content[i + j];
if (b >= 32 && b <= 126)
{
Console.Write((char)b);
}
else
{
Console.Write('.');
}
}
else
{
Console.Write(' ');
}
}
Console.WriteLine();
position += 16;
}
Console.WriteLine("\n\n");
}
}
}
public static void ReadCSV()
{
string filePath = "defender.csv";
if (!File.Exists(filePath))
{
Console.WriteLine("Threat dictionary not found. Attempting to retrieve using PowerShell...");
try
{
ProcessStartInfo psi = new ProcessStartInfo()
{
FileName = "powershell.exe",
Arguments = "Get-MpThreatCatalog | Export-Csv -Path ./defender.csv -NoTypeInformation",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
};
using (Process 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))
{
Console.WriteLine("PowerShell execution failed or defender.csv not created.\n" + error);
Console.WriteLine("Ensure PowerShell is available, Windows Defender is installed, and you have sufficient permissions.");
return;
}
Console.WriteLine("Threat catalog successfully retrieved.");
}
}
catch (Exception ex)
{
Console.WriteLine("Error executing PowerShell: " + ex.Message);
Console.WriteLine("Make sure PowerShell is installed and accessible, and that script execution is not restricted.");
return;
}
}
if (!File.Exists(filePath))
{
Console.WriteLine("Warning: Threat name CSV dictionary (defender.csv) not found.");
Environment.Exit(1);
return;
}
string[] lines = File.ReadAllLines(filePath);
for (int i = 1; i < lines.Length; i++)
{
string[] fields = SplitCsvLine(lines[i]);
if (fields.Length >= 4)
{
string threatID = fields[2];
string threatName = fields[3];
if (!ThreatDictionary.ContainsKey(threatID))
{
ThreatDictionary.Add(threatID, threatName);
}
}
}
}
static string[] SplitCsvLine(string line)
{
List<string> result = new List<string>();
bool inQuotes = false;
string currentField = "";
foreach (char c in line)
{
if (c == '\"')
{
inQuotes = !inQuotes;
}
else if (c == ',' && !inQuotes)
{
result.Add(currentField);
currentField = "";
}
else
{
currentField += c;
}
}
if (currentField != "")
{
result.Add(currentField);
}
return result.ToArray();
}
public static void SaveRuleContent(string filePath, long beginPosition, long endPosition, string outputFilePath)
{
if (endPosition > beginPosition)
{
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
using (BinaryReader reader = new BinaryReader(fs))
{
reader.BaseStream.Seek(beginPosition, SeekOrigin.Begin);
byte[] content = reader.ReadBytes((int)(endPosition - beginPosition));
using (FileStream output = new FileStream(outputFilePath, FileMode.Create, FileAccess.Write))
{
output.Write(content, 0, content.Length);
}
}
}
}
}
}