Эта библиотека и CLI-инструмент на Rust демонстрируют альтернативный метод поиска базового адреса загруженных DLL без обхода Process Environment Block (PEB). Этот метод особенно полезен в сценариях, где обход PEB может быть обнаружен или заблокирован.
Различия веток
Этот репозиторий содержит две ветки с разными подходами:
Основная ветка (Main)
Использует крейт winapi и VirtualQuery для проверки памяти
Функции библиотеки (lib.rs) не содержат операторов вывода для чистой интеграции
CLI-инструмент (main.rs) включает отладочный вывод для демонстрации концепции
Подходит для изучения и понимания метода
Ветка OPSEC
Без внешних зависимостей — полностью самодостаточна
Без вызовов Windows API — использует прямой доступ к памяти с обработкой исключений вместо
VirtualQuery
Без операторов вывода в функциях библиотеки
Повышенная скрытность — не совершает вызовов API
Лучше подходит для имплантов/инструментов — оставляет меньше следов и её сложнее обнаружить
Обе ветки безопасны в использовании, но ветка OPSEC даёт дополнительные преимущества операционной безопасности для сценариев, где вызовы API могут отслеживаться или блокироваться.
Как это работает
Программа использует подход с обходом стека для поиска DLL:
Доступ к Thread Environment Block (TEB):
Использует встроенный ассемблер для чтения указателя TEB из сегментного регистра GS (GS:[0x30])
Извлекает базу стека (GS:[0x08]) и предел стека (GS:[0x10]) из TEB
Обход стека:
Начинает с текущего указателя стека (RSP)
Поднимается по стеку в поисках адресов возврата
Проверяет каждый адрес на исполняемую память
Основная ветка: использует VirtualQuery для проверки областей памяти
Ветка OPSEC: использует прямой доступ к памяти с обработкой исключений
Идентификация модуля:
Для каждого потенциального адреса возврата проверяет, указывает ли он на исполняемую память
Когда исполняемая память найдена, идёт назад для поиска PE-заголовка
Проверяет модуль по следующим признакам:
Сигнатура MZ (DOS-заголовок)
Сигнатура PE
Характеристики DLL
64-битная архитектура
Имя модуля из каталога экспорта
Проверка:
Подтверждает, что модуль является целевой DLL, проверяя его имя в каталоге экспорта
Убеждается, что все структуры PE-заголовка корректны
Почему такой подход?
Традиционные методы поиска DLL часто включают обход списка модулей PEB. Несмотря на эффективность, такой подход может:
Быть обнаруженным программным обеспечением безопасности
Быть заблокированным в определённых средах
Метод обхода стека предлагает альтернативу, которая:
Не полагается на PEB
Может работать в средах, где обход PEB заблокирован
use moonwalk::find_dll_base;
fn main() {
// Найти ntdll.dll
if let Some(ntdll_base) = find_dll_base("ntdll.dll") {
println!("ntdll.dll base: 0x{:X}", ntdll_base);
}
// Без учёта регистра, расширение .dll необязательно
if let Some(kernel32_base) = find_dll_base("KeRNEl32") {
println!("kernel32.dll base: 0x{:X}", kernel32_base);
}
}
Как CLI-инструмент
Сборка:
root@kitploit:~
cargo build --release
Запуск:
root@kitploit:~
# Найти ntdll.dll (по умолчанию)
cargo run --release
# Найти конкретную DLL (без учёта регистра, расширение .dll необязательно)
cargo run --release kernel32.dll
cargo run --release KeRNEl32
cargo run --release USER32
Пример
Операторы вывода больше не включены. Это изображение включено в образовательных целях.
Примечания
Имена DLL не чувствительны к регистру, расширение .dll необязательно
Работает только с DLL, присутствующими в стеке вызовов
Основная ветка: использует VirtualQuery для безопасной проверки доступа к памяти
Ветка OPSEC: использует прямой доступ к памяти с обработкой исключений для максимальной скрытности
Обе ветки имеют чистые библиотечные интерфейсы без отладочного вывода