Mark McKinnon a102b6ff90 Update regripper plugins
Update the plugins with Wills PR change on the regripper repo that has not been merged as of yet. PR on Regripper repo is https://github.com/keydet89/RegRipper2.8/pull/31
2020-05-19 15:06:59 -04:00

423 lines
11 KiB
Perl

#-----------------------------------------------------------
# shellbags_test.pl
#
#
#
# copyright 2012 Quantum Analytics Research, LLC
# Author: H. Carvey, keydet89@yahoo.com
#-----------------------------------------------------------
package shellbags_test;
use strict;
require 'shellitems.pl';
my %config = (hive => "USRCLASS\.DAT",
hivemask => 32,
output => "report",
category => "User Activity",
osmask => 20, #Vista, Win7/Win2008R2
hasShortDescr => 1,
hasDescr => 0,
hasRefs => 0,
version => 20130528);
sub getConfig{return %config}
sub getShortDescr {
return "Shell/BagMRU traversal in XP/Win7 user hives";
}
sub getDescr{}
sub getRefs {}
sub getHive {return $config{hive};}
sub getVersion {return $config{version};}
my $VERSION = getVersion();
my %item = ();
my $XP = 0;
my $root_key;
sub pluginmain {
my $class = shift;
my $hive = shift;
::logMsg("Launching shellbags_test v.".$VERSION);
::rptMsg("shellbags_test v.".$VERSION); # banner
::rptMsg("(".getHive().") ".getShortDescr()."\n"); # banner
my $reg = Parse::Win32Registry->new($hive);
$root_key = $reg->get_root_key;
my %paths = ("Win7" => "Local Settings\\Software\\Microsoft\\Windows\\Shell\\BagMRU",
"XP" => "Software\\Microsoft\\Windows\\ShellNoRoam\\BagMRU");
my $key;
if ($key = $root_key->get_subkey($paths{"Win7"})) {
setup($key);
}
elsif ($key = $root_key->get_subkey($paths{"XP"})) {
$XP = 1;
setup($key);
}
}
sub setup {
my $key = shift;
($XP == 1) ? ($item{path} = "ShellNoRoam\\BagMRU\\") : ($item{path} = "Shell\\BagMRU\\");
$item{name} = "Desktop\\";
# Print header info
::rptMsg(sprintf "%-20s |%-20s | %-20s | %-20s | %-20s |Resource","MRU Time","Modified","Accessed","Created","Zip_Subfolder");
::rptMsg(sprintf "%-20s |%-20s | %-20s | %-20s | %-20s |"."-" x 12,"-" x 12,"-" x 12,"-" x 12,"-" x 12,"-" x 12);
traverse($key,\%item);
}
sub traverse {
my $key = shift;
my $parent = shift;
my %item = ();
my @vals = $key->get_list_of_values();
my %values;
foreach my $v (@vals) {
my $name = $v->get_name();
$values{$name} = $v->get_data();
}
my $mru;
if (exists $values{MRUListEx}) {
$mru = unpack("V",substr($values{MRUListEx},0,4));
}
delete $values{MRUListEx};
foreach my $v (sort {$a <=> $b} keys %values) {
next unless ($v =~ m/^\d/);
my $nodeslot = "";
eval {
$nodeslot = $key->get_subkey($v)->get_value("NodeSlot")->get_data();
};
my $type = unpack("C",substr($values{$v},2,1));
my $size = unpack("v",substr($values{$v},0,2));
# probe($values{$v});
# Need to first check to see if the parent of the item was a zip folder
# and if the 'zipsubfolder' value is set to 1
if (exists ${$parent}{zipsubfolder} && ${$parent}{zipsubfolder} == 1) {
if ($XP == 0) {
%item = parseZipSubFolderItem($values{$v});
$item{zipsubfolder} = 1;
}
}
elsif (length($values{$v}) == 22 && $type != 0x47) {
$item{name} = parseGUID(substr($values{$v},4,16));
}
elsif (substr($values{$v},0x0d,2) =~ m/\x3a\x3a/){
%item = parseXPShellDeviceItem($values{$v});
}
elsif ($type == 0x00) {
# Variable/Property Sheet
%item = parseVariableEntry($values{$v});
}
elsif ($type == 0x01) {
#
%item = parse01ShellItem($values{$v});
}
elsif ($type == 0x1F) {
# System Folder
%item = parseSystemFolderEntry($values{$v});
}
elsif ($type == 0x2e) {
# Device
%item = parseDeviceEntry($values{$v});
}
elsif ($type == 0x2F) {
# Volume (Drive Letter)
%item = parseDriveEntry($values{$v});
}
elsif ($type == 0xc3 || $type == 0x41 || $type == 0x42 || $type == 0x46 || $type == 0x47) {
# Network stuff
my $id = unpack("C",substr($values{$v},3,1));
if ($type == 0xc3 && $id != 0x01) {
%item = parseNetworkEntry($values{$v});
}
else {
%item = parseNetworkEntry($values{$v});
}
}
elsif ($type == 0x31 || $type == 0x32 || $type == 0xb1 || $type == 0x74) {
# Folder or Zip File
%item = parseFolderEntry($values{$v});
# if (exists $item{mft_rec_num}) {
# print "MFT record number : ".$item{mft_rec_num}."\n";
# print "MFT sequence number: ".$item{mft_seq_num}."\n";
# }
# probe($values{$v});
}
elsif ($type == 0x35) {
%item = parseFolderEntry2($values{$v});
}
elsif ($type == 0x64 || $type == 0x65 || $type == 0x69) {
%item = parseType64Item($values{$v});
}
elsif ($type == 0x71) {
# Control Panel
if ($size == 0x1e) {
%item = parseControlPanelEntry($values{$v});
}
else {
$item{name} = parseGUID(substr($values{$v},0xe,16));
}
}
elsif ($type == 0x61) {
# URI type
%item = parseURIEntry($values{$v});
}
elsif ($type == 0x53) {
%item = parseTypex53($values{$v});
}
else {
# Unknown type
$item{name} = sprintf "Unknown Type (0x%x)",$type;
# probe($values{$v});
}
if ($type == 0x32) {
if (lc($item{name}) =~ m/\.zip$/) {
$item{zipsubfolder} = 1;
}
}
# for debug purposes
# $item{name} = $item{name}."[".$v."]";
# ::rptMsg(${$parent}{path}.$item{name});
if ($mru != 4294967295 && ($v == $mru)) {
$item{mrutime} = $key->get_timestamp();
$item{mrutime_str} = $key->get_timestamp_as_string();
$item{mrutime_str} =~ s/T/ /;
$item{mrutime_str} =~ s/Z/ /;
}
else {
$item{mrutime_str} = "";
}
my ($m,$a,$c,$o) = "";
(exists $item{mtime_str} && $item{mtime_str} ne "0") ? ($m = $item{mtime_str}) : ($m = "");
(exists $item{atime_str} && $item{atime_str} ne "0") ? ($a = $item{atime_str}) : ($a = "");
(exists $item{ctime_str} && $item{ctime_str} ne "0") ? ($c = $item{ctime_str}) : ($c = "");
(exists $item{datetime} && $item{datetime} ne "N/A") ? ($o = $item{datetime}) : ($o = "");
if ($item{name} eq "" || $item{name} =~ m/\\$/) {
}
else {
$item{name} = $item{name}."\\";
}
$item{name} = ${$parent}{name}.$item{name};
$item{path} = ${$parent}{path}.$v."\\";
my $resource = $item{name};
if (exists $item{filesize}) {
$resource .= " [".$item{filesize}."]";
}
my $str = sprintf "%-20s |%-20s | %-20s | %-20s | %-20s |".$resource." [".$item{path}."]",$item{mrutime_str},$m,$a,$c,$o;
::rptMsg($str);
# For XP, check NodeSlot value
if ($XP == 1 && $nodeslot ne "") {
my %itempos = getItemPos($nodeslot);
if (scalar(keys %itempos) > 0) {
foreach my $name (keys %itempos) {
my $n = $name;
$n .= " [".$itempos{$name}{size}."]" if ($itempos{$name}{size} ne "");
$n .= " [ShellNoRoam\\Bags\\".$nodeslot."\\Shell\\".$itempos{$name}{itempos}."]";
my $str = sprintf "%-20s |%-20s | %-20s | %-20s | %-20s | ","",$itempos{$name}{mtime_str},$itempos{$name}{atime_str},$itempos{$name}{ctime_str},"";
::rptMsg($str.$n);
}
}
}
traverse($key->get_subkey($v),\%item);
}
}
#-----------------------------------------------------------
# getItemPos()
#-----------------------------------------------------------
sub getItemPos {
my $nodeslot = shift;
my %item = ();
my $key_path = "Software\\Microsoft\\Windows\\ShellNoRoam\\Bags\\".$nodeslot."\\Shell";
my $key;
if ($key = $root_key->get_subkey($key_path)) {
my @vals = $key->get_list_of_values();
if (scalar(@vals) > 0) {
foreach my $v (@vals) {
my $name = $v->get_name();
if ($name =~ m/^ItemPos/) {
%item = parseBagEntry($v->get_data(),$name);
}
}
}
}
else {
::rptMsg($key_path." not found\.");
}
return %item;
}
#-----------------------------------------------------------
# parseBagEntry()
#-----------------------------------------------------------
sub parseBagEntry {
my $data = shift;
my $name = shift;
my $ofs = 24;
my $len = length($data);
my %bag = ();
while ($ofs < $len) {
my %item = ();
my $sz = unpack("v",substr($data,$ofs,2));
my $dat = substr($data,$ofs,$sz);
my $type = unpack("C",substr($dat,2,1));
if ($type == 0x1f) {
%item = parseSystemBagItem($dat);
$bag{$item{name}}{itempos} = $name;
$bag{$item{name}}{mtime_str} = "";
$bag{$item{name}}{atime_str} = "";
$bag{$item{name}}{ctime_str} = "";
$bag{$item{name}}{size} = "";
}
elsif ($type == 0x31 || $type == 0x32 || $type == 0x3a) {
%item = parseFolderItem($dat);
$bag{$item{name}}{itempos} = $name;
(exists $item{mtime_str} && $item{mtime_str} ne "0") ? ($bag{$item{name}}{mtime_str} = $item{mtime_str}) : ($bag{$item{name}}{mtime_str} = "");
(exists $item{atime_str} && $item{atime_str} ne "0") ? ($bag{$item{name}}{atime_str} = $item{atime_str}) : ($bag{$item{name}}{atime_str} = "");
(exists $item{ctime_str} && $item{ctime_str} ne "0") ? ($bag{$item{name}}{ctime_str} = $item{ctime_str}) : ($bag{$item{name}}{ctime_str} = "");
$bag{$item{name}}{size} = $item{size};
}
else {
}
$ofs += $sz + 8;
}
return %bag;
}
#-----------------------------------------------------------
# parseSystemBagItem()
#-----------------------------------------------------------
sub parseSystemBagItem {
my $data = shift;
my %item = ();
my %vals = (0x00 => "Explorer",
0x42 => "Libraries",
0x44 => "Users",
0x4c => "Public",
0x48 => "My Documents",
0x50 => "My Computer",
0x58 => "My Network Places",
0x60 => "Recycle Bin",
0x68 => "Explorer",
0x70 => "Control Panel",
0x78 => "Recycle Bin",
0x80 => "My Games");
$item{type} = unpack("C",substr($data,2,1));
$item{id} = unpack("C",substr($data,3,1));
if (exists $vals{$item{id}}) {
$item{name} = $vals{$item{id}};
}
else {
$item{name} = parseGUID(substr($data,4,16));
}
return %item;
}
#-----------------------------------------------------------
# parseFolderItem()
#-----------------------------------------------------------
sub parseFolderItem {
my $data = shift;
my %item = ();
my $ofs_mdate = 0x08;
$item{type} = unpack("C",substr($data,2,1));
$item{size} = unpack("V",substr($data,4,4));
my @m = unpack("vv",substr($data,$ofs_mdate,4));
($item{mtime_str},$item{mtime}) = convertDOSDate($m[0],$m[1]);
my $ofs_shortname = $ofs_mdate + 6;
my $tag = 1;
my $cnt = 0;
my $str = "";
while($tag) {
my $s = substr($data,$ofs_shortname + $cnt,1);
return %item unless (defined $s);
if ($s =~ m/\x00/ && ((($cnt + 1) % 2) == 0)) {
$tag = 0;
}
else {
$str .= $s;
$cnt++;
}
}
# $str =~ s/\x00//g;
my $shortname = $str;
my $ofs = $ofs_shortname + $cnt + 1;
# Read progressively, 1 byte at a time, looking for 0xbeef
$tag = 1;
$cnt = 0;
while ($tag) {
my $s = substr($data,$ofs + $cnt,2);
return %item unless (defined $s);
if (unpack("v",$s) == 0xbeef) {
$tag = 0;
}
else {
$cnt++;
}
}
$item{extver} = unpack("v",substr($data,$ofs + $cnt - 4,2));
$ofs = $ofs + $cnt + 2;
@m = unpack("vv",substr($data,$ofs,4));
($item{ctime_str},$item{ctime}) = convertDOSDate($m[0],$m[1]);
$ofs += 4;
@m = unpack("vv",substr($data,$ofs,4));
($item{atime_str},$item{atime}) = convertDOSDate($m[0],$m[1]);
my $jmp;
if ($item{extver} == 0x03) {
$jmp = 8;
}
elsif ($item{extver} == 0x07) {
$jmp = 26;
}
elsif ($item{extver} == 0x08) {
$jmp = 30;
}
else {}
$ofs += $jmp;
$str = substr($data,$ofs,length($data) - $ofs);
my $longname = (split(/\x00\x00/,$str,2))[0];
$longname =~ s/\x00//g;
if ($longname ne "") {
$item{name} = $longname;
}
else {
$item{name} = $shortname;
}
return %item;
}
1;