>From ee85b03cd26169db067ee917f8f3e4e8ade54f0f Mon Sep 17 00:00:00 2001 From: Richard W.M. Jones Date: Tue, 17 May 2011 09:00:30 +0100 Subject: [PATCH 1/3] virt-win-reg: Don't hard-code the relationship between hive name and path. The crucial change is the tuple that is returned by map_path_to_hive: - my ($hivename, [...]) = map_path_to_hive ($_); + my ($hiveshortname, $hivefile, [...]) = map_path_to_hive ($_); Previously the $hivename was both the name of the hive (eg. "sam"), the name of the local copy in /tmp, and the name of the hive in %systemroot%\system32\config. In the new code, the $hiveshortname (eg. "sam") is still used for the local copy in /tmp, but we return $hivefile which is the full Windows path (eg. "/windows/system32/config/sam"). The purpose of this change is to allow us in future to return hives from other Windows directories, specifically HKEY_USER hives from Windows home directories. Although this is just code motion, it requires some quite extensive changes to virt-win-reg. --- tools/virt-win-reg | 90 ++++++++++++++++++++++++++++----------------------- 1 files changed, 49 insertions(+), 41 deletions(-) diff --git a/tools/virt-win-reg b/tools/virt-win-reg index 210d99f..056ecce 100755 --- a/tools/virt-win-reg +++ b/tools/virt-win-reg @@ -275,7 +275,10 @@ my $systemroot = $g->inspect_get_windows_systemroot ($roots[0]); # Create a working directory to store the downloaded registry files. my $tmpdir = tempdir (CLEANUP => 1); -# Only used when merging to map downloaded hive names to hive handles. +# Used when merging (only) to map from the downloaded hiveshortname to +# various properties about the hive. The key is hiveshortname. The +# value is a hashref containing {h} (hive handle) and {hivefile} (full +# hive path on the Windows side). my %hives; if (!$merge) { # Export mode. @@ -286,24 +289,25 @@ if (!$merge) { # Export mode. my $name = shift @ARGV; # or undef # Map this to the hive name. This function dies on failure. - my ($hivename, $prefix); - ($hivename, $path, $prefix) = map_path_to_hive ($path); + my ($hiveshortname, $hivefile, $prefix); + ($hiveshortname, $hivefile, $path, $prefix) = map_path_to_hive ($path); # Download the chosen hive. - download_hive ($hivename); + download_hive ($hivefile, $hiveshortname); # Open it. - my $h = Win::Hivex->open ("$tmpdir/$hivename", debug => $debug); + my $h = Win::Hivex->open ("$tmpdir/$hiveshortname", debug => $debug); unless ($name) { # Export it. - warn "exporting $path from $hivename with prefix $prefix ..." if $debug; + warn "exporting $path from $hiveshortname with prefix $prefix ..." + if $debug; reg_export ($h, $path, \*STDOUT, prefix => $prefix, unsafe_printable_strings => $unsafe_printable_strings); } else { # Export a single key using hivexget. - my @args = ("hivexget", "$tmpdir/$hivename", $path, $name); + my @args = ("hivexget", "$tmpdir/$hiveshortname", $path, $name); warn "running ", join (" ", @args), " ..." if $debug; system (@args) == 0 or die "hivexget failed: $?" } @@ -320,17 +324,15 @@ else { # Import mode. # Now we've done importing, commit all the hive handles and # close them all. - $_->commit (undef) foreach values %hives; - %hives = (); - - # Look in the tmpdir for all the hive files which have been - # downloaded / modified by the import mapper, and upload - # each one. - opendir my $dh, $tmpdir or die "$tmpdir: $!"; - foreach (readdir $dh) { - unless (/^\./) { - upload_hive ($_) - } + foreach (values %hives) { + my $h = $_->{h}; + delete $_->{h}; + $h->commit (undef); + } + + # Upload all the downloaded hives. + foreach my $hiveshortname (keys %hives) { + upload_hive ($hiveshortname, $hives{$hiveshortname}->{hivefile}) } # Sync everything. @@ -345,18 +347,19 @@ sub import_mapper { local $_ = shift; - my ($hivename, $path, $prefix) = map_path_to_hive ($_); + my ($hiveshortname, $hivefile, $path, $prefix) = map_path_to_hive ($_); # Need to download this hive? - unless (-f "$tmpdir/$hivename") { - download_hive ($hivename); + unless (-f "$tmpdir/$hiveshortname") { + download_hive ($hivefile, $hiveshortname); - my $h = Win::Hivex->open ("$tmpdir/$hivename", + my $h = Win::Hivex->open ("$tmpdir/$hiveshortname", write => 1, debug => $debug); - $hives{$hivename} = $h; + my %hash = ( h => $h, hivefile => $hivefile ); + $hives{$hiveshortname} = \%hash; } - return ($hives{$hivename}, $path); + return ($hives{$hiveshortname}->{h}, $path); } # Given a path, map that to the name of the hive and the true path @@ -364,30 +367,35 @@ sub import_mapper sub map_path_to_hive { local $_ = shift; - my ($hivename, $prefix); + my ($hiveshortname, $hivefile, $prefix); if (/^\\?(?:HKEY_LOCAL_MACHINE|HKLM)\\SAM(\\.*)?$/i) { - $hivename = "sam"; + $hiveshortname = "sam"; + $hivefile = "$systemroot/system32/config/$hiveshortname"; $_ = defined $1 ? $1 : "\\"; $prefix = "HKEY_LOCAL_MACHINE\\SAM"; } elsif (/^\\?(?:HKEY_LOCAL_MACHINE|HKLM)\\SECURITY(\\.*)?$/i) { - $hivename = "security"; + $hiveshortname = "security"; + $hivefile = "$systemroot/system32/config/$hiveshortname"; $_ = defined $1 ? $1 : "\\"; $prefix = "HKEY_LOCAL_MACHINE\\SECURITY"; } elsif (/^\\?(?:HKEY_LOCAL_MACHINE|HKLM)\\SOFTWARE(\\.*)?$/i) { - $hivename = "software"; + $hiveshortname = "software"; + $hivefile = "$systemroot/system32/config/$hiveshortname"; $_ = defined $1 ? $1 : "\\"; $prefix = "HKEY_LOCAL_MACHINE\\SOFTWARE"; } elsif (/^\\?(?:HKEY_LOCAL_MACHINE|HKLM)\\SYSTEM(\\.*)?$/i) { - $hivename = "system"; + $hiveshortname = "system"; + $hivefile = "$systemroot/system32/config/$hiveshortname"; $_ = defined $1 ? $1 : "\\"; $prefix = "HKEY_LOCAL_MACHINE\\SYSTEM"; } elsif (/^\\?(?:HKEY_USERS|HKU)\\.DEFAULT(\\.*)?$/i) { - $hivename = "default"; + $hiveshortname = "default"; + $hivefile = "$systemroot/system32/config/$hiveshortname"; $_ = defined $1 ? $1 : "\\"; $prefix = "HKEY_LOCAL_MACHINE\\.DEFAULT"; } @@ -396,25 +404,25 @@ sub map_path_to_hive p => $_) } - return ($hivename, $_, $prefix); + return ($hiveshortname, $hivefile, $_, $prefix); } # Download a named hive file. Die on failure. sub download_hive { local $_; - my $hivename = shift; + my $hivefile = shift; + my $hiveshortname = shift; - my $winfile_before = "$systemroot/system32/config/$hivename"; my $winfile; - eval { $winfile = $g->case_sensitive_path ($winfile_before); }; + eval { $winfile = $g->case_sensitive_path ($hivefile); }; if ($@) { die __x("virt-win-reg: {p}: file not found in guest: {err}\n", - p => $winfile_before, err => $@); + p => $hivefile, err => $@); } warn "downloading $winfile ..." if $debug; - eval { $g->download ($winfile, "$tmpdir/$hivename"); }; + eval { $g->download ($winfile, "$tmpdir/$hiveshortname"); }; if ($@) { die __x("virt-win-reg: {p}: could not download registry file: {err}\n", p => $winfile, err => $@); @@ -425,18 +433,18 @@ sub download_hive sub upload_hive { local $_; - my $hivename = shift; + my $hiveshortname = shift; + my $hivefile = shift; - my $winfile_before = "$systemroot/system32/config/$hivename"; my $winfile; - eval { $winfile = $g->case_sensitive_path ($winfile_before); }; + eval { $winfile = $g->case_sensitive_path ($hivefile); }; if ($@) { die __x("virt-win-reg: {p}: file not found in guest: {err}\n", - p => $winfile_before, err => $@); + p => $hivefile, err => $@); } warn "uploading $winfile ..." if $debug; - eval { $g->upload ("$tmpdir/$hivename", $winfile); }; + eval { $g->upload ("$tmpdir/$hiveshortname", $winfile); }; if ($@) { die __x("virt-win-reg: {p}: could not upload registry file: {err}\n", p => $winfile, err => $@); -- 1.7.5