Memory API - С чего начать

Первое знакомство с Memory API в скриптах EyeAuras

Memory API в скриптах EyeAuras

Memory API нужен, когда вы хотите читать не экран, а реальные данные из памяти процесса: entity list, структуры игрока, координаты, HP, target id, view matrix и похожие вещи. Если нужен быстрый игровой контекст, посмотрите Aimbot и ESP у Game Hacking Academy.

Главная идея EyeAuras не в том, что это "ещё один reader памяти". Главное здесь в том, что поверх разных способов доступа к памяти лежит один и тот же верхний слой:

  • типизированное чтение и запись
  • строки, структуры и pointer math
  • MemoryOfModule(...)
  • ReadImports() и ReadExports()
  • pattern scanning
  • code caves

То есть верхний слой можно сохранить при смене backend, если новый backend поддерживает нужные операции.

Какие backend'ы уже есть

  • LocalProcess — обычный локальный процесс через WinAPI. Это нормальная первая точка входа. С защищёнными процессами он не подходит. Подробнее: LocalProcess.
  • NativeLocalProcess — тот же локальный сценарий, но поверх handle, который вы уже получили своим способом.
  • LCProcess — backend через MemProcFS и LeechCore. Основной сценарий здесь это DMA, обычно через FPGA. Подробнее: LCProcess. По теме полезны Ulf Frisk, LeechCore, MemProcFS и PCILeech.
  • KDProcess — backend через kernel driver. Нужен там, где обычного WinAPI уже мало.

В исходной версии руководства KD описан как закрытая бета, а FPGA/DMA — как доступные варианты. Это историческая информация, а не проверка доступности в вашей сборке. Для KD/LC нужны соответствующие компоненты и подготовленный хост.

Если у вас свой драйвер или свой способ чтения памяти, его тоже можно встроить в Memory API. Для этого есть отдельные точки расширения: Кастомный IProcess и Кастомные memory backend.

Куда читать дальше по backend'ам и расширению

Если вам нужна не только базовая работа с LocalProcess, а более конкретный сценарий, удобнее всего идти так:

  • для обычного локального чтения и user-mode контроля: LocalProcess
  • для DMA, MemProcFS и LeechCore: LCProcess
  • если хотите подключить свой драйвер, bridge или внешний reader как полноценный процесс: Кастомный IProcess
  • если хотите оборачивать уже существующий backend в кэш, логирование, статистику или другие decorator-слои: Кастомные memory backend

Что значит IProcess

Если коротко, interface в C# здесь означает не "сложную внутренность", а просто контракт.

  • IProcess — объект, который представляет процесс
  • IProcessMemory — объект, через который вы работаете с памятью процесса

Если вы читаете эту страницу именно как автор интеграции, дальше обычно полезно смотреть две статьи:

  • Кастомный IProcess — если хотите подключить новый источник памяти как полноценный process-wrapper
  • Кастомные memory backend — если хотите добавить кэширование, логирование, статистику или другой низкоуровневый слой поверх уже существующего backend'а

Для старта достаточно помнить простую связку:

  • LocalProcess открывает процесс
  • process.Memory даёт доступ к памяти

Первый пример

Примеры с LocalProcess рассчитаны на верхний уровень C#-скрипта в запущенном EyeAuras с загруженным модулем памяти. Log даёт хост скрипта. В обычном C#-классе передайте логгер и процесс явно. Одна ссылка на SDK не запускает модуль: во встраиваемом хосте сначала нужны запуск приложения, UseMemory() и ожидание EnsureReadyAsync(); подробнее в Embedded SDK.

LocalProcess.ByProcessId(...) возвращает новый ILocalProcess, который освобождает создавший его код. process.Memory используется вместе с этим reader'ом; отдельно закрывать заимствованный сервис хоста не нужно. Эти примеры не проверяют доступность нативных компонентов вашей сборки.

Самый безопасный стартовый сценарий это открыть текущий процесс EyeAuras, взять модуль и прочитать его экспорты.

csharp
using System.Diagnostics;
using EyeAuras.Memory;
using EyeAuras.Memory.Scaffolding;

{
    using var process = LocalProcess.ByProcessId(Process.GetCurrentProcess().Id);
    using var kernel32 = process.MemoryOfModule("kernel32.dll");

    Log.Info($"Process: {process.ProcessName} ({process.ProcessId})");
    Log.Info($"Modules: {process.GetProcessModules().Count}");
    Log.Info($"kernel32 exports: {kernel32.ReadExports().Count}");
}

