Программерські типси та трикси Спецвипуск трюки для (не дуже)системщиків-початківців

Зміст статті

Хочеш стати впевненим користувачем комп'ютера? Чи легко знаходити кнопку «Пуск» і запускати гру «Сапер»? Хочеш, щоб твої друзі заздрісно дивилися на тебе, тому що ти почав користуватися заповітними гарячими клавішами Alt+TAB? Якщо так, то скажи мені, навіщо ти взяв журнал старшого брата? Хіба він тобі його купував? Віддай журнал негайно!

Віддав? Добре. У цій статті ми розпилюватимемо циркулярною пилкою такі речі, як Driver Signature Enforcement, що чимало стурбувала свого часу драйверописачів, а також TLS – Thread Local Storage, такого собі невід'ємного та прихованого сусіда будь-якого PE-файлу.

Дещо про Driver Signature Enforcement

Як відомо, починаючи з Windows Vista, хлопці з Microsoft серйозно перейнялися завантаженням непідписаних (читай – чужих) драйверів у систему (для Vista йдеться про 64-бітну версію). Насамперед це було зроблено, мабуть, для захисту системи від руткітів, основна бойова частина яких залежить від драйвера ядра. В результаті це призвело до різноманітних проблем, які дісталися системним розробникам, зайнятим у розробці драйверів. Тепер для успішного завантаження драйвера в Windows Vista/7 потрібен був цифровий підпис, а його потрібно було купувати за великі гроші у таких компаній, як Verisign або Thawte.

Розробники руткітів через ці новини не дуже засмутилися. Замість того, щоб засмучуватись, вони почали шукати «ліві» шляхи та лазівки, що дозволяють вантажити непідписані драйвера в систему. У них це традиційно вийшло, і першою серед них була наша улюблена красуня – Рутковська.

Я не розповідатиму тобі про ці способи, про них ти цілком зможеш прочитати вІнтернет. Замість того, щоб їсти чужу рибу, ми краще візьмемо свою вудку і подивимося, що можна вивудити з цього кумедного механізму – Driver Signature Enforcement.

Його «серцем» є бібліотека сi.dll, яка, як завжди, знаходиться в папці /%systemroot%/system32. Експортує вона такі функції:

  • CiCheckSignedFile
  • CiFindPageHashesInCatalog
  • CiFindPageHashesInSignedFile
  • CiFreePolicyInfo
  • CiGetPEInformation
  • CiInitialize
  • CiVerifyHashInCatalog

Найцікавіша тут функція – CiInitialize, вона імпортується ядром під час процесу ініціалізації системи, її псевдокод виглядає приблизно так:

VOID SepInitializeCodeIntegrity() ULONG CiOptions; memset(g_CiCallbacks, 0, 3*sizeof (SIZE_T)); CiOptions = 42; if(KeLoaderBlock) if(*(ULONG*)(KeLoaderBlock+84)) if(SepIsOptionPresent((KeLoaderBlock+84), L"DISABLE_INTEGRITY_CHECKS")) CiOptions 0; if(SepIsOptionPresent((KeLoaderBlock+84), L"TESTSIGNING")) CiOptions = 8; > CiInitialize(CiOptions,(KeLoaderBlock+32), &g_CiCallbacks); > >

Найцікавіше тут те, що CiInitialize повертає назад у ядро ​​три покажчика на функції: g_CiCallbacks[0] = CI! CiValidateImageHeader, g_CiCallbacks [1] = CI! = CI! CiQueryInformation.

Запам'ятаймо це і подивимося на закінчений стек викликів функцій на ранньому етапі ініціалізації системи:

nt!SepInitializeCodeIntegrity nt!SepInitializationPhase1 + 0x1a1 nt!SeInitSystem + 0x29 nt!Phase1InitializationDiscard + 0x7ce nt!Phase1Initialization + 0xd <12 iThreadStartup +0x19

Як тут можна побачити, SepInitializeCodeIntegrity (а вірніше, CiInitialize) створює якісь необхідні надалі умови для успішного завантаження системи. Якщо ми полезімо вглиб CiInitialize, то побачимо, що ця функція перевіряє валідність драйверів, що знаходяться в Boot Driver List (тобто вантажуються при старті). Якщо під час цього процесу будуть виявлені помилки, процес завантаження буде зупинено.

Продовжуємо розглядати процес завантаження драйверів у систему. Стек викликів системних функцій у цьому випадку Vista/7 буде виглядати наступним чином:

