Ripping VSCs – Developer Examples

Tuesday, February 14, 2012 Posted by Corey Harrell
The previous post, Ripping VSCs – Developer Method, provided a detailed explanation about how data can be parsed directly inside Volume Shadow Copies (VSCs). Unlike the Practitioner Method, the Developer Method accessed data directly thereby bypassing the need to go through a symbolic link. The previous post explained how and why it’s possible to programmatically access files in VSCs. Ripping VSCs – Developer Examples picks up where the last post left off by demonstrating how existing scripts can be used to parse data inside VSCs.

The Ripping VSCs – Developer Method made two key points that need to be understood about accessing data in VSCs. The first take away is that to read or parse data directly requires a handle to be opened to the object using the full UNC path. The line below shows how to open a handle to the IE9_main.log file in Volume Shadow Copy 18:

open FILE, \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy18\WINDOWS\IE9_main.log or die $!;

The second take away is that to query information by executing commands against a folder/file's path requires a handle to the object to be opened into a variable. The line below shows how to open a handle to the IE9_main.log file in Volume Shadow Copy 18 into the variable $file:

open ($file, \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy18\WINDOWS\IE9_main.log) or die $!;

To modify or write a script to parse data inside a VSC means one of the handles above has to be used. The easiest way I found to change existing scripts is to identify the points where the script is interacting with an external file. Then change that code to use either a handle or make it avoid executing commands against a file/directory path. This is how I aproached the three scripts discussed in this post.

The scripts I wanted to try to get to work against VSCs are ones I’ve used a lot in the past. I knew what results I should expect so it made things easier to identify any issues I caused. One script already worked against VSCs which was Kristinn Gudjonsson’s (parses Office 2007 metadata). I picked two other scripts to modify because the changes reinforce the two take aways from the The Ripping VSCs – Developer Method post. These scripts were Harlan Carvey’s RegRipper (parses registry hives) and (parses Windows link files). I’m discussing the scripts starting with the one requiring no modifications then progressing to the more difficult changes.

Disclaimer: the modifications being made to these scripts are to demonstrate how they can be altered in order to support examining VSCs. As such, my recommendations for anyone wanting to make these changes for actually casework would be to reach out to Kristinn and Harlan (the authors) for feedback on the best way to alter their scripts. against VSCs is a script to read metadata from Microsoft Office 2007 documents. The script has no options and only takes the file path to the office document. At the time I wrote this post the current version was 0.1 and by default it was able to parse files directly inside VSCs. The picture below shows the script parsing a Word document in VSC 18.

Reviewing the script and identifying where the code interacts with an external file brings you to line 92.

92. # read the parameter (the document)
93. $doc = $ARGV[0];
95. # create a ZIP object
96. $zip = Archive::Zip->new();
98. # read the Word document, that is the ZIP file
99. $zip->read( $doc ) == AZ_OK or die "Unable to open Office file\n";

As the code shows, the file path entered on the command-line is stored in the $doc variable (line 92) and is then read into the ZIP object (line 99). Looking at the module doing this work says “the Archive::Zip module allows a Perl program to create, manipulate, read, and write Zip archive files”. My research identified opening a handle using the IO::File module but the script shows other modules that open files can access VSCs as well.

RegRipper against VSCs

