Створення власного компонента GINA.Часть 1, Різне, Програмування, статті






Уже кілька років багато хто просить мене написати про GINA (Graphical Identification and Authentication) – компоненті, який служить точкою входу для інтерактивної реєстрації. Сьогодні я почну розповідати про ньому. Це допоможе вам, якщо ви зібралися розробити свою реалізацію цієї штуковини. Я створю приклад KIOSKGNA, саму просту реалізацію GINA, яку я тільки зміг придумати. Наступного разу я покажу FULLGINA з більш багатою функціональністю. Приклади і фрагменти коду написані на некерованому C++, Найбільш підходящим для розробки GINA в наш час.


Що таке GINAі навіщо її замінювати?

GINA – це частина WinLogon, яку можна заміняти для модифікації функціональності UI входу в Windows. Замінивши GINA, можна вибрати механізм аутентифікації, що використовується Windows для інтерактивних користувачів. Найчастіше це корисно при реєстрації з застосуванням смарт-карт або біометричних даних.

Чесно скажу, заміна GINA – складне завдання і підходити до неї треба серйозно. До такої заміни слід вдаватися лише в тому випадку, якщо іншого варіанту немає (наприклад при реалізації нового механізму реєстрації, не підтримуваного Windows).

На секунду задумайтеся про те, що робить GINA. Він збирає облікові дані локальних і віддалених користувачів (останніх через Terminal Services), яким потрібна інтерактивна реєстрація на комп’ютері. Потім компонент встановлює сеанс входу. Його злом дозволить вкрасти відкриті паролі, біометричні дані користувача, PIN-коди смарт-карт і т. д. Скомпрометований компонент GINA може служити “чорним ходом “, дозволяючи будь скористатися привілеями адміністратора. Коротше кажучи, замінюючи GINA, доручіть цю роботу кращим програмістам і ретельно перевірте результат.

І ще дещо. Тут той самий випадок, коли чим простіше і менше, тим краще. Цей компонент працює під обліковим записом SYSTEM, приймає дані від локальних і віддалених користувачів і виконується постійно. Тому його код повинен бути абсолютно куленепробивним.


З чого почати

На момент написання цієї статті документація по реалізації GINA була дуже мізерною. В Platform SDK є два приклади: GINASTUB і GINAHOOK. GINASTUB просто завантажує MSGINA.DLL, реалізацію GINA за замовчуванням, входить до складу Windows, і переправляє їй всі запити. При збірці і установці цього прикладу ви не побачите жодних змін в системі. Так як GINASTUB обгортає MSGINA, вона може виконувати пре-і пост-процесну обробку кожного запиту. Можливо, вам вистачить цього нескладного методу, але він безумовно не годиться, якщо треба зробити щось нетривіальне кшталт заміни механізму реєстрації на біометричну аутентифікацію.

Другий приклад називається GINAHOOK. Він схожий на GINASTUB, але більш просунутий, перехоплюючи відображаються MSGINA діалоги. Пропонована методика дозволяє змінити зовнішній вигляд будь-якого діалогового вікна входу і в якійсь мірі модифікувати його поведінку. Проте небезпека тут в тому, що це призведе до використання недокументованою функціональності MSGINA. До такої функціональності ставляться як прості речі на зразок ідентифікаторів елементів управління в діалогах, так і поведінку нижележащих віконних процедур. Не йдіть цим шляхом, якщо потрібно підтримувати різні версії операційної системи, тому що ваша реалізація GINA може звалитися при установці чергового пакету оновлень!

Більшість нетривіальних реалізацій GINA найкраще писати з нуля. Але на волі такі звірі не зустрічаються (і вже точно жодного безкоштовного прикладу). Ось я і виправлю цю ситуацію.

Через складність предмета я присвячу йому кілька випусків своєї рубрики і не зможу освітити всі темні куточки розробки GINA. Моя мета – дати вам початковий імпульс на випадок, якщо вам доведеться самостійно розробляти GINA. Додаткову інформацію ви знайдете на сторінці Wikki, присвяченій розробці GINA, де можна взяти (або додати) різноманітні відомості і вихідний код. Зайдіть на мою сторінку Wikki за посиланням pluralsight.com / wiki.


SAS

Перш ніж заглибитися в тему, я хотів би розповісти про SAS (Secure Attention Sequence). Це дія, що виконується користувачем для залучення уваги операційної системи і дозволяє йому проводити деякі операції, пов’язані з безпекою, наприклад вхід, розблокування робочої станції або зміну пароля.