nt!MmLoadSystemImage nt!MiObtainSectionForDriver nt!MiCreateSectionForDriver nt!MmCheckSystemImage nt!NtCreateSection nt!MmCreateSection nt!MiValidateImageHeaderІнтерес для нас представляє SeValidateImageHeader – вона перевіряє, чи є цифровий підпис драйвера. Робить вона це так. Спочатку йде перевірка змінної nt!g_CiEnabled (її сенс, думаю, розшифровувати немає необхідності :)) і, якщо вона встановлена ​​в TRUE, перевірить значення покажчика nt!g_CiCallbacks[0]. Якщо останній не дорівнює NULL, то викличе цю функцію та поверне керування. Якщо ж nt!g_CiCallbacks[0] буде порожнім, то вона поверне статус 0xc0000428, що в перекладі загальнолюдською мовою відповідає «Windows cannot verify the digital signature of this file».

Якщо змінна nt!g_CiEnabled дорівнює FALSE, то функція виділить у пам'яті один байт, скопіює туди покажчик на свій перший аргумент, після чого з чистою совістю поверне STATUS_SUCCESS. Всі! Ось таким ось нехитрим способом WIndows Vista/7 перевіряє наявність та валідність цифрового підпису, щоб завантажити драйвер.

Висновок:перевірка того, чи буде завантажений драйвер у систему, залежить лише від однієї змінної. І якщо будь-хто захоче вимкнути цю перевірку – все, що потрібно буде зробити – це переписати в пам'яті один байт. Щоправда, зробити це буде досить складно, тому що ні nt!g_CiEnabled, ні nt!g_CiCallbacks не експортуються ядром і знайти їх буде проблематично.

Що ти знаєш про TLS? Thread Local Storage, або локальна пам'ять потоку - напевно, найдокументованіша з найбільш недокуметованих можливостей Windows.

Що ми знаємо про TLS? Воно зазвичай використовується програмістами у багатопотокових додатках. Ріхтер у своїй біблії системного програмування наводить такий приклад – з кожним потоком TLS зв'язується дата і час, коли він був створений. У момент знищення потоку можна вважати час, протягом якого потік існував. Сценарії, де є дані, пов'язані одночасно і з програмою в цілому, і з окремим потоком, зокрема, змушують використовувати TLS. Наприклад, нехай процес має деякий масив. Кожен елемент масиву разом із вмістом відповідає окремому потоку. Звідки потік дізнається, який індекс у глобальному масиві – його? Так, можна передати функції потоку ThreadProc параметра у вигляді індексу… але це все відомі сторони медалі. Що лежить на поверхні TLS? Що ми про нього не знаємо?

PE-формат підтримує функції зворотного виклику (TLS-callback), що автоматично викликаються системою до передачі управління на точку входу. Зокрема, це дозволяє визначити наявність налагоджувача або потай виконати деякі дії. Якщо PE-файл має калбеки, вони можуть змінювати таблицю TLS під час виконання. Це означає, що якщо у тебе встановлений один калбек, він легко зможе додати інші калбеки під час виконання.

TLS використовується у великій кількості протекторів, захистів, вірусів, crackme та інших програм, що знаходяться у сфері наших спільних інтересів.

Blacklight використовують деякі антиналагоджувальні прийоми, що починаються зі створення callback таблиці TLS (Thread Local Storage). Blacklight's TLS callback намагається обдурити наладчик, створюючи копію головного процесу (fork) до того, як об'єкт процесу повністю створено.

Деякі віруси впроваджуються виключно шляхом модифікування всього чотирьох байт - покажчика на TLS-таблицю, розташовану в пам'яті (в одній із системних DLL), де знаходиться покажчик на команду передачі управління на shell-код.

Звичайно, подібна техніка впровадження працює тільки на тій версії операційної системи, під яку вона ув'язнена, але антивіруси таких вірусів не виявляють. Або взагалі не звертають уваги зміну directory table.

До речі, якщо тебе цікавить використання TLS як антиналагоджувальний прийом – подробиці читай у чудовій статті К. Касперски «Вичерпне посібник з приготування та злому TLS» (http://www.xakep.ru/magazine/xa/118/080/1). asp).

Висновок

Сподіватимемося, що прочитання цієї статті змогло зробити тебе просунутим користувачем комп'ютера. А що робить розвинений користувач? Бере відладчик і колупає все поспіль. Від цього він стає ще більш сучасним користувачем :). Загалом, рухайся вперед, читай] [, і нехай буде з тобою Сила!

На диску ти зможеш знайти фундаментальну, аж на цілих 186 Кб, працю Matthew Conover'a з Symantec, присвячену вивченню механізму безпеки в ядрі Vista – Windows Vista Kernel Mode Security, а також кілька сорців, присвячених темі статті.