Pattern scanning нужен, когда адрес нельзя держать жёстко: мешают обновления, ASLR и плавающие layout'ы. Вместо "читать по 0x12345678" вы ищете устойчивую последовательность байтов рядом с нужным местом. По теме хорошо зайти через Dynamic Memory Allocation и Pattern Scanner.
Почти всегда сканировать стоит не весь процесс, а память конкретного модуля:
using System.Diagnostics;
using EyeAuras.Memory;
using EyeAuras.Memory.Scaffolding;
using var process = LocalProcess.ByProcessId(Process.GetCurrentProcess().Id);
using var memory = process.MemoryOfModule("kernel32.dll");
Так и быстрее, и понятнее: найденный offset сразу привязан к модулю.
Всё строится вокруг BytePattern. Из коробки поддерживаются:
? и ??\xAA\xBB^, который отмечает точку интереса внутри совпаденияvar exact = BytePattern.FromPattern(new byte[] { 0x48, 0x85, 0xC0, 0x74, 0x0A });
var hex = BytePattern.FromTemplate("48 85 C0 74 0A");
var wildcards = BytePattern.FromTemplate("48 85 ?? 74 0A");
var cStyle = BytePattern.FromTemplate(@"\x48\x85\xC0\x74\x0A");
var masked = BytePattern.FromMaskedPattern(new byte[] { 0x48, 0x85, 0xC0, 0x74, 0x0A }, "xxxxx");
var withOffset = BytePattern.FromTemplate("48 ^ 85 C0 74 0A");
В примере ниже мы будем использовать один и тот же паттерн 48 85 C0 74 0A, чтобы было проще связать схему, код и результат поиска.
^ особенно полезен, когда вам нужен не старт совпадения, а конкретный байт внутри инструкции. Например, 48 ^ 85 C0 74 0A вернет offset не на первый 48, а на следующий байт 85.
Основные методы:
FindOffset(...) — вернуть offset или -1GetOffset(...) — вернуть offset или бросить исключениеFindOffsets(...) и GetOffsets(...) — то же самое для нескольких сигнатурvar pattern = BytePattern.FromTemplate("48 85 C0 74 0A");
var offset = memory.FindOffset(pattern);
if (offset >= 0)
{
var va = memory.BaseAddress + offset;
Log.Info($"Found at 0x{offset:X}, VA={va.ToHexadecimal()}");
}
offset — смещение внутри текущего IMemoryVA — абсолютный адрес в процессеЕсли вы ищете внутри MemoryOfModule(...), абсолютный адрес обычно считается как memory.BaseAddress + offset.
Если взять схему выше, FindOffset(BytePattern.FromTemplate("48 85 C0 74 0A")) вернет offset на первый подсвеченный байт 48.
Find* или Get*Find* — если отсутствие сигнатуры это нормальный сценарийGet* — если отсутствие сигнатуры уже означает несовместимую версию клиента или ошибку.exe или .dll.^, а не лишнюю ручную арифметику.entity list или view matrix сигнатура обычно выступает только как опорная точка. Дальше вы уже читаете указатели и структуры.