Інжект DLL у сучаснихMetro-додатках

Іжект DLL – одна з найстаріших технік, яка використовується для виконання свого коду в програмах Windows. Зазвичай цей метод використовується для зміни стандартної поведінки програми або додавання нового функціоналу.
Іжект 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 і зберігаємо файли в тій директорії, де знаходиться програми. Саме тому ми й розпочали наше дослідження.