Инжект DLL в современных Metro-приложениях

Инжект DLL в современных Metro-приложениях

Ижект DLL – одна из самых старых техник, используемая для выполнения своего кода в приложениях в ОС Windows. Обычно этот метод используется для изменения стандартного поведения приложения или добавления нового функционала.

Автор: Mauro Leggieri

Ижект DLL – одна из самых старых техник, используемая для выполнения своего кода в приложениях в ОС Windows. Обычно этот метод используется для изменения стандартного поведения приложения или добавления нового функционала.

Инжект DLL в процесс – относительно простая задача: необходимо создать удаленный поток, где будет вызываться LoadLibrary, используя метод CreateRemoteThread или NtCreateThreadEx. Для получения доступа к инжектируемому процессу вам необходимы некоторые привилегии, однако их получение выходит за рамки этой статьи.

Когда вы попытаетесь инжектировать библиотеку в Metro-приложение в Windows 8, то обнаружите, что хотя инжектируемый код и работает корректно, ваша DLL НЕ загрузится. Метод LoadLibrary возвратит FALSE, и метод GetLastError возвратит ERROR_ACCESS_DENIED.

Ну, подумаете вы… Современные UI-приложения имеют ограниченные доступ к ресурсам системы и запускаются в «песочнице», так что подобные проблемы ожидаемы.

Во время исследования методов по добавлению нового функционала в приложение Windows Mail, поставляемое вместе Windows 8, и перехвату функций в современных UI-приложениях посредством Deviare, нам нужно выяснить, почему LoadLibrary возвращает FALSE.

На сцену выходит реверс-инжиниринг

Мы начнем с анализа метода LoadLibrary. Он вызывает LoadLibraryEx с dwFlags=0 и выполняет некоторые проверки. Первая остановка.

Если вы хотите загрузить упакованный объект (package), то должны использовать LoadPackagedLibrary API. Если вы хотите загрузить обычную DLL, то должны использовать LoadLibrary[Ex]. В документации на LoadPackagedLibrary говорится о том, что путь не может быть абсолютным или содержать «..», однако эти проверки в основном делаются в методе LoadLibraryEx. Единственное отличие между LoadLibrary и LoadPackagedLibrary - в параметре dwFlags, который равен 4 или 0.

Кроме того, LoadLibraryEx будет формировать поисковый путь для обнаружения DLL, а затем вызовет недокументированный метод LdrLoadDll. Поскольку мы хотим напрямую указать путь к библиотеке, то, соответственно, сразу будем вызывать метод LdrLoadDll.

Вторая попытка:

Хотя LdrLoadDll корректно нашел DLL, при использовании SpyStudio для проверки ошибок, мы обнаружили, что при вызове метода NtOpenFile возникла ошибка STATUS_ACCESS_DENIED. Мы установили, что это проблема имеет отношение к безопасности.

Используя утилиту icacls.exe, мы установили дополнительные привилегии на DLL-файл, чтобы позволить чтение и запуск в процессах с низким уровнем достоверности (low integrity processes). Также мы добавили нового пользователя в Windows 8 с именем «ALL APPLICATION PACKAGES» в список пользователей с правами на чтение и запуск DLL-кода.

Третья попытка:

NtOpenFile выполнил начальные проверки безопасности, однако DLL все равно не загружена.

Продолжая исследовать LdrLoadDll, мы перешли в режим ядра из NtCreateSection API и выяснили, что функция CiValidateImageHeader библиотеки ci.dll возвращает ошибку STATUS_INVALID_IMAGE_HASH, после чего мы добавили цифровую подпись к файлу. Для предупреждения будущих проблем, вместо самоподписанного сертификата, мы использовали настоящий.

Теперь с функцией CiValidateImageHeader все ок, но далее функция CiValidateImageData возвращает ту же самую ошибку. Далее мы добавили параметр /ph при использовании утилиты SignTool.exe для включения страниц хэшей в подписываемый процесс.

Четвертая попытка:

Ну, подумали мы: теперь DLL подписана, с привилегиями все ок. Попробуем еще раз.

И вновь ошибка.

На этот раз камнем преткновения стала функция SeGetImageRequiredSigningLevel, которая находится в ntoskrnl.exe. SeGetImageRequiredSigningLevel проверяет минимальные требования к сертификату при загрузке DLL внутри WinRT-приложения.

Мы решили, что нужно подписать нашу DLL кросс-сертификатом, который используется для подписи драйверов режима ядра.

Вывод:

Исследования были остановлены, поскольку на данный момент у нас нет кросс-сертификата, однако мы обнаружили, что один из параметров ядра определяет, какой тип сертификата проверяется функцией SeGetImageRequiredSigningLevel.

В этом посте объясняется метод ручного обхода посредством WinDbg защитных проверок и запуска недостоверных приложений в устройстве Surface. Следуя схожей процедуре, мы можем обойти защитные проверки и корректно смапировать и заинжектить DLL в WinRT-приложениях в версии Windows для настольных ПК.

Перед началом нашего исследования, у нас уже был рабочий метод по инжекту DLL в WinRT-приложениях: нужно скопировать DLL-файл в папку System32. Хотя для этого и нужны права администратора, но в этом случае вы можете использовать метод LoadLibrary без указания пути к библиотеке, поскольку System32 является папкой, где по умолчанию происходит поиск библиотек. К тому же, поскольку вы используете относительный путь, некоторые проверки безопасности отменяются. Еще один плюс – вам не нужно подписывать файл!

Однако мы, как и множество компаний, хотим избежать разрастания папки System32 и храним файлы в той же директории, где находится приложения. Именно поэтому мы и начали наше исследование. 

Цифровые следы - ваша слабость, и хакеры это знают.

Подпишитесь и узнайте, как их замести!