Сканирование по сигнатурам
Практическое введение в поиск по сигнатурам.
Для AI-first навигации см. AI Memory / Processes — там описаны подключение к процессу, работа с указателями, readers и место pattern scanning в memory workflow.
Поиск последовательности байтов
Что такое Pattern Scanning
Pattern scanning — это способ искать в памяти конкретные последовательности байтов. Он полезен, когда нужно найти функции, данные или код, которые во время работы программы не всегда находятся по одному и тому же адресу.
Зачем это нужно
- Динамические адреса. Программы часто загружают код и данные в разные места при каждом запуске. Pattern scanning помогает находить нужное независимо от того, куда именно всё попало в этот раз.
- Уникальные совпадения. Паттерны работают как отпечатки пальцев — по уникальной последовательности байтов можно определить конкретный участок памяти.
Найти байты в известном буфере
Для поиска не обязательно открывать процесс. Полный пример работает с байтовым содержимым через публичный MemoryAccessor:
using EyeAuras.Memory;
using EyeAuras.Memory.Scaffolding;
{
using var memory = MemoryAccessor.FromByteArray(
new byte[] { 0x00, 0x55, 0x8B, 0x12, 0xEC, 0x00 });
var pattern = BytePattern.FromTemplate("55 8B ?? ^ EC 00");
var start = memory.FindOffset(pattern); // 1
var marked = start < 0 ? -1 : start + pattern.PatternOffset; // 4
}
?? принимает любой байт. start — смещение начала совпадения, marked — отмеченного байта. Здесь база массива равна нулю; для памяти модуля абсолютный адрес равен memory.BaseAddress + start, либо + marked, если нужен маркер. При -1 адрес не вычисляют. GetOffset вместо отсутствующего совпадения бросит исключение.
В EyeAuras 20fd3d4 одиночный поиск синхронно копирует весь диапазон и учитывает StartOffset. Множественный поиск возвращает словарь и использует другой алгоритм: добавляет PatternOffset, не учитывает StartOffset, не гарантирует самое младшее совпадение и может пропустить образец на границе блоков. Токена отмены нет. Для большого диапазона учитывайте стоимость чтения и не запускайте поиск из UI/render callback. Точные перегрузки и ограничения.
Пример с процессом ниже требует загруженного MemoryModule; в embedded-хосте объявите UseMemory() и дождитесь EnsureReadyAsync(). Одного metadata SDK для LocalProcess недостаточно.
BytePattern
Класс BytePattern добавлен для поддержки нескольких способов задания паттернов. Это упрощает работу с разными форматами, которые обычно используются при сканировании памяти.
Pattern scanning доступен для любого типа, реализующего интерфейс IMemory, например:
{
using var process = LocalProcess.ByProcessName("pathofexile"); //uses naive RPM under the hood
Log.Info($"Process: {process}");
var modules = process.GetProcessModules(); //enumerate all loaded modules
using var memory = process.MemoryOfModule("pathofexile.exe"); //memory implements IMemory
Log.Info($"Process memory: {memory}, base: {memory.BaseAddress.ToHexadecimal()}");
// Возвращает начало совпадения; одиночный поиск не прибавляет PatternOffset.
var offset = memory.FindOffset(BytePattern.FromTemplate("55 8B ?? ^ EC 00"));
// will return dictionary with all found offsets for all given patterns
var playerPattern = BytePattern.FromTemplate("55 8B ?? ^ EC 00");
var targetPattern = BytePattern.FromTemplate("BB AA ??");
var offsetsByPattern = memory.FindOffsets(playerPattern, targetPattern);
// by using Get* instead of Find* the code will throw an exception in case pattern is not found
var criticalOffset = memory.GetOffset(BytePattern.FromTemplate("55 8B ?? ^ EC 00"));
}
Поддерживаемые типы паттернов
-
Массивы байтов
- Паттерн задаётся точными значениями байтов.
- Пример:
var pattern = BytePattern.FromPattern(new byte[] {0x55, 0x8B, 0xEC});Совпадёт только с этой последовательностью байтов.
-
Паттерны в стиле C
- Используются escape-последовательности вида
\xAA\xBB\xCC, как в C-style patterns. - Пример:
var pattern = BytePattern.FromTemplate(@"\x55\x8B\xEC");Эквивалентно массиву байтов
[0x55, 0x8B, 0xEC]. - Используются escape-последовательности вида
-
Шестнадцатеричные строки с wildcard-байтами
- Паттерн задаётся как hex-строка, где
??означает wildcard, то есть любой байт. - Пример:
var pattern = BytePattern.FromTemplate("55 8B ?? 83");Совпадёт с любой последовательностью, которая начинается с
55 8B, затем содержит любой байт, а после него —83. - Паттерн задаётся как hex-строка, где
-
Маскированные паттерны
- Используется массив байтов и маска, где фиксированные байты помечаются как
x, а wildcard — как?. - Пример:Совпадёт с любой последовательностью, которая начинается с
var pattern = BytePattern.FromMaskedPattern(new byte[] { 0x55, 0x8B, 0xEC, 0x00, 0x08 }, "xxx??");55 8B EC, а затем содержит любые два байта.
- Используется массив байтов и маска, где фиксированные байты помечаются как
-
Шаблоны со смещением
- Паттерн задаётся через template, а позиция итогового смещения отмечается символом
^. - Пример:
var pattern = BytePattern.FromTemplate("55 8B ?? ^ EC 00");Маркер задаёт
PatternOffset = 3. В EyeAuras20fd3d4одиночныеFindOffset/GetOffsetвозвращают начало совпадения без этой прибавки; множественныеFindOffsets/GetOffsetsприбавляют её. Не переносите результат одной перегрузки в другую без учёта этого различия. - Паттерн задаётся через template, а позиция итогового смещения отмечается символом