From 362d5cd9b6527e4f9d3a3729afbe7cd90486c39d Mon Sep 17 00:00:00 2001 From: Dawid Zamirski Date: Thu, 16 Feb 2017 18:17:26 -0500 Subject: [PATCH 12/16] hivexregedit: allow to pass HIVEX_OPEN_UNSAFE via new --unsafe flag. Also make --export catpure, log and skip over errors when reading subkeys/values so that export in unsafe mode does not abort at first sign of error. (cherry picked from commit 2610b1e089fa84d294f9925342929e3d7408c35b) --- perl/lib/Win/Hivex/Regedit.pm | 59 ++++++++++++++++++++++++++++++++++++++----- regedit/hivexregedit | 20 ++++++++++++--- 2 files changed, 70 insertions(+), 9 deletions(-) diff --git a/perl/lib/Win/Hivex/Regedit.pm b/perl/lib/Win/Hivex/Regedit.pm index 8914f9e..355699e 100644 --- a/perl/lib/Win/Hivex/Regedit.pm +++ b/perl/lib/Win/Hivex/Regedit.pm @@ -67,7 +67,7 @@ package Win::Hivex::Regedit; use strict; use warnings; -use Carp qw(croak confess); +use Carp qw(croak carp confess); use Encode qw(encode decode); require Exporter; @@ -528,19 +528,51 @@ sub reg_export_node print $fh "]\n"; my $unsafe_printable_strings = $params{unsafe_printable_strings}; + my $unsafe = $params{unsafe}; + + my @values; + my @safe_values; # Get the values. - my @values = $h->node_values ($node); + if ($unsafe) { + my $have_vals = 0; + eval { + @values = $h->node_values ($node); + $have_vals = 1; + }; + + if (!$have_vals) { + carp "Failed to read node values at $path"; + } + } else { + @values = $h->node_values ($node); + } foreach (@values) { use bytes; my $key = $h->value_key ($_); - my ($type, $data) = $h->value_value ($_); - $_ = { key => $key, type => $type, data => $data } + my ($type, $data); + + if ($unsafe) { + my $val_ok = 0; + eval { + ($type, $data) = $h->value_value ($_); + $val_ok = 1; + }; + + if (!$val_ok) { + carp "skipping unreadable value of key: $key in $path"; + next; + } + } else { + ($type, $data) = $h->value_value ($_); + } + + push @safe_values, { key => $key, type => $type, data => $data }; } - @values = sort { $a->{key} cmp $b->{key} } @values; + @values = sort { $a->{key} cmp $b->{key} } @safe_values; # Print the values. foreach (@values) { @@ -573,7 +605,22 @@ sub reg_export_node } print $fh "\n"; - my @children = $h->node_children ($node); + my @children; + + if ($unsafe) { + my $have_children = 0; + eval { + @children = $h->node_children ($node); + $have_children = 1; + }; + + if (!$have_children) { + carp "Could not get children of $path"; + } + } else { + @children = $h->node_children ($node); + } + @children = sort { $h->node_name ($a) cmp $h->node_name ($b) } @children; reg_export_node ($h, $_, $fh, @_) foreach @children; } diff --git a/regedit/hivexregedit b/regedit/hivexregedit index 0e534de..aa0ee6e 100755 --- a/regedit/hivexregedit +++ b/regedit/hivexregedit @@ -252,6 +252,17 @@ into another program or stored in another hive. =cut +my $unsafe; + +=item B<--unsafe> + +Use heuristics to tolerate certain levels of corruption within hives. + +This is unsafe but may allow to export/merge valid keys/values in an +othewise corrupted hive. + +=cut + GetOptions ("help|?" => \$help, "debug" => \$debug, "merge|import" => \$merge, @@ -259,6 +270,7 @@ GetOptions ("help|?" => \$help, "prefix=s" => \$prefix, "encoding=s" => \$encoding, "unsafe-printable-strings" => \$unsafe_printable_strings, + "unsafe" => \$unsafe, ) or pod2usage (2); pod2usage (1) if $help; @@ -281,7 +293,8 @@ if ($merge) { # --merge (reg_import) my $hivefile = shift @ARGV; - my $h = Win::Hivex->open ($hivefile, write => 1, debug => $debug); + my $h = Win::Hivex->open ($hivefile, write => 1, debug => $debug, + unsafe => $unsafe); # Read from stdin unless other files have been specified. unshift (@ARGV, '-') unless @ARGV; @@ -312,13 +325,14 @@ if ($merge) { # --merge (reg_import) my $hivefile = shift @ARGV; my $key = shift @ARGV; - my $h = Win::Hivex->open ($hivefile, debug => $debug); + my $h = Win::Hivex->open ($hivefile, debug => $debug, unsafe => $unsafe); print "Windows Registry Editor Version 5.00\n\n"; reg_export ($h, $key, \*STDOUT, prefix => $prefix, - unsafe_printable_strings => $unsafe_printable_strings); + unsafe_printable_strings => $unsafe_printable_strings, + unsafe => $unsafe); } =head1 SEE ALSO -- 1.8.3.1