Найбільш відома SAS – комбінація клавіш Ctrl + Alt + Del, перехоплюється ядром. Вона допомагає перешкодити шкідливим програмам, які намагаються підмінити діалог входу і вкрасти облікові дані користувача, тому що WinLogon, отримуючи SAS-повідомлення, змінює звичайний робочий стіл користувача на захищений до запиту облікових даних. Цікавилися, куди діваються ваші панель задач і робочий стіл при натисканні Ctrl + Alt + Del? Вони нікуди не зникають, просто їх немає на поточному робочому столі. Мета всього цього – привчити користувачів вводити пароль лише після натискання Ctrl + Alt + Del.

Але SAS – це не тільки Ctrl + Alt + Del. Наприклад, якщо біометричне пристрій здатний повідомляти драйверу про те, що воно використовується, це може служити SAS (скажімо, користувач підніс палець до сканера відбитків пальців). Часто SAS викликається пристроєм читання смарт-карт, коли така карта виймається або вставляється. При створенні власного GINA потрібно вибрати механізм (и) виклику SAS. Функ-ція WlxSasNotify в WinLogon викликається при виявленні SAS або при необхідності імітувати його. Звичайно, можна змусити WinLogon використовувати Ctrl + Alt + Del, якщо немає нічого більш підходящого.


Структура GINA

GINA представляє собою DLL, що завантажується і періодично викликається WinLogon. Це “довгограюча” бібліотека, зазвичай вивантажується тільки при перезавантаженні комп’ютера, так що витоку пам’яті вкрай небажані!

Нестандартний компонент GINA повинен містити кілька точок входу, визначених Microsoft. Я перерахував ці функції в табл. 1. Такий компонент практично завжди підтримує внутрішній стан, і WinLogon допомагає в цьому, передаючи void * першим аргументом цих функцій. Вам вирішувати, на що вказує цей покажчик. У моєму прикладі це покажчик на екземпляр класу Gina, що реалізує стан і поведінку мого компонента GINA.

Новачків в розробці GINA бентежить те, що крім Wlx-функцій, які повинен реалізувати нестандартний GINA, WinLogon надає кілька функцій, які GINA може викликати при необхідності (табл. 2). Так як у цих функцій однаковий префікс Wlx, їх легко переплутати. Швидко розрізнити їх можна по першому параметру функції. Якщо це HANDLE hWlx, значить, функція надається WinLogon для виклику з GINA, а якщо PVOID pWlxContext, цю функцію має реалізувати GINA.


Стани WinLogon

В будь-який момент WinLogon може перебувати в одному з трьох станів; в цій статті вони позначаються при кожному згадуванні. Можливі стану такі: LOGGED_OFF (WinLogon в даний час не зареєстрував користувача), LOGGED_ON (користувач увійшов) і LOCKED (користувач зареєстрований на заблокованій робочої станції).

WinLogon викликає деякі важливі функції GINA при переході з одного стану в інший. Тепер, коли ви знаєте про SAS і станах WinLogon, я продемонструю GINA в дії.

На рис. 1 приведена спрощена схема станів і переходів GINA, заглядайте туди при читанні статті. Вона включає багато основні функції GINA, які викликає WinLogon, і ілюструє нормальний хід подій.


Ініціалізація

При завантаженні комп’ютера після ініціалізації операційної системи та запуску всіх автоматичних сервісів WinLogon завантажує GINA і викликає WlxNegotiate, потім WlxInitialize.

Реалізація WlxNegotiate тривіальна. Вона просто дозволяє GINA і WinLogon звірити версії і переконатися, що все піде гладко. Обрана версія визначає функціональність, очікувану WinLogon від вашого GINA, а також функціональність, очікувану GINA від WinLogon. На момент написання цієї статті останньою версією була 1.4, вона забезпечує додаткову підтримку Remote Desktop в Windows XP, так що саме її я реалізую в прикладі FULLGINA.

У функції WlxInitialize ви отримуєте описувач (hWlx), відповідний WinLogon, а також покажчик на таблицю функцій, які може викликати GINA. Це Wlx-функції, реалізовані в WinLogon і приймаючі HANDLE першим аргументом. Щоб згодом викликати ці функції, потрібно десь зберегти покажчик і описувач. Ось тут-то і знадобиться останній аргумент pWlxContext, який є вихідним параметром, що повертається WinLogon. Найпростіше змусити його вказувати на структуру даних (class або struct), використовувану для зберігання стану GINA, в якому міститься описувач і покажчик на таблицю функцій, передані WinLogon. На рис. 2 наведено дуже простий приклад.

