简体   繁体   中英

Keylogger and mousetracker: should I use non-blocking I/O?

I'm writing a simple keylogger/mouselogger in C/C++ for Windows. To do that, I use the Win32 functions LowLevelMouseProc and LowLevelKeyboardProc .

If relevant, here is a GitHub gist with my code, which is ultra-elementary: define the event callback and register it along with a callback for SIGINT. I'll add a summarized version at the end of the question.

My question is the following : in order to minimize overhead, how should I save these events to disk?

Answers in both C or C++ are welcome.

Is it a good practice to simply write to a buffered file each time I get a new event and let the file handle flushing when the buffer is full? I heard about non-blocking I/O but microsoft's doc says that there is an additional overhead. And finally, I'm not sure wether I should create a second thread for this.

I'd like to use some sort of buffering to avoid many little disk I/O. Ideally I would write to disk once before my process is killed. But I have no idea how to achieve this.

CODE:

#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;
}

Use 2 buffers. One for writing, one for reading (flushing to disk). Once some condition is met (buffer full, program shutdown, ...), swap the buffers and start flushing to disk in a seperate thread.

This might look something like:

#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;
}

In this case, the buffer gets written to disk when a certain size limit is reached. This could be further optimized, by not checking the size on every write for example.

Note: In this example, error handling is omitted and the lifetime of the internal buffers should be managed accordingly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM