- Статус
- Оффлайн
- Регистрация
- 13 Фев 2026
- Сообщения
- 402
- Реакции
- 8
Решил на досуге глянуть, почему Warden в WoW так бодро раздает баны, особенно в контексте Linux и Proton-GE. По факту, это не статичный бинарь, а полноценный RCE-фреймворк: сервер кидает шифрованные модули, клиент их разворачивает в памяти, исполняет и шлет отчет. Логика сканирования меняется на лету без патчей игры.
Раскладка по памяти
Когда Warden активен, в процессе WoW висит несколько анонимных RWX регионов:
Энтропия шифрованных кусков около 7.15 бит/байт. Похоже на RC4, но это скорее редхерринг для любителей реверса. Реальное мясо происходит в лоадере, который я вытащил из дампа.
Анатомия лоадера
В дампе лоадера три основные функции, идущие друг за другом:
1. Stack Probe (0x13470008) — классический __chkstk от MSVC для работы со стеком.
2. SSE2 Memset (0x13470060) — жестко оптимизированная зачистка памяти перед копированием секций.
3. Module Loader Core (0x13470110) — сердце системы, отвечающее за развертывание модулей.
Header Validation и PEB-walk
Blizzard юзают забавный трюк с заголовком: вместо стандартного PE там кастомная структура с магическими байтами 0x8B08EB. В памяти это выглядит как jmp +8 — заголовок сам является валидной входной точкой, которая просто перепрыгивает метаданные.
Импорты Warden резолвит через классический проход по PEB/TEB (gs:[0x30] -> PEB -> LDR). Под Wine/Proton это работает идеально, так как Wine полностью реализует эти структуры. Для поиска нужных DLL используется хэширование FNV-1a.
SIMD и скрытие строк
Чтобы не светить строки типа "kernel32.dll", Warden хранит только хэши. Причем конвертация UTF-16 (имена DLL в списке модулей) в ASCII для хэширования идет через SIMD (инструкции pand, packuswb). Грузят 16 байт, маскируют 0x00FF, пакуют. Скорость бешеная, палево минимальное.
Runtime Behavior
Поток античита (TID 42246) обычно спит в pselect6. Скан триггерится сервером через порт 3724. Это не постоянный мониторинг, а ивентовая система: прилетел запрос — проснулись — просканили — уснули.
Интересный нюанс: под Wine античит видит встроенные DLL как "Builtin DLL". Blizzard их принимает как легитные, хотя они сильно отличаются от нативных Windows-лицов. По сути, это потенциальная дыра для подмены логики. Использование seccomp против него бесполезно — всё происходит в юзерспейсе через прямые указатели на память процесса.
Кто уже ковырял линуксовые либы Warden на предмет векторов под LUA-анлокеры?
Раскладка по памяти
Когда Warden активен, в процессе WoW висит несколько анонимных RWX регионов:
- 0x13470000 (172 KB) — сам лоадер, живой исполняемый код.
- 0x134a0000 (516 KB) — зашифрованный payload модуля.
- 0xc9e10000 (18 MB) — воркспейс, каша из расшифрованного кода и данных.
Энтропия шифрованных кусков около 7.15 бит/байт. Похоже на RC4, но это скорее редхерринг для любителей реверса. Реальное мясо происходит в лоадере, который я вытащил из дампа.
Анатомия лоадера
В дампе лоадера три основные функции, идущие друг за другом:
1. Stack Probe (0x13470008) — классический __chkstk от MSVC для работы со стеком.
2. SSE2 Memset (0x13470060) — жестко оптимизированная зачистка памяти перед копированием секций.
3. Module Loader Core (0x13470110) — сердце системы, отвечающее за развертывание модулей.
Код:
// rcx = module_data (упакованный пакет)
// rdx = target_base (база для распаковки)
// r8 = callback_table
// r9 = context
int warden_load_module(void *module_data, void *target_base, void **callback_table, void *context);
Header Validation и PEB-walk
Blizzard юзают забавный трюк с заголовком: вместо стандартного PE там кастомная структура с магическими байтами 0x8B08EB. В памяти это выглядит как jmp +8 — заголовок сам является валидной входной точкой, которая просто перепрыгивает метаданные.
Импорты Warden резолвит через классический проход по PEB/TEB (gs:[0x30] -> PEB -> LDR). Под Wine/Proton это работает идеально, так как Wine полностью реализует эти структуры. Для поиска нужных DLL используется хэширование FNV-1a.
SIMD и скрытие строк
Чтобы не светить строки типа "kernel32.dll", Warden хранит только хэши. Причем конвертация UTF-16 (имена DLL в списке модулей) в ASCII для хэширования идет через SIMD (инструкции pand, packuswb). Грузят 16 байт, маскируют 0x00FF, пакуют. Скорость бешеная, палево минимальное.
Runtime Behavior
Поток античита (TID 42246) обычно спит в pselect6. Скан триггерится сервером через порт 3724. Это не постоянный мониторинг, а ивентовая система: прилетел запрос — проснулись — просканили — уснули.
Интересный нюанс: под Wine античит видит встроенные DLL как "Builtin DLL". Blizzard их принимает как легитные, хотя они сильно отличаются от нативных Windows-лицов. По сути, это потенциальная дыра для подмены логики. Использование seccomp против него бесполезно — всё происходит в юзерспейсе через прямые указатели на память процесса.
Кто уже ковырял линуксовые либы Warden на предмет векторов под LUA-анлокеры?