#!/usr/bin/perl # # Copyright (C) 2006 by Jacob Cunningham. All rights reserved # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE. # IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA, OR PROFITS OR # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #----------------------------------------------------------------------------\ # http://jafat.sourceforge.net # # Version 1.0 #----------------------------------------------------------------------------\ no warnings; use Parse::Win32Registry qw( :REG_ ); use Getopt::Std; getopts("f:thn"); #Parse cmd line opts my $filename = $opt_f; if ((!defined $opt_f) || (defined $opt_h)) { print_usage(); } if (defined $opt_t) { $delim = "\t"; } else { $delim = ","; } # Get to it! my $registry = Parse::Win32Registry->new($filename); my $root_key = $registry->get_root_key; my $software_key = $root_key->get_subkey(".DEFAULT\\Software") || $root_key->get_subkey("Software"); if (!defined($software_key)) { die "Could not locate the Software key\n"; } my $key_name = "Microsoft\\Windows\\CurrentVersion\\Explorer\\UserAssist\\{75048700-EF1F-11D0-9888-006097DEACF9}\\Count"; # Print Header if (!defined $opt_n) { print "Original $delim Unencoded $delim Last Run $delim Times Run\n"; } else { print " Unencoded $delim Last Run $delim Times Run\n"; } if (my $key = $software_key->get_subkey($key_name)) { foreach my $value ($key->get_list_of_values) { # String portion my $value_name = $value->get_name || "(Default)"; # Decode my $unencoded = rot_decode($value_name); # Data portion my $reg_data = $value->get_data_as_string; # Remove Spaces $reg_data =~ s/\s*//g; #Date is MS Time format - Convert to localtime my $msdate = (substr($reg_data,16,16)); # If it's not all 0s if ($msdate !~ /0{16}/) { $msdate = hex(reverse_hex($msdate)); $msdate = MStime_to_unix($msdate); } else { $msdate = ""; } # of times run - Counter is initailized at 0x06, so subtract 5 my $times_run = substr($reg_data,8,8); $times_run = hex(reverse_hex($times_run)); $times_run = ($times_run - 5); if ($times_run < 0) { $times_run = ""; } # Print out results if (!defined $opt_n) { print "$value_name "; print "$delim"; } print " $unencoded"; print "$delim"; print " $msdate"; print "$delim"; print " $times_run\n"; # Re-init vars undef $value_name; undef $reg_data; undef $msdate; undef $times_run; } } #---------------------------------------------------------------------------\ # Decode ROT 13 encoded data sub rot_decode { my $tmp_rot = shift; $tmp_rot =~ tr/[a-zA-Z]/[n-za-mN-ZA-M]/; return($tmp_rot); } #---------------------------------------------------------------------------\ # Print Usage info # sub print_usage { print "\nThis script traverses the \\UserAssist\\{#}\\Count registry entries\n"; print "from NTUSER.DAT files and prints out the program that was run,\n"; print "the date of the last time it was run, and the number of times run.\n"; print "\n $0 \n"; print "\t -h This help info\n"; print "\t -f \n"; print "\t -t [Use Tab delimited output instead of default \",\"]\n"; print "\t -n Supress the output of the original ROT13 encoded value\n\n"; exit; } # #---------------------------------------------------------------------------\ ## Reverse a hex string # sub reverse_hex { my $HEXDATE = shift; my @bytearry=(); my $byte_cnt = 0; my $max_byte_cnt = 8; my $byte_offset = 0; while($byte_cnt < $max_byte_cnt) { my $tmp_str = substr($HEXDATE,$byte_offset,2); push(@bytearry,$tmp_str); $byte_cnt++; $byte_offset+=2; } return join('',reverse(@bytearry)); } #---------------------------------------------------------------------------\ # Convert MS FILETIME to Unix Epoch sub MStime_to_unix { my $mstime_dec = shift; # The number of seconds between Unix/FILETIME epochs my $MSConversion = "11644473600"; #Convert 100ms increments to Seconds. $mstime_dec = ($mstime_dec * .0000001); # Add difference in epochs $mstime_dec-=$MSConversion; # Get localtime my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($mstime_dec); my @weekdays_array = qw(Sun Mon Tue Wed Thur Fri Sat); my @month_array = qw(Jan Feb Mar Apr May Jun Jul Aug Sept Oct Nov Dec); $year += 1900; $mon = sprintf("%02d",$mon); $mday = sprintf("%02d",$mday); $hour = sprintf("%02d",$hour); $min = sprintf("%02d",$min); $sec = sprintf("%02d",$sec); my $datestring = "$weekdays_array[$wday] $month_array[$mon] $mday $year $hour:$min:$sec"; return $datestring; } #---------------------------------------------------------------------------\