В журнале появятся имя и PID текущего процесса, число модулей и экспортов kernel32.dll. MemoryOfModule задаёт базу и размер модуля для PE-helper'ов и поиска; это не защита от чтения за его границами. Адреса прямого чтения остаются абсолютными. Процесс должен жить дольше представления модуля.

Базовый маршрут

Обычно работа выглядит так:

  1. открыть процесс
  2. выбрать нужный модуль
  3. ограничить память через MemoryOfModule(...)
  4. найти опорную точку через export, import или сигнатуру
  5. уже потом читать структуры и указатели

Если хотите лучше понять, почему так надёжнее, чем просто хранить один жёсткий адрес, очень помогают Game Fundamentals, Dynamic Memory Allocation и Pattern Scanner.

Что доступно всегда, а что нет

IProcess описывает общий доступ к памяти, модулям, потокам и регионам. Фактическая доступность зависит от backend, прав и состояния целевого процесса. Наличие интерфейса не гарантирует успешное чтение любого адреса.

Выделение памяти, смена защиты, запуск кода и загрузка DLL относятся к отдельным возможностям. ILocalProcess объединяет IProcessControlApi, IProcessSupportsManualMapping и IProcessSupportsUserApc; это не обещание тех же возможностей у произвольного IProcess. Для KD/LC сверяйте контракт своей версии backend.

Выделение, защита и освобождение памяти

В свежих версиях у IProcessControlApi появились явные методы для полного цикла работы с выделенным регионом:

  • AllocateMemory(...) выделяет память и возвращает IMemoryRegion
  • IMemoryRegion хранит Address и Size
  • ProtectMemory(...) меняет protection и возвращает предыдущее значение
  • FreeMemory(...) явно освобождает ранее выделенный регион

Это удобно в сценариях, где нужно:

  • подготовить буфер внутри процесса
  • временно открыть страницу под patching или shellcode
  • потом вернуть protection назад
  • в конце корректно освободить память

Давайте запишем число в собственный временный буфер текущего процесса, прочитаем его и вернём защиту перед освобождением. Это верхний уровень скрипта EyeAuras с загруженным модулем памяти; входных адресов здесь нет.

csharp
using System;
using System.Diagnostics;
using EyeAuras.Memory;

{
    using var process = LocalProcess.ByProcessId(Process.GetCurrentProcess().Id);
    IProcessControlApi control = process;
    var region = control.AllocateMemory(
        IntPtr.Zero, 4096,
        MemoryAllocationType.Commit | MemoryAllocationType.Reserve,
        MemoryProtectionType.ReadWrite);
    try
    {
        process.Memory.Write<int>(region.Address, 742);
        var oldProtection = control.ProtectMemory(
            region.Address, region.Size, MemoryProtectionType.ReadOnly);
        try
        {
            Log.Info($"Value={process.Memory.Read<int>(region.Address)}");
        }
        finally
        {
            control.ProtectMemory(region.Address, region.Size, oldProtection);
        }
    }
    finally
    {
        control.FreeMemory(region);
    }
}

Результат — Value=742 в журнале. Запись сделана до включения ReadOnly. ProtectMemory возвращает прежнюю защиту, FreeMemory освобождает выделенный регион целиком. Сам IMemoryRegion — дескриптор с Address и Size, а не автоматический владелец памяти. Reader освобождается после буфера. У этих синхронных методов нет параметра отмены; другой backend может не поддерживать управление памятью.

Зачем нужен DLL inject

Пока вы читаете память снаружи, вы в основном наблюдаете за процессом. DLL inject нужен, когда код должен выполняться уже внутри целевой программы: вызывать её внутренние функции, ставить хуки, делать code cave, строить internal-логику. Отдельная статья с разбором вариантов, manual mapping и особенностей запуска здесь: DLL inject. Если нужен внешний фон, полезны DLL Memory Hack, DLL Injector, Code Caves & DLL's и Triggerbot.

Контракты на этой странице сверены по EyeAuras 20fd3d4; это чтение исходников, без запуска примеров. Полные сигнатуры и ограничения своей версии проверяйте по карте API памяти и SDK/XML reference.

Что читать дальше