Я хотел бы поделиться с вами интересным проектом, который мог бы быть полезным для анализа сигнатур от WD. Возможно, вы уже знакомы с ним - https://github.com/matterpreter/DefenderCheck.
После некоторого времени проведенного за изучением и разработкой, я создал асинхронную версию этого проекта, и я должен признать, что она работает гораздо быстрее. Теперь можно быстро обрабатывать большие объемы данных и искать сигнатуры, которые могут указывать на проблемы с WD. Просто скопируйте сигнатуру в hex-редакторе, используя код из проекта, и вы сможете найти и исправить проблему.
Для компиляции замените код на следующий:
Надеюсь, что этот проект будет полезным для вас, и я призываю вас воспользоваться им. Если у вас есть какие-либо вопросы или отзывы, буду рад услышать их.
Удачи и продуктивного анализа сигнатур!
После некоторого времени проведенного за изучением и разработкой, я создал асинхронную версию этого проекта, и я должен признать, что она работает гораздо быстрее. Теперь можно быстро обрабатывать большие объемы данных и искать сигнатуры, которые могут указывать на проблемы с WD. Просто скопируйте сигнатуру в hex-редакторе, используя код из проекта, и вы сможете найти и исправить проблему.
Для компиляции замените код на следующий:
C#:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace DefenderCheck
{
static class ProcessExtensions
{
public static Task WaitForExitAsync(this Process process, CancellationToken cancellationToken = default)
{
if (process == null)
throw new ArgumentNullException(nameof(process));
var tcs = new TaskCompletionSource<bool>();
process.EnableRaisingEvents = true;
process.Exited += (s, e) => tcs.TrySetResult(true);
if (cancellationToken != default)
cancellationToken.Register(() => tcs.TrySetCanceled());
return tcs.Task;
}
}
class Program
{
private const string TempDirectoryPath = @"C:\Temp";
private const string TestFilePath = @"C:\Temp\testfile.exe";
static async Task Main(string[] args)
{
bool debug = false;
if (args.Length == 2 && args[1].Contains("debug"))
{
debug = true;
}
string targetFile = args[0];
if (!File.Exists(targetFile))
{
Console.WriteLine("[-] Can't access the target file");
return;
}
string originalFileDetectionStatus = Scan(targetFile).ToString();
if (originalFileDetectionStatus.Equals("NoThreatFound"))
{
if (debug) { Console.WriteLine("Scanning the whole file first"); }
Console.WriteLine("[+] No threat found in the submitted file!");
return;
}
if (!Directory.Exists(TempDirectoryPath))
{
Console.WriteLine(@"[-] C:\Temp doesn't exist. Creating it...");
Directory.CreateDirectory(TempDirectoryPath);
}
byte[] originalFileContents = await ReadAllBytesAsync(targetFile);
int originalFileSize = originalFileContents.Length;
Console.WriteLine("Target file size: {0} bytes", originalFileContents.Length);
Console.WriteLine("Analyzing...\n");
byte[] buffer = new byte[originalFileSize / 2];
Array.Copy(originalFileContents, 0, buffer, 0, buffer.Length);
int lastGood = 0;
bool threatFound = false;
while (!threatFound)
{
if (debug) { Console.WriteLine("Testing {0} bytes", buffer.Length); }
await WriteAllBytesAsync(TestFilePath, buffer);
List<Task<ScanResult>> scanTasks = new List<Task<ScanResult>>
{
Task.Run(() => Scan(TestFilePath))
};
for (int i = 0; i < lastGood; i += buffer.Length)
{
int remainingBytes = originalFileContents.Length - i;
int bytesToCopy = Math.Min(buffer.Length, remainingBytes);
byte[] previousPart = new byte[bytesToCopy];
Array.Copy(originalFileContents, i, previousPart, 0, bytesToCopy);
string previousFilePath = $@"{TempDirectoryPath}\previousPart{i}.exe";
await WriteAllBytesAsync(previousFilePath, previousPart);
scanTasks.Add(Task.Run(() => Scan(previousFilePath)));
}
await Task.WhenAll(scanTasks);
foreach (var task in scanTasks)
{
string detectionStatus = task.Result.ToString();
if (detectionStatus.Equals("ThreatFound"))
{
if (debug) { Console.WriteLine("Threat found. Half-splitting again..."); }
byte[] tempArray = await HalfSplitterAsync(buffer, lastGood);
Array.Resize(ref buffer, tempArray.Length);
Array.Copy(tempArray, buffer, tempArray.Length);
break;
}
else if (detectionStatus.Equals("NoThreatFound"))
{
if (debug) { Console.WriteLine("No threat found. Going up 50% of the current size."); };
lastGood = buffer.Length;
byte[] tempArray = Overshot(originalFileContents, buffer.Length);
if (tempArray.Length == buffer.Length)
{
Console.WriteLine("Exhausted the search. The binary looks good to go!");
Environment.Exit(0);
}
Array.Resize(ref buffer, tempArray.Length);
Array.Copy(tempArray, buffer, tempArray.Length);
}
else
{
Console.WriteLine("Unknown detection status: {0}", detectionStatus);
Environment.Exit(1);
}
}
}
}
public static async Task<ScanResult> ScanByteArray(byte[] bytes)
{
// Создаем временный файл для сохранения массива байтов
string tempFilePath = Path.Combine(TempDirectoryPath, "tempfile.exe");
try
{
// Записываем массив байтов во временный файл
await WriteAllBytesAsync(tempFilePath, bytes);
// Выполняем сканирование временного файла
ScanResult scanResult = await Scan(tempFilePath);
return scanResult;
}
finally
{
// Удаляем временный файл
if (File.Exists(tempFilePath))
{
File.Delete(tempFilePath);
}
}
}
public static async Task<byte[]> HalfSplitterAsync(byte[] originalarray, int lastgood)
{
int startIndex = lastgood;
int endIndex = originalarray.Length;
int bufferSize = endIndex - startIndex;
if (bufferSize <= 0)
{
Console.WriteLine("[-] Invalid buffer size. Something is wrong...");
Environment.Exit(1);
}
byte[] splitarray = new byte[bufferSize];
Array.Copy(originalarray, startIndex, splitarray, 0, bufferSize);
// Scan the split array for threats
ScanResult scanResult = await ScanByteArray(splitarray);
if (scanResult == ScanResult.ThreatFound)
{
Console.WriteLine("[!] Identified end of bad bytes at offset 0x{0:X} in the original file", endIndex);
await Scan(TestFilePath, true);
byte[] offendingBytes = new byte[256];
int offendingBytesLength = Math.Min(bufferSize, 256);
Array.Copy(splitarray, bufferSize - offendingBytesLength, offendingBytes, 0, offendingBytesLength);
HexDump(offendingBytes, 16);
File.Delete(TestFilePath);
Environment.Exit(0);
}
return splitarray;
}
public static byte[] Overshot(byte[] originalArray, int splitArraySize)
{
int newSize = splitArraySize + (originalArray.Length - splitArraySize) / 2;
if (newSize == originalArray.Length - 1)
{
Console.WriteLine("Exhausted the search. The binary looks good to go!");
Environment.Exit(0);
}
byte[] newArray = new byte[newSize];
Array.Copy(originalArray, 0, newArray, 0, newArray.Length);
return newArray;
}
public static async Task<byte[]> ReadAllBytesAsync(string path)
{
using (FileStream sourceStream = new FileStream(path,
FileMode.Open, FileAccess.Read, FileShare.Read,
bufferSize: 4096, useAsync: true))
{
int bufferSize = (int)sourceStream.Length;
byte[] buffer = new byte[bufferSize];
await sourceStream.ReadAsync(buffer, 0, bufferSize);
return buffer;
}
}
public static async Task WriteAllBytesAsync(string path, byte[] bytes)
{
using (FileStream destinationStream = new FileStream(path,
FileMode.Create, FileAccess.Write, FileShare.None,
bufferSize: 4096, useAsync: true))
{
await destinationStream.WriteAsync(bytes, 0, bytes.Length);
}
}
public static async Task<ScanResult> Scan(string file, bool getSig = false)
{
if (!File.Exists(file))
{
return ScanResult.FileNotFound;
}
var process = new Process();
var mpcmdrun = new ProcessStartInfo(@"C:\Program Files\Windows Defender\MpCmdRun.exe")
{
Arguments = $"-Scan -ScanType 3 -File \"{file}\" -DisableRemediation -Trace -Level 0x10",
CreateNoWindow = true,
ErrorDialog = false,
UseShellExecute = false,
RedirectStandardOutput = true,
WindowStyle = ProcessWindowStyle.Hidden
};
process.StartInfo = mpcmdrun;
process.Start();
await process.WaitForExitAsync(); // Ожидание асинхронного завершения процесса
if (!process.HasExited)
{
process.Kill();
return ScanResult.Timeout;
}
if (getSig)
{
string stdout;
while ((stdout = await process.StandardOutput.ReadLineAsync()) != null)
{
if (stdout.Contains("Threat "))
{
string[] sig = stdout.Split(' ');
string sigName = sig[19];
Console.WriteLine($"File matched signature: \"{sigName}\"\n");
break;
}
}
}
switch (process.ExitCode)
{
case 0:
return ScanResult.NoThreatFound;
case 2:
return ScanResult.ThreatFound;
default:
return ScanResult.Error;
}
}
public enum ScanResult
{
[Description("No threat found")]
NoThreatFound,
[Description("Threat found")]
ThreatFound,
[Description("The file could not be found")]
FileNotFound,
[Description("Timeout")]
Timeout,
[Description("Error")]
Error
}
//Adapted from https://www.codeproject.com/Articles/36747/Quick-and-Dirty-HexDump-of-a-Byte-Array
public static void HexDump(byte[] bytes, int bytesPerLine = 16)
{
if (bytes == null)
{
Console.WriteLine("[-] Empty array supplied. Something is wrong...");
return;
}
int bytesLength = bytes.Length;
int totalLines = (bytesLength + bytesPerLine - 1) / bytesPerLine;
StringBuilder result = new StringBuilder();
for (int line = 0; line < totalLines; line++)
{
int lineStart = line * bytesPerLine;
int lineEnd = Math.Min(lineStart + bytesPerLine, bytesLength);
int lineLength = lineEnd - lineStart;
// Hex representation
StringBuilder hexBuilder = new StringBuilder(lineLength * 3);
for (int i = lineStart; i < lineEnd; i++)
{
hexBuilder.Append(bytes[i].ToString("X2"));
hexBuilder.Append(" ");
}
string hexLine = hexBuilder.ToString().PadRight(bytesPerLine * 3);
// ASCII representation
StringBuilder asciiBuilder = new StringBuilder(lineLength);
for (int i = lineStart; i < lineEnd; i++)
{
byte b = bytes[i];
char c = (b >= 32 && b <= 126) ? (char)b : '.';
asciiBuilder.Append(c);
}
string asciiLine = asciiBuilder.ToString();
// Combine hex and ASCII lines
string fullLine = $"{hexLine} {asciiLine}\n";
result.Append(fullLine);
}
Console.WriteLine(result.ToString());
}
}
}
Надеюсь, что этот проект будет полезным для вас, и я призываю вас воспользоваться им. Если у вас есть какие-либо вопросы или отзывы, буду рад услышать их.
Удачи и продуктивного анализа сигнатур!