Keystroke counter daemon
New here? Learn about Bountify and follow @bountify to get notified of new bounties! x

I'd like to keep track of when I'm at my keyboard and when I'm not. The bounty is for a daemon that records keystrokes (whether they're happening or not), and logs them to a file.

I'd like the format to be the following, output to some reasonable log location:

keyboard <timestamp> <number of keystrokes>
keyboard <timestamp #2> <number of keystrokes>

With some form of adjustable granuality on daemon startup (1 minute intervals seems like a good default)

Adapting an existing keylogger and adding timestamps is one approach I think might work well. No need to worry about any kind of security, this is for personal use only.

If you write an Arch Linux package to install the software I'll tip extra. Other neat extras would include monitoring mouse movement or certain running programs (movie players come to mind).

Edit: One good bet for a keystroke logger is evdev

Take a look at https://whatpulse.org, maybe it is what you want.
iurisilvio over 5 years ago
awarded to tannhauser

Crowdsource coding tasks.

1 Solution


Here is my solution, tested on Arch Linux

Compile with -std=c99, run as root.
Options: -t time_interval : (default 60sec)

-f log_file : (default /etc/keystrokes.log)

-d device : (default /dev/input/event0, should work)

-h : show help

http://www1.datafilehost.com/d/1928a7bf - .tar.gz archive with precompiled ArchLinux package for i686 and sources with PKGBUILD to rebuild it manually.

Source:

#include <stdio.h>
#include <stdlib.h>
#include <linux/input.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>

int main(int argc, char const *argv[])
{
    pid_t pid, sid;
    pid = fork();
    if (pid < 0) 
            exit(EXIT_FAILURE);
     if (pid > 0)
            exit(EXIT_SUCCESS);
    umask(0);

    int itertime = 60; 
    char logname[256] = "/etc/keystrokes.log"; 
    char devicename[100] = "/dev/input/event0";

    for (int i = 1; i < argc; ++i){
        if (!strcmp (argv[i], "-f")){
            strcpy(logname, argv[++i]);
            continue;
        }

        if (!strcmp (argv[i], "-t")){
            itertime = atoi(argv[++i]);
            continue;
        }

        if (!strcmp (argv[i], "-d")){
            strcpy(devicename, argv[++i]);
            continue;                
        }

        if (!strcmp(argv[i], "-h")){    
            printf("Options:\n-t time_interval (default 60sec)\n"
                    "-f log_filename (default /etc/keystroked/keystrokes.log\n"
                    "-d device (default /dev/input/event0, will prob work on Arch Linux)\n"
                    "NOTE! Should be run with root privilegies\n");
            exit(EXIT_SUCCESS);
        }
    }   
    int device = open(devicename, O_RDONLY);

    if (device < 0)
        exit(EXIT_FAILURE);

    long flag = fcntl(device, F_GETFL, 0);
    fcntl(device, F_SETFL, flag | O_NONBLOCK);

    sid = setsid();
    if (sid < 0)
            exit(EXIT_FAILURE);

    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);

    time_t start, end;
    struct input_event ev;
    unsigned long counter = 0;  
    struct tm *loc;
    char buf[100];

    start = time(NULL);
    loc = localtime(&start);
    strftime(buf, sizeof(char)*100 - 1, "%F %T", loc);

    FILE *logfile = fopen(logname, "a");
    fprintf(logfile, "Started %s...\n", buf);
    fclose(logfile);

    while (1) {
        end = time(NULL);
        if (difftime(end, start) < itertime){ 

            int c = read(device, &ev, sizeof(struct input_event));
            if (c >= 0 && ev.type == 1 && ev.value == 1)
                ++counter;

       } else {
            loc = localtime(&end);
            strftime(buf, sizeof(char)*100 - 1, "%F %T", loc);

            logfile = fopen(logname, "a");
            fprintf(logfile, "keyboard %s %ld\n", buf, counter);
            fclose(logfile);

            counter = 0;
            start = time(NULL);         
       }
    }
    close(device);
    exit(EXIT_SUCCESS);
}    
Newbie question: Can this pattern be used for the start of a keylogger?
akshatpradhan over 5 years ago
Yes, and the keylogger is called evdev--no need to go in circles.
vanceza over 5 years ago
Excellent solution. You're welcome to post it to AUR if you want to maintain it. If not, I could instead, although I just won't maintain it. A couple minor points: -it's considered better practice to log to /var than to /etc, which is (theoretically) read-only on some systems. Also, your help documentation doesn't match your actual log file -you could print some error message and abort if the user doesn't have the correct file read + write permissions on startup (or if you're really lazy, check if they're superuser, but that's inaccurate) Arch uses systemd, if you wanted to add standard daemon sugar
vanceza over 5 years ago
https://github.com/vanceza/keystroked Added the systemd daemon script
vanceza over 5 years ago
Suppose I wanted to rewrite this in ruby (only because that's what I'm learning). Could I do that? Would I use something like this http://technofetish.net/repos/buffaloplay/ruby_evdev/doc/
akshatpradhan over 5 years ago
View Timeline