Ця реалізація в моєму прикладі складніше, але ідея показана вірно. Відтепер при виклику будь-яких функцій GINA з WinLogon, останній передає pWlxContext першим параметром, так що у вас завжди є доступ до стану. Наприклад:



BOOL WINAPI WlxIsLogoffOk(PVOID pWlxContext)
{
return ((Gina*)pWlxContext)->IsLogoffOk();
}

Просто переправляючи кожен виклик класу GINA, я можу додавати змінні-члени класу, що зберігають стану GINA. Це природний спосіб розробки GINA, а заглушки можна повторно використовувати в будь-якому проекті.


Один день з життя GINA

Після ініціалізації GINA WinLogon запускає свій автомат станів, викликаючи функції, експортовані з GINA, у міру зміни свого стану. Відразу після ініціалізації користувач не зареєстрований, так що WinLogon вимагає вивести запрошення, викликаючи WlxDisplaySASNotice. На цьому етапі звичайний GINA виводить знайомий діалог з текстом “Press Ctrl + Alt + Del to log in” (“Натисніть Ctrl + Alt + Del для входу”).

Коли користувач натискає Ctrl + Alt + Del або коли GINA викликає WlxSasNotify для генерації SAS іншого типу, WinLogon знищує діалогове вікно (подробиці пізніше) і викликає таку функцію GINA – WlxLoggedOutSAS.

Ім’я WlxLoggedOutSAS може здатися кумедним, але воно точно відображає те, що відбувається в GINA. Ви перебуваєте в стані LOGGED_OUT і отримуєте SAS. Тепер потрібно автентифікувати користувача, який намагається зареєструватися. Мій приклад FULLGINA відкриває діалогове вікно для отримання імені користувачі та пароля, а потім викликає LsaLogonUser для перевірки правильності пароля. Якщо пароль неправильний, я виводжу повідомлення про помилку і знову звертаюсь ім’я користувача та пароль. Отримавши правильні облікові дані, LsaLogonUser встановлює сеанс входу для користувача і повертає описувач маркера (token) в мій код, в свою чергу повертається в WinLogon.

WinLogon приймає маркер від GINA і налаштовує список управління доступом (ACL) на робочому столі за замовчуванням, закриваючи його від усіх, крім сеансу входу поточного користувача. Крім адміністраторів і самої операційної системи інші зареєстровані користувачі не можуть звертатися до цього робочого столу. Коли робочий стіл за замовчуванням готовий, WinLogon знову викликає GINA через функцію WlxActivateUserShell. Тепер GINA повинен запустити налаштовувану оболонку і повернути управління WinLogon.

Цікаво, що WinLogon не надає функції WlxActivateUserShell описувач маркера, переданий на попередньому етапі. Цей стан GINA повинен підтримувати самостійно. Тепер WinLogon знаходиться в стані LOGGED_ON і всім управляє зареєстрований користувач. Припустимо, користувач натискає Ctrl + Alt + Del. Можете вгадати ім’я викликається WinLogon функції?

Якщо ви вибрали WlxLoggedOnSAS, ви вгадали. Тут користувачеві, ймовірно, варто запропонувати кілька варіантів. На рис. 3 наведено звичайний діалог, який відображається на цьому етапі. Він виглядає знайомим. На самому ділі реалізувати його куди легше, ніж здається, завдяки тому, що WinLogon забезпечує більшу частину функцій. Від GINA потрібно лише повідомити WinLogon, який варіант вибрав користувач, повернувши одну з декількох визначених констант з WlxLoggedOnSAS. Обробка запитів на зміну пароля – єдине, що вимагає від програміста істотних зусиль, і якщо паролі використовуються, ця функціональність все одно буде потрібно в інших місцях GINA.

Припустимо, користувач вирішив заблокувати комп’ютер. Тоді WinLogon викличе GINA-функцію WlxDisplayLockedNotice, аналогічну WlxDisplaySAS-Notice. Ви просто відображаєте модальний діалог і чекаєте, поки WinLogon знищить його.

