![Windows injection по версии GigaChat. Исключительно для привлечения внимания Windows injection по версии GigaChat. Исключительно для привлечения внимания](https://habrastorage.org/getpro/habr/upload_files/d00/ed4/cb1/d00ed4cb1456ed8e4193f7bc62f63bce.jpg)
Приветствую всех!
Сегодня я вам представлю свои наработки по способу инжекта 64-битных DLL библиотек в процессы WOW64, сам который считал невозможным. Любителей потрогать внутренности Windows приглашаю под кат.
Windows обеспечивает совместимость со старыми x86-приложениями с помощью прослойки WOW64. Эта технология создает 32-битное пространство, совместимые структуры PEB/TEB и предоставляет полный набор 32-битных библиотек для работы с Win32 API. Важно отметить, что эти библиотеки не всегда копируют код из нативных 32-битных библиотек Windows x86. Вместо этого, выполняется выход из эмуляции 32-битного режима, а затем передается управление в соответствующую функцию из 64-битной библиотеки. В частности, это касается ntdll.dll, поэтому в процессах WOW64 всегда находятся два экземпляра ntdll: один нативный x64 и второй — WOW64.
![Это разные ntdll, но находятся в одном адресном пространстве Это разные ntdll, но находятся в одном адресном пространстве](https://habrastorage.org/getpro/habr/upload_files/504/0f6/d38/5040f6d38fd93da2991e3a2bf70acb66.png)
Выход из эмуляции можно выполнить и произвольно, для выполнения 64-битного кода прямо посреди 32-битного. Этот метод называется Heaven's Gate и доступен в любом WOW64 процессе, но подобный код не получится выполнить в Windows x86, так как там этот механизм отсутствует. Переключение всегда выполняется для всех потоков в WOW64 процессе, если указатель на начальную функцию находится в памяти корректно загруженного 32-битного модуля (exe или dll). Однако, если адрес указывает на код в 64-битном модуле, переключение не произойдет и режим потока останется прежним, что открывает определенные возможности.
![Определение типа контекста для потока выполняет wow64.dll!Run64IfContextIs64 Определение типа контекста для потока выполняет wow64.dll!Run64IfContextIs64](https://habrastorage.org/getpro/habr/upload_files/251/6fd/d54/2516fdd5429b8ba32e9edd738d61c7fa.png)
Благодаря тому, что любом WOW64 процессе всегда есть несколько 64-битных библиотек, можно использовать свободное место в конце секции .text для выполнения шеллкода, чтобы загрузить нашу библиотеку. Также важно понимать, что DLL-библиотеки можно загружать стандартным способом (например, с помощью LoadLibrary) или вручную, выполняя все действия PE-загрузчика самостоятельно — этот метод называется Manual Map. В этой части мы рассмотрим первый способ.
![Место для шеллкода Место для шеллкода](https://habrastorage.org/getpro/habr/upload_files/9ac/852/658/9ac85265841a78cf260dccb6afade990.png)
Hidden text
Предупреждая вопросы - система позволяет записать данные в RX страницы без каких-либо проблем, но такие изменения не проходят бесследно - выполняется механизм Copy-on-Write, создающий изолированную измененную копию для конкретного процесса, что можно отследить с помощью QueryWorkingSetEx (пример кода)
Загрузка DLL с помощью LoadLibrary (но не совсем)
LoadLibrary — функция Win32 API для загрузки динамических библиотек, определенная в kernel32.dll, и часто используемая как явно, так и неявно. Однако в нашем случае мы не можем её использовать, так как kernel32.dll в процессе принадлежит подсистеме WOW64 и может загружать только 32-битные библиотеки. LoadLibrary сама по себе не выполняет загрузку, а вызывает недокументированную функцию LdrLoadDll из ntdll, которая и выполняет всю работу. К счастью, LdrLoadDll, хоть и не упоминается на MSDN, доступна в отладочных символах и публично экспортируется из ntdll. Прототип вызова этой функции следующий:
NTSTATUS __stdcall LdrLoadDll(PWSTR SearchPath, PULONG LoadFlags, PUNICODE_STRING Name, PVOID *BaseAddress)
Так как 64-битная версия ntdll всегда загружается по одному и тому же адресу в памяти, мы можем найти адрес LdrLoadDll и вызвать её в пространстве процесса-цели следующим образом:
Получаем адрес LdrLoadDll с помощью GetProcAddress.
Находим свободное пространство в сегменте .text в ntdll для шеллкода.
Открываем хендл процесса-цели с помощью OpenProcess.
Выделяем страницу памяти под контекст шеллкода с помощью VirtualAllocEx (или находим свободную RW страницу памяти, убедившись, что это не нарушит работу программы).
С помощью WriteProcessMemory записываем в контекст адрес LdrLoadDll и данные о пути к загружаемой библиотеке
Записываем сам шеллкод в найденное место в ntdll.
Создаем новый поток в ntdll с помощью CreateRemoteThread.
В шеллкод вызываем LdrLoadDll, остальная работа будет выполнена без нашего участия.
Пример кода можно увидеть на github.
![Hello World из x64 библиотеки в пространстве WOW64 Hello World из x64 библиотеки в пространстве WOW64](https://habrastorage.org/getpro/habr/upload_files/799/c09/646/799c09646df6624a4ebd484d027318e2.png)
Плюсы такого инжекта заключаются в том, что LdrLoadDll выполнит полную загрузку библиотеки, подгрузив все необходимые зависимости, включая 64-битную kernel32.dll и другие. Во-первых, это удобно, так как не требует самостоятельной подгрузки зависимостей. Во-вторых, инжектируемая библиотека не нуждается в серьезных переработках под спартанские условия.
Минусы заключаются в том, что библиотека будет явным образом видна в списке загруженных библиотек и её можно загрузить только из файла на диске, что может стать ограничением для некоторых задач. Тем не менее, для большинства 32-битных приложений такая библиотека будет незаметна. Например, это можно использовать для перехвата NT-функций в 64-битной ntdll, тогда как все проверки на предмет изменений будут направлены на 32-битную версию.
В следующей части я опишу, как выполнить тот же инжект 64-to-32, но уже загружая библиотеку вручную - иначе говоря manual map. Это освободит от упомянутых минусов LdrLoadDll-инжекта, а также даст гибкость при загрузке.
Всех благодарю за внимание.
Комментарии (6)
NN1
08.07.2024 19:19Есть библиотека с удобными обёртками для работы из под WOW64: https://github.com/rwfpl/rewolf-wow64ext/
boris768 Автор
08.07.2024 19:19Вот этот вариант будет немного получше, не используется инлайн ассемблер и компилируется не только с помощью msvc
NN1
08.07.2024 19:19+1Зато имеем опкоды записанные в бинарном виде.
Лучше ассемблером , чтобы было легко править.
Ilya_JOATMON
Некоторый оффтоп, но может кто знает, есть ли какие открытые разработки по загрузке для исследования кернел драйверов windows в user space?
boris768 Автор
я думаю, что вы ищите это
https://github.com/waryas/KACE/
Ilya_JOATMON
Да, похоже на то. Жаль, что два года как заброшено. Ну ладно, допиливать все равно по месту придется.