From 362d5cd9b6527e4f9d3a3729afbe7cd90486c39d Mon Sep 17 00:00:00 2001
From: Dawid Zamirski <dzamirski@datto.com>
Date: Thu, 16 Feb 2017 18:17:26 -0500
Subject: [PATCH 12/12] 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