Коли користувач натискає Ctrl + Alt + Del, WinLogon викликає WlxWkstaLockedSAS, і ви знову повинні запитати у користувача облікові дані. Складність тут в тому, що GINA повинен повідомити WinLogon, чи той це користувач, який заблокував комп’ютер і тепер повернувся розблокувати його або хтось зовсім інший. В останньому випадку ви перевіряєте, чи є новий користувач адміністратором, і запитуєте, чи бажає він примусово завершити сеанс поточного користувача. В цьому випадку рано чи пізно буде викликана WlxLogoff, яка поверне управління в WlxDisplaySASNotify для запиту облікових даних користувача.

Якщо користувач просто розблокує комп’ютер, WinLogon повертається в стан LOGGED_ON і користувач знову керує робочим столом. Тепер не забудьте, що користувач може завершити сеанс, вимкнути комп’ютер або навіть заблокувати комп’ютер, не натискаючи Ctrl + Alt + Del і не потрапляючи в GINA. Наприклад, API-функції LockWorkstation і навіть ExitWindowsEx можна викликати з будь-якої програми, в тому числі з Windows Explorer. Звичайно, GINA буде повідомлений про те, що користувач завершує сеанс або блокує комп’ютер, але враховуйте, що не всі ці дії ініціюється GINA.


Модальні діалоги і потоки GINA

Кожен модальний діалог, який відображається з GINA, повинен підтримувати переривання з WinLogon. Є кілька причин, за якими WinLogon може втрутитися в користувальницький інтерфейс GINA: користувач може бути неактивний протягом декількох хвилин, може з’явитися SAS, спрацювати хранитель екрану і т. д. WinLogon обходиться з цим дуже просто. Замість того щоб викликати звичайні Win32-функції DialogBox, DialogBoxParam та ін, GINA викликає аналогічні функції, розкриваються WinLogon. Останній може перехопити процедуру діалогового вікна і закрити модальний діалог в будь-який момент. Так що, якщо для реалізації діалогових вікон ви використовуєте середу начебто MFC, вам доведеться злегка підкрутити її так, щоб викликалися API-функції WinLogon.

Але при використанні MFC або більш складних середовищ постає питання про їх придатність для розробки GINA. Не забудьте, хороший GINA компактний, простий і куленепробивні. Постарайтеся звести обсяг завантаження GINA коду до мінімуму.

Раз вже я заговорив про інтерфейс, хотілося б звернути вашу увагу на те, що GINA – насправді GUI-компонент. Він спроектований однопоточному, принаймні з точки зору WinLogon. Останній не передбачає викликів з інших потоків крім того, з якого GINA викликався в перший раз. Наприклад, коли GINA отримує SAS від зовнішнього влаштуй-ства, йому не слід викликати WlxSaSNotify з випадкового потоку. Замість цього потрібно використовувати потік WinLogon. Найкраще це зробити з потоку, що викликав WlxDisplaySAS / LockedNotice, щоб дати зрозуміти WinLogon, що користувач згенерував SAS, звернувшись до вашого пристрою, і хоче увійти в систему або заблокувати її. Якщо у вас є другий потік, що приймає дані від пристрою, можна просто відправити повідомлення діалогу, що відображає SAS або повідомлення про блокування. Потім UI-потік може сміливо викликати WlxSasNotify.


Розгортання GINA

Після того як GINA зібраний, його необхідно розгорнути і протестувати. Я настійно не рекомендую розгортати GINA на комп’ютері розробника. Використовуйте окремий комп’ютер для тестування GINA. Особисто я застосовую Virtual PC і її функцію скасування дискових операцій. Якщо трапиться щось дей-ствительно погане і все закінчиться нескінченним циклом перезавантажень (так, рано чи пізно з вами це станеться), я просто закриваю Virtual PC і відміняю зміни. Інший варіант – вибрати безпечний режим і видалити неправильний GINA.

Для розгортання GINA в тестових цілях просто скопіюйте DLL на цільовий комп’ютер (для неї підійде каталог System32) і змініть реєстр, додавши іменований параметр в розділ WinLogon:



HKLMSOFTWAREMicrosoftWindows NTCurrentVersionWinLogon

Іменований параметр повинен називатися GinaDLL, мати тип REG_SZ, а значенням має бути ім’я DLL. Перезавантажте комп’ютер, і новий GINA запуститься при завантаженні комп’ютера. При спробі розгорнути нову версію GINA поточна версія може виявитися заблокованою ОС, і її файл не вдасться перезаписати. Тоді перейменуйте файл з GINA на диску до копіювання нового. Згодом ви зможете просто видалити старий файл.

