Building a Better Keylogger

April 24, 2011 by Noah
As some of you may or may not have known, in the past I wrote a keylogger in Perl for Linux systems. The purpose was to see what my significant other was doing to my computer while I was away from it, and certainly not to log passwords and things that malicious people use keyloggers for. I posted the source code to it here with the express disclaimer that it should be used only for educational purposes. ;)

Well, that keylogger had its problems. Although it had a couple of pros in there too compared to my new keylogger. The problem it had was that it required you to have root privileges on the Linux system you run it on, because it needed to read from /dev/input/* devices directly, which only the root user has permission to do. It also needed you to figure out which device node to read from ahead of time. And finally, it didn't work on some types of keyboards (I only tested it with a USB keyboard but I've heard reports from others that it just doesn't work for them).

The only pro it had was that it would log keys at the hardware level, including on text mode terminals.

Enter the New Keylogger

After reading this blog post about GUI isolation in *nix, I found out the trick to reading keys in the X Window System without root privileges. So, I wrote a new keylogger to take advantage of this new information I learned.

And so, the new keylogger does not require root privileges! The new keylogger relies on the X Window System, though, but this is the de facto windowing system on just about every Linux/Unix system out there today. This also means it will only log keys entered into graphical applications (for desktop *nix users though, this would log keys for just about everybody) so users in a text-mode terminal won't be logged.

One issue I ran into though is that the xinput test command seems to expect you to have a terminal (or TTY), i.e. that you run the command from a graphical terminal. So trying to read the output of this command in Perl caused some weird buffering issue, where the command wouldn't give any output until about 100 characters were typed. So, the script requires the IO::Pty::Easy module which creates a virtual TTY so that xinput believes you're running it from a real shell.

The new keylogger's source code can be found here. Have fun! :)

More Ideas

They say that the Qubes system isn't vulnerable to this. In Qubes you basically set up different "security zones" for your various apps, to prevent the apps from messing with each other. On the back end it seems that it just uses multiple X servers to partition off the various zones. I have an idea how my keylogger could defeat even this...

When run from a graphical terminal, the $DISPLAY environment variable is already set to your current X display, e.g. ":0.0". But when launched from a non-graphical environment, the script would need to set the value of $DISPLAY itself, in order for xinput to know which X server to connect to.

Well, maybe if the keylogger changes up the value of $DISPLAY to log from different X servers it may be able to cross the partitions set up by Qubes. I'll have to investigate this further. (6)



There are 3 comments on this page. Add yours.

Avatar image
ammonite posted on November 17, 2011 @ 21:21 UTC


mapped for my azerty keyboard

Avatar image
crossfire posted on March 5, 2012 @ 06:17 UTC

i want to be free

Avatar image
morad posted on January 3, 2013 @ 15:29 UTC


Add a Comment

Used for your Gravatar and optional thread subscription. Privacy policy.
You may format your message using GitHub Flavored Markdown syntax.