Code Cave
Что такое code cave в EyeAuras, как его искать и когда он вообще нужен
Code Cave в Memory API
Code cave — это свободный участок внутри PE-модуля, обычно заполненный нулями. Его можно использовать под данные, небольшой payload, trampoline или служебный буфер. По общей идее полезны Code Caves & DLL's, DLL Memory Hack и DLL Injector.
Получить список кандидатов в модуле
Метод для обычного C#-класса принимает уже открытый IProcess и точное имя его PE-модуля. Он выполняет поиск, пока представление памяти ещё живо, и возвращает готовый массив:
using System.Linq;
using EyeAuras.Memory;
using EyeAuras.Memory.Scaffolding;
static CodeCaveEntry[] FindCandidates(IProcess process, string moduleName)
{
using var memory = process.MemoryOfModule(moduleName);
return memory.EnumerateCodeCaves(minBytes: 64, alignment: 16).ToArray();
}
StartVA результата — абсолютный адрес, StartRva — смещение от базы модуля, Size — пригодная длина после выравнивания. Пустой массив означает, что в просмотренной части секций кандидатов нет. Reader остаётся у вызывающего кода.
В EyeAuras 20fd3d4 поиск ленивый, по умолчанию просматривает читаемые исполняемые секции и допускает смесь 0x00, 0xCC, 0x90, а не только нули. maxScanPerSection = 1_048_576 ограничивает число байт каждой секции; alignment = 1 отключает выравнивание. Для ожидаемого округления выбирайте степень двойки. Токена отмены нет, чтение секции синхронное. Найденное заполнение не доказывает, что память никому не нужна, и не резервирует её.
Как искать
Искать code cave нужно на памяти конкретного модуля:
using System.Diagnostics;
using EyeAuras.Memory;
using EyeAuras.Memory.Scaffolding;
{
using var process = LocalProcess.ByProcessId(Process.GetCurrentProcess().Id);
using var moduleMemory = process.MemoryOfModule("kernel32.dll");
var candidates = moduleMemory.EnumerateCodeCaves(minBytes: 64, alignment: 16).ToArray();
Log.Info($"Кандидатов: {candidates.Length}");
}
После этого можно перечислить кандидатов:
Дальше — фрагменты для настройки поиска внутри открытого блока с moduleMemory,
не отдельные скрипты после его закрытия. Полный helper с получением модуля
и материализацией результата приведён в начале страницы.
var caves = moduleMemory.EnumerateCodeCaves(
minBytes: 64,
alignment: 16);
Каждый результат приходит как CodeCaveEntry. На практике чаще всего важны Section, StartVA, StartRva и Size.
Данные и код
Не каждый cave подходит для одних и тех же задач. Обычно сценарии делятся так:
readable + writable + not executable— строки, структуры, аргументы, служебные данныеreadable + executable—trampoline, payload, redirection
Для этого есть sectionFilter:
var dataCave = moduleMemory.EnumerateCodeCaves(
minBytes: 128,
alignment: 2,
sectionFilter: s => s.IsReadable && s.IsWritable && !s.IsExecutable)
.FirstOrDefault();
var execCave = moduleMemory.EnumerateCodeCaves(
minBytes: 64,
alignment: 16,
sectionFilter: s => s.IsReadable && s.IsExecutable)
.FirstOrDefault();
Что это не делает
EnumerateCodeCaves(...):
- не пишет данные сам
- не делает hook
- не ставит
jmp - не меняет protection
- не запускает код автоматически
Это только поиск подходящего места.
FreeMemory(...) освобождает выделенную память, а не найденное заполнение внутри PE-модуля. Поиск не устанавливает право на запись или владение диапазоном. Изменение защиты и размещение данных — отдельные операции, которые нельзя считать безопасными только по результату поиска.
Ограничения
- Ищите cave через
MemoryOfModule(...), а не на всей памяти процесса. - Сам поиск требует только чтения памяти.
- Запись в найденный cave зависит от backend'а.
- Для активного patching обычно нужны
LocalProcess,NativeLocalProcessилиKDProcess. - Для
LCProcessпоиск cave полезен как анализ, но не как обычный инструмент управления процессом.