RegRipper is a tool to perform registry analysis in examinations. There is a command-line version ( as well as a version with a GUI. The two switches I’m using in this post are: -r to specific the registry hive and –p to specify a single plugin (note: -f specifies a plug in file). At the time I wrote this post the current version of Regripper was 20090102 and by default it was unable to parse registry hives directly in VSCs. The picture below shows RegRipper failing to parse the UserInfo key in an ntuser.dat hive in VSC 18.

The error reported by RegRipper was that the ntuser.dat registry hive was not found. Opening in a text editor and identifying the point where it interacts with a registry hive brings you to lines 89 and 170. I copied and pasted sections of the code below.

89. if ($config{file}) {
90. # First, check that a hive file was identified, and that the path is
91. # correct
92.      my $hive = $config{reg};
93.      die "You must enter a hive file path/name.\n" if ($hive eq "");
94.      die $hive." not found.\n" unless (-e $hive);

170. if ($config{plugin}) {
171. # First, check that a hive file was identified, and that the path is
172. # correct
173.      my $hive = $config{reg};
174.      die "You must enter a hive file path/name.\n" if ($hive eq "");
175.      die $hive." not found.\n" unless (-e $hive);

The first section (lines 89 to 94) appears to be for when a plugin file is ran (-f switch) while the second section (lines 170 to 175) is for a single plugin file (-p which was ran). Looking at lines 94 and 175 shows the error that appeared when RegRipper failed (ntuser.dat not found). Those two lines are performing an error check to see if the registry hive is present. The issue is the check is performed against a path inside a VSC. Remember the file size issue in the previous post? Commands can’t execute against a path to a VSC since they fail (at least in all my testing). To make RegRipper work with VSCs just make a change to lines 94 and 175. One option is to comment out those lines completely and another option is to remove the –e switch (worked in my testing). For demonstration purposes I commented the lines out. The changed lines are below:

94. # die $hive." not found.\n" unless (-e $hive);

175. # die $hive." not found.\n" unless (-e $hive);

The picture below shows the command is now successful; the modified RegRipper successfully rips the ntuser.dat hive in VSC 18. against VSCs is a script included with WFA 2/e to parse Windows link files. This was the first script I changed to work with VSCs and it was the most difficult one to figure out. The picture below shows failing to parse a link file (Receipt-#4-Walmart-shredder.docx.lnk) in VSC 18.

Looking at the code to see how it interacts with link files shows three areas of interest. The first is the portion where the file entered on the command line is stored in the $file variable (line 16) and a check is performed to see if the file is present (line 17).

16. my $file = shift || die "You must enter a filename.\n";
17. die "$file not found.\n" unless (-e $file);

The second portion is where the stat command is executed against the file path stored in the $file variable (line 65) and then the file path is printed before the file size (line 66)

64. # Get info about the file
65. my ($size,$atime,$mtime,$ctime) = (stat($file))[7,8,9,10];
66. print $file." $size bytes\n";

The third section is where the file stored in the $file variable is opened into the FH filehandle.

71. # Open file in binary mode
72. open(FH,$file) || die "Could not open $file: $!\n";

Those three sections need to be modified in order for to parse VSCs directly. The first change is to comment out line 72 because the filehandle needs to be opened in the beginning of the script. Remember to parse files inside VSCs a handle needs to be used? Here is the line commented out and I added my own comment explaining it.

# (corey) Had to move to first in script to access file in VSC
#open($file,$file) || die "Could not open $file: $!\n";

Continuing with the first change the handle needs to be opened before any actions are taken against the external link file. The script uses the $file variable throughout it so the easiest thing to do is to create a new variable (I picked $file_path). The second change is to comment out the error check against the file path while the third change is to open the file into the $file variable. Below are my changes made to the beginning of the script.

use strict;

# (corey) created variable to store file path. (without it this line won't work print $file." $size bytes\n";)
my $file_path = shift || die "You must enter a filename.\n";

# (corey) line below is not needed because of the line above
# my $file = shift || die "You must enter a filename.\n";

# (corey) added and changed the open command so handle is inside a variable
open(my $file,$file_path) || die "Could not open $file_path: $!\n";

# (corey)Line below caused error even though file opened
#die "$file not found.\n" unless (-e $file);

# Setup some variables

The last change is for reporting purposes. The line printing the file size contains the $file variable. This will cause it to print out a glob of characters instead of the file’s path. My $file_path variable contains the file’s path so it can be used with the print command as shown below.

# (corey) had to change the variable in the line below to print the path to the file
#print $file." $size bytes\n";
print "$file_path"." $size bytes\n";

In summary, the changes made were to make open a file handle into a variable in order to access a file inside a VSC. The other changes were to avoid executing a command against the file’s path (error check) and to change a variable to show the file path. The end result; is now to able successfully parse the link file (Receipt-#4-Walmart-shredder.docx.lnk) in VSC 18.

Next and Last Post in Series: Examining VSCs with GUI Tools
  1. Nice work Corey. Thanks for sharing your research. Im going to integrate this stuff into my scripts.


  2. Are you talking about your Python scripts? If so, I' am curious if you can replicate accessing VSCs directly like I did with Perl. I assumed its possible but it would be cool to know for sure.

  3. Corey,
    Not sure if you've seen this blog yet...

    He doesn't post real often, but thought I'd bring him to your attention.

Post a Comment