mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-08 22:29:33 +00:00
423 lines
11 KiB
Perl
423 lines
11 KiB
Perl
#-----------------------------------------------------------
|
|
# shellbags_test.pl
|
|
#
|
|
#
|
|
# License: GPL v3
|
|
# 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;
|