Якщо трапилася неприємність і вам потрібно відновити старий GINA, просто видаліть ключ GinaDLL і не забудьте, що до реєстру можна звертатися віддалено за умови, що ви є адміністратором на віддаленому комп’ютері. Просто запустите REGEDIT.EXE і виберіть File / Connect Network Registry.

Завершивши тестування і виконавши реальне розгортання, ви повинні після копіювання GINA DLL на диск користувача встановити для файлу ACL так, щоб лише адміністратори могли змінювати файл. Ви не досягнете такого рівня захисту за замовчуванням, просто помістивши файл в каталог System32.


Налагодження GINA

Якщо ви не належите до тих, хто регулярно використовує низькорівневі символьні отладчики, налагодження GINA в період його виконання в WinLogon не доставить вам задоволення. Ось чому мій приклад спроектований так, щоб він міг працювати без WinLogon, і я рекомендую вам зробити те ж саме. Я просто додаю в GINA DLL ще одну вхідну крапку, DebugGINA. В остаточних збірках ця функція нічого не робить. Однак в налагоджувальних збірках через цю функцію я можу задіяти будь-який сценарій налагодження. Для цього треба зробити інтерфейс абстрактним з точки зору WinLogon, так щоб при налагодженні можна було імітувати таблицю функцій WinLogon, підставляючи соб-ственную реалізацію. Стандартний спосіб домогтися цього при компонентному тестуванні – застосування інтерфейсів в поєднанні з сурогатними об’єктами.

Я використовую дуже простий інтерфейс IWinLogon, що містить методи для всіх функцій, які GINA потрібно викликати з WinLogon. Наприклад, WlxDialogBox перетворюється в IWinLogon :: wlxDialogBox. А при звичайній роботі я використовую реалізацію IWinLogon, дейст-вітельно викликає функції з WinLogon. При налагодженні підставляється сурогатна реалізація, у багатьох випадках нічого не робить. Сурогатна реалізація IWinLogon :: wlxDialogBox просто викликає DialogBox. Елементарно, але працює як годинник.

Звичайно, вам знадобиться програма для завантаження GINA і виклику отладочной функції, але це неважко. Ось простий фрагмент коду, що викликає LoadLibrary і GetProcAddress для виклику налагоджувальної версії GINA. Просто скомпілюйте його в EXE-файл і зможете увійти в GINA з відладчика.

void main() {
GetProcAddress(LoadLibrary(“mygina.dll”),
“DebugGINA”)();
}

Але спочатку переконайтеся, що налагодження виконується під обліковим записом SYSTEM для імітації середовища Win-Logon. При частій налагодженні GINA я тримаю відкритої командний рядок під обліковим записом SYSTEM і просто ввожу DEVENV для запуску отладчика, завантаження проекту і трасування.

Як отримати командний рядок під обліковим записом SYSTEM? Один із способів – призначити запуск за розкладом інтерактивного завдання, вказавши CMD.EXE в якості програми:



at 7:32pm /interactive cmd

Звичайно, обраний час повинно бути в найближчому майбутньому, наприклад через одну хвилину. Це змушує планувальник (працює під SYSTEM) запустити командний рядок, успадковують контекст захисту SYSTEM. Відладчик, запущений з такої командного рядка, теж успадкує цей контекст. Командний рядок слід назвати приблизно так (наберіть у командному рядку після її запуску):



title SYSTEM (DANGER, WILL ROBINSON)

Цей дурнувато виглядає заголовок насправді дуже серйозний – командний рядок потрібно закривати після закінчення налагодження, так як SYSTEM має повний контроль над усім на комп’ютері і помилка в такий команд-ної рядку може мати серйозні наслідки.

В наступному випуску цієї рубрики я розгляну деякі більш складні аспекти розробки GINA начебто застосування CreateProcessAsUser для запуску оболонки та інші важливі питання. В кінці серії у вас буде проста, але повнофункціональна реалізація GINA, що підходить для того, щоб почати з неї свою роботу.

Вихідний код можна скачати за посиланням: http://msdn.microsoft.com/msdnmag/code05.aspx.

Питання та коментарі (англійською мовою) надсилайте за адресою briefs@microsoft.com.

Кит Браун (Keith Brown) – співзасновник Pluralsight, спеціалізується на розробці високоякісних курсів навчання для програмістів. Його остання книга “The. NET Developer” s Guide to Windows Security ” доступна по посиланню www.pluralsight.com / keith / book. З ним можна зв’язатися через www.pluralsight.com / keith.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*