Keylogger и mousetracker: я должен использовать неблокирующий ввод / вывод? - PullRequest
0 голосов
/ 10 декабря 2018

Я пишу простой кейлоггер / mouselogger на C / C ++ для Windows.Для этого я использую функции Win32 LowLevelMouseProc и LowLevelKeyboardProc.

Если уместно, вот мой GitHub gist с моим кодом, который является ультраэлементарным: определить событиеобратный вызов и зарегистрируйте его вместе с обратным вызовом для SIGINT.Я добавлю обобщенную версию в конце вопроса.

Мой вопрос следующий : чтобы минимизировать накладные расходы, как мне сохранить эти события на диск?

Приветствуются ответы как на C, так и на C ++.

Полезно ли просто записывать в буферизованный файл каждый раз, когда я получаю новое событие, и позволить файлу обрабатывать сброс при заполнении буфера?Я слышал о неблокирующем вводе / выводе, но в документе Microsoft говорится, что есть дополнительные издержки.И, наконец, я не уверен, стоит ли мне создавать для этого второй поток.

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

КОД:

#include "pch.h"
#include <stdio.h>
#include <Windows.h>

HHOOK handle;
LRESULT CALLBACK lowLevelMouseProc(
    _In_ int    nCode,
    _In_ WPARAM wParam,
    _In_ LPARAM lParam
)
{
    MSLLHOOKSTRUCT* lp = (MSLLHOOKSTRUCT*)lParam;
    if (wParam == WM_MOUSEMOVE) {
        // Best way to save pt.x and pt.y to disk?
        printf("%d %d \n", lp->pt.x, lp->pt.y);
    }
    return CallNextHookEx(0, nCode, wParam, lParam);
}

int main()
{
    handle = SetWindowsHookExA(WH_MOUSE_LL, &lowLevelMouseProc, NULL, 0);
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0));
    UnhookWindowsHookEx(handle)
    return 0;
}

1 Ответ

0 голосов
/ 10 декабря 2018

Используйте 2 буфера.Один для записи, один для чтения (сброс на диск).После выполнения какого-либо условия (переполнение буфера, завершение работы программы, ...), поменяйте местами буферы и начните сброс на диск в отдельном потоке.

Это может выглядеть примерно так:

#include <Windows.h>
#include <vector>
#include <thread>
#include <fstream>
#include <atomic>

struct Point
{
    long x, y;
};

class Buffer
{
public:
    Buffer(std::string _file = "log.txt", const size_t _buffer_size = 100000) : buffer_size(_buffer_size), file(_file)
    {
        points1.reserve(_buffer_size);
        points2.reserve(_buffer_size);
    }

    void write(Point p)
    {
        buf->push_back(p);
        if (buf->size() >= buffer_size && !thread_running.load())
            to_disk();
    }

private:
    const size_t buffer_size;
    const std::string file;
    std::atomic<bool> thread_running{ false };
    std::vector<Point> points1, points2;
    std::vector<Point> *buf = &points1, *other = &points2;


    void swap_buffer()
    {
        std::swap(buf, other);
    }

    void to_disk()
    {
        swap_buffer();
        auto tmp_buf = other;
        auto tmp_file = file;
        auto tmp_flag = &thread_running;
        auto fn = [tmp_buf, tmp_file, tmp_flag]() {
            tmp_flag->store(true);
            std::fstream f(tmp_file, std::ios::app);
            for (auto &v : *tmp_buf)
                f << v.x << ' ' << v.y << '\n';
            tmp_buf->clear();
            tmp_flag->store(false);
        };
        std::thread t(fn);
        t.detach();
    }
};
Buffer buffer("log.txt");


HHOOK handle;
LRESULT CALLBACK lowLevelMouseProc(
    _In_ int    nCode,
    _In_ WPARAM wParam,
    _In_ LPARAM lParam
)
{
    MSLLHOOKSTRUCT* lp = (MSLLHOOKSTRUCT*)lParam;
    if (wParam == WM_MOUSEMOVE) {
        buffer.write({ lp->pt.x, lp->pt.y });
    }
    return CallNextHookEx(0, nCode, wParam, lParam);
}

int main()
{
    handle = SetWindowsHookExA(WH_MOUSE_LL, &lowLevelMouseProc, NULL, 0);
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0));
    UnhookWindowsHookEx(handle);
    return 0;
}

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

Примечание: в этом примере обработка ошибок опущена, и время жизни внутренних буферов должно соответственно управляться.

...