1.5.7881

Середина декабря — сканирование паттернов

C# Scripting — добавлено сканирование по сигнатурам

Что такое Pattern Scanning?

Pattern scanning — это способ поиска определённых последовательностей байтов в памяти. Он полезен, когда нужно найти функции, данные или участки кода, которые при каждом запуске программы могут находиться по разным адресам.

Зачем это нужно?

  1. Динамические адреса: программы часто загружают код и данные в разные места памяти при каждом запуске. Pattern scanning позволяет находить нужное независимо от того, где именно это оказалось.
  2. Уникальные совпадения: сигнатуры работают как отпечатки пальцев — они помогают распознавать конкретные области памяти по уникальным последовательностям байтов.

BytePattern

Добавлен класс BytePattern, который поддерживает несколько способов описания сигнатур. Это упрощает работу с разными типами шаблонов, которые обычно используются при сканировании памяти.

Сканирование по сигнатурам доступно для любого типа, реализующего интерфейс IMemory, например:

csharp
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()}");

// will find a singular offset pointing at 4th byte in the sequence
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.FindOffset(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")); 

Поддерживаемые типы сигнатур

  1. Массивы байтов

    • Позволяют задавать сигнатуру точными значениями байтов.
    • Пример:
    var pattern = BytePattern.FromPattern(new byte[] {0x55, 0x8B, 0xEC});
    

    Точно совпадает с этими байтами.

  2. Сигнатуры в C-стиле

    • Используют escape-последовательности вида \xAA\xBB\xCC, как в шаблонах C-style.
    • Пример:
    var pattern = BytePattern.FromTemplate("\x55\x8B\xEC");
    

    Эквивалентно массиву байтов [0x55, 0x8B, 0xEC].

  3. Шестнадцатеричные строки с wildcards

    • Сигнатура задаётся как hex-строка, где ?? означает wildcard (любой байт).
    • Пример:
    var pattern = BytePattern.FromTemplate("55 8B ?? 83");
    

    Совпадает с любой последовательностью, начинающейся с 55 8B, затем с любым байтом и потом 83.

  4. Маскированные сигнатуры

    • Сочетают массив байтов и маску, где фиксированные байты помечаются как x, а wildcard — как ?.
    • Пример:
      csharp
      var bytes = ;
      var mask = ;
      var pattern = BytePattern.FromMaskedPattern(new byte[] { 0x55, 0x8B, 0xEC, 0x00, 0x08 }, "xxx??");
      
      Совпадает с любой последовательностью, начинающейся с 55 8B EC, после чего идут любые два байта.
  5. Шаблоны со смещением

    • Позволяют задать сигнатуру через шаблон и отметить позицию итогового смещения символом ^.
    • Пример:
    var pattern = BytePattern.FromTemplate("55 8B ?? ^ EC 00");
    

    В этом случае смещение ставится прямо перед EC (то есть после пропуска 3 байтов). Это означает, что после нахождения сигнатуры итоговый offset будет Offset + 3.


Исправления и улучшения

  • [UI] Небольшое исправление layout в вынесенном C# editor