Win::Hivex::Regedit module for importing and exporting regedit format files.
[hivex.git] / perl / lib / Win / Hivex / Regedit.pm
1 # Win::Hivex::Regedit
2 # Copyright (C) 2009-2010 Red Hat Inc.
3 # Derived from code by Petter Nordahl-Hagen under a compatible license:
4 #   Copyright (c) 1997-2007 Petter Nordahl-Hagen.
5 # Derived from code by Markus Stephany under a compatible license:
6 #   Copyright (c)2000-2004, Markus Stephany.
7 #
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Lesser General Public
10 # License as published by the Free Software Foundation; either
11 # version 2 of the License, or (at your option) any later version.
12 #
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 # Lesser General Public License for more details.
17 #
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with this library; if not, write to the Free Software
20 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
22 =pod
23
24 =head1 NAME
25
26 Win::Hivex::Regedit - Helper for reading and writing regedit format files
27
28 =head1 SYNOPSIS
29
30  use Win::Hivex;
31  use Win::Hivex::Regedit qw(reg_import reg_export);
32  
33  $h = Win::Hivex->open ('SOFTWARE', write => 1);
34  
35  open FILE, "updates.reg";
36  reg_import (\*FILE, $h);
37  $h->commit (undef);
38  
39  reg_export ($h, "\\Microsoft\\Windows NT\\CurrentVersion", \*OUTFILE,
40     prefix => "HKEY_LOCAL_MACHINE\\SOFTWARE");
41
42 =head1 DESCRIPTION
43
44 Win::Hivex::Regedit is a helper library for reading and writing the
45 Windows regedit (or C<.REG>) file format.  This is the textual format
46 that is commonly used on Windows for distributing groups of Windows
47 Registry changes, and this format is read and written by the
48 proprietary C<reg.exe> and C<regedit.exe> programs supplied with
49 Windows.  It is I<not> the same as the binary "hive" format which the
50 hivex library itself can read and write.  Note that the regedit format
51 is not well-specified, and hence deviations can occur between what the
52 Windows program can read/write and what we can read/write.  (Please
53 file bugs for any deviations found).
54
55 Win::Hivex::Regedit is the low-level Perl library.  There is also a
56 command line tool for combining hive files and reg files
57 (L<hivexregedit(1)>).  If you have a Windows virtual machine that you need
58 to merge regedit-format changes into, use the high-level
59 L<virt-win-reg(1)> tool (part of libguestfs tools).
60
61 =head2 FUNCTIONS
62
63 =cut
64
65 package Win::Hivex::Regedit;
66
67 use strict;
68 use warnings;
69
70 use Carp qw(croak confess);
71 use Encode qw(encode);
72
73 require Exporter;
74
75 use vars qw(@EXPORT_OK @ISA);
76
77 @ISA = qw(Exporter);
78 @EXPORT_OK = qw(reg_import reg_export);
79
80 =head2 reg_import
81
82  reg_import ($fh, ($h|$map), [encoding => "UTF-16LE"]);
83
84 This function imports the registry keys from file handle C<$fh> either
85 into the hive C<$h> or via a map function.
86
87 The hive handle C<$h> must have been opened for writing, ie.
88 using the C<write =E<gt> 1> flag to C<Win::Hivex-E<gt>open>.
89
90 In the binary hive file, the first part of the key name (eg.
91 C<HKEY_LOCAL_MACHINE\SOFTWARE>) is not stored.  You just have to know
92 (somehow) that this maps to the C<SOFTWARE> hive.  Therefore if you
93 are given a file containing a mixture of keys that have to be added to
94 different hives, you have to have a way to map these to the hive
95 handles.  This is outside the scope of the hivex library, but if the
96 second argument is a CODEREF (ie. reference to a function) then this
97 C<$map> function is called on each key name:
98
99  map ($keyname)
100  ==> ($h, $keyname)
101
102 As shown, the function should return a pair, hive handle, and the true
103 key name (with the prefix stripped off).  For example:
104
105  sub map {
106    if ($_[0] =~ /^HKEY_LOCAL_MACHINE\\SOFTWARE(.*)/i) {
107      return ($software_h, $1);
108    } else ...
109  }
110
111 C<encoding> is the encoding used by default for strings.  If not
112 specified, this defaults to C<"UTF-16LE">, however we highly advise
113 you to specify it.  See L</ENCODING STRINGS> below.
114
115 As with the regedit program, we merge the new registry keys with
116 existing ones, and new node values with old ones.  You can use the
117 C<-> (minus) character to delete individual keys and values.  This is
118 explained in detail in the Wikipedia page on the Windows Registry.
119
120 Remember you need to call C<$h-E<gt>commit (undef)> on the hivex
121 handle before any changes are written to the hive file.  See
122 L<hivex(3)/WRITING TO HIVE FILES>.
123
124 =cut
125
126 sub reg_import
127 {
128     local $_;
129     my $fh = shift;
130     my $hmap = shift;
131     my %params = @_;
132
133     my $encoding = $params{encoding} || "utf-16le";
134
135     my $state = "outer";
136     my $newnode;
137     my @newvalues;
138     my @delvalues;
139     my $lineno = 0;
140
141     while (<$fh>) {
142         # Join continuation lines.  This is recipe 8.1 from the Perl
143         # Cookbook.  Note we allow spaces after the final \ because
144         # this is fairly common in pasted regedit files.
145         $lineno++;
146         chomp;
147         if (s/\\\s*$//) {
148             $_ .= <$fh>;
149             redo unless eof ($fh);
150         }
151
152         #print STDERR "reg_import: parsing <<<$_>>>\n";
153
154         if ($state eq "outer") {
155             # Ignore blank lines, headers.
156             next if /^\s*$/;
157
158             # .* is needed before Windows Registry Editor Version.. in
159             # order to eat a possible Unicode BOM which regedit writes
160             # there.
161             next if /^.*Windows Registry Editor Version.*/;
162             next if /^REGEDIT/;
163
164             # Ignore comments.
165             next if /^\s*;/;
166
167             # Expect to see [...] or -[...]
168             # to merge or delete a node respectively.
169             if (/^\[(.*)\]\s*$/) {
170                 $state = "inner";
171                 $newnode = $1;
172                 @newvalues = ();
173                 @delvalues = ();
174             } elsif (/^-\[(.*)\]\s*$/) {
175                 _delete_node ($hmap, \%params, $1);
176                 $state = "outer";
177             } else {
178                 croak (_unexpected ($_, $lineno));
179             }
180         } elsif ($state eq "inner") {
181             if (/^(".*)=-\s*$/) { # delete value
182                 my $key = _parse_quoted_string ($_);
183                 croak (_parse_error ($_, $lineno)) unless defined $key;
184                 push @delvalues, $key;
185             } elsif (/^@=-\s*$/) { # delete default key
186                 push @delvalues, "";
187             } elsif (/^".*"=/) { # ordinary value
188                 my $value = _parse_key_value ($_, $encoding);
189                 croak (_parse_error ($_, $lineno)) unless defined $value;
190                 push @newvalues, $value;
191             } elsif (/^@=(.*)/) { # default key
192                 my $value = _parse_value ("", $1, $encoding);
193                 croak (_parse_error ($_, $lineno)) unless defined $value;
194                 push @newvalues, $value;
195             } elsif (/^\s*$/) { # blank line after values
196                 _merge_node ($hmap, \%params, $newnode, \@newvalues, \@delvalues);
197                 $state = "outer";
198             } else {
199                 croak (_unexpected ($_, $lineno));
200             }
201         }
202     } # while
203
204     # Still got a node left over to merge?
205     if ($state eq "inner") {
206         _merge_node ($hmap, \%params, $newnode, \@newvalues, \@delvalues);
207     }
208 }
209
210 sub _parse_key_value
211 {
212     local $_ = shift;
213     my $encoding = shift;
214     my $key;
215     ($key, $_) = _parse_quoted_string ($_);
216     return undef unless defined $key;
217     return undef unless substr ($_, 0, 1) eq "=";
218     return _parse_value ($key, substr ($_, 1), $encoding);
219 }
220
221 # Parse a double-quoted string, returning the string.  \ is used to
222 # escape double-quotes and other backslash characters.
223 #
224 # If called in array context and if there is anything after the quoted
225 # string, it is returned as the second element of the array.
226 #
227 # Returns undef if there was a parse error.
228 sub _parse_quoted_string
229 {
230     local $_ = shift;
231
232     # No initial quote character.
233     return undef if substr ($_, 0, 1) ne "\"";
234
235     my $i;
236     my $out = "";
237     for ($i = 1; $i < length; ++$i) {
238         my $c = substr ($_, $i, 1);
239         if ($c eq "\"") {
240             last
241         } elsif ($c eq "\\") {
242             $i++;
243             $c = substr ($_, $i, 1);
244             $out .= $c;
245         } else {
246             $out .= $c;
247         }
248     }
249
250     # No final quote character.
251     return undef if $i == length;
252
253     $_ = substr ($_, $i+1);
254     if (wantarray) {
255         return ($out, $_);
256     } else {
257         return $out;
258     }
259 }
260
261 # Parse the value, optionally prefixed by a type.
262
263 sub _parse_value
264 {
265     local $_;
266     my $key = shift;
267     $_ = shift;
268     my $encoding = shift;       # default encoding for strings
269
270     my $type;
271     my $data;
272
273     if (m/^dword:([[:xdigit:]]{8})$/) { # DWORD
274         $type = 4;
275         $data = _dword_le (hex ($1));
276     } elsif (m/^hex:(.*)$/) {   # hex digits
277         $type = 3;
278         $data = _data_from_hex_digits ($1);
279         return undef unless defined $data;
280     } elsif (m/^hex\(([[:xdigit:]]+)\):(.*)$/) {   # hex digits
281         $type = hex ($1);
282         $data = _data_from_hex_digits ($2);
283         return undef unless defined $data;
284     } elsif (m/^str:(".*")$/) { # only in Wine fake-registries, I think
285         $type = 1;
286         $data = _parse_quoted_string ($1);
287         return undef unless defined $data;
288         $data = encode ($encoding, $data);
289     } elsif (m/^str\(([[:xdigit:]]+)\):(".*")$/) {
290         $type = hex ($1);
291         $data = _parse_quoted_string ($2);
292         return undef unless defined $data;
293         $data = encode ($encoding, $data);
294     } elsif (m/^(".*")$/) {
295         $type = 1;
296         $data = _parse_quoted_string ($1);
297         return undef unless defined $data;
298         $data = encode ($encoding, $data);
299     } else {
300         return undef;
301     }
302
303     my %h = ( key => $key, t => $type, value => $data );
304     return \%h;
305 }
306
307 sub _dword_le
308 {
309     pack ("V", $_[0]);
310 }
311
312 sub _data_from_hex_digits
313 {
314     local $_ = shift;
315     s/[,[:space:]]//g;
316     pack ("H*", $_)
317 }
318
319 sub _merge_node
320 {
321     local $_;
322     my $hmap = shift;
323     my $params = shift;
324     my $path = shift;
325     my $newvalues = shift;
326     my $delvalues = shift;
327
328     my $h;
329     ($h, $path) = _map_handle ($hmap, $path);
330
331     my $node = _node_lookup ($h, $path);
332     if (!defined $node) {       # Need to create this node.
333         my $name = $path;
334         $name = $1 if $path =~ /([^\\]+)$/;
335         my $parentpath = $path;
336         $parentpath =~ s/[^\\]+$//;
337         my $parent = _node_lookup ($h, $parentpath);
338         if (!defined $parent) {
339             confess "reg_import: cannot create $path since parent $parentpath does not exist"
340         }
341         $node = $h->node_add_child ($parent, $name);
342     }
343
344     # Get the current set of values at this node.
345     my @values = $h->node_values ($node);
346
347     # Delete values in @delvalues original and values that are going
348     # to be replaced.
349     my @delvalues = @$delvalues;
350     foreach (@$newvalues) {
351         push @delvalues, $_->{key};
352     }
353     @values = grep { ! _imember ($h->value_key ($_), @delvalues) } @values;
354
355     # Get the actual values from the hive.
356     @values = map {
357         my $key = $h->value_key ($_);
358         my ($type, $data) = $h->value_value ($_);
359         my %h = ( key => $key, t => $type, value => $data );
360         $_ = \%h;
361     } @values;
362
363     # Add the new values.
364     push @values, @$newvalues;
365
366     $h->node_set_values ($node, \@values);
367 }
368
369 sub _delete_node
370 {
371     local $_;
372     my $hmap = shift;
373     my $params = shift;
374     my $path = shift;
375
376     my $h;
377     ($h, $path) = _map_handle ($hmap, $path);
378
379     my $node = _node_lookup ($h, $path);
380     # Not an error to delete a non-existant node.
381     return unless defined $node;
382
383     # However you cannot delete the root node.
384     confess "reg_import: the root node of a hive cannot be deleted"
385         if $node == $h->root ();
386
387     $h->node_delete_child ($node);
388 }
389
390 # Call the map function, if necessary.
391 sub _map_handle
392 {
393     local $_; # called function may use this
394     my $hmap = shift;
395     my $path = shift;
396     my $h = $hmap;
397
398     if (ref ($hmap) eq "CODE") {
399         ($h, $path) = &$hmap ($path);
400     }
401     return ($h, $path);
402 }
403
404 sub _imember
405 {
406     local $_;
407     my $item = shift;
408
409     foreach (@_) {
410         return 1 if lc ($_) eq lc ($item);
411     }
412     return 0;
413 }
414
415 sub _unexpected
416 {
417     local $_ = shift;
418     my $lineno = shift;
419
420     "reg_import: parse error: unexpected text found at line $lineno near\n$_"
421 }
422
423 sub _parse_error
424 {
425     local $_ = shift;
426     my $lineno = shift;
427
428     "reg_import: parse error: at line $lineno near\n$_"
429 }
430
431 =head2 reg_export
432
433  reg_export ($h, $key, $fh, [prefix => $prefix]);
434
435 This function exports the registry keys starting at the root
436 C<$key> and recursively downwards into the file handle C<$fh>.
437
438 C<$key> is a case-insensitive path of the node to start from, relative
439 to the root of the hive.  It is an error if this path does not exist.
440 Path elements should be separated by backslash characters.
441
442 C<$prefix> is prefixed to each key name.  The usual use for this is to
443 make key names appear as they would on Windows.  For example the key
444 C<\Foo> in the SOFTWARE Registry, with $prefix
445 C<HKEY_LOCAL_MACHINE\SOFTWARE>, would be written as:
446
447  [HKEY_LOCAL_MACHINE\SOFTWARE\Foo]
448  "Key 1"=...
449  "Key 2"=...
450
451 The output is written as pure 7 bit ASCII, with line endings which are
452 the default for the local host.  You may need to convert the file's
453 encoding using L<iconv(1)> and line endings using L<unix2dos(1)> if
454 sending to a Windows user.  Strings are always encoded as hex bytes.
455 See L</ENCODING STRINGS> below.
456
457 Nodes and keys are sorted alphabetically in the output.
458
459 This function does I<not> print a header.  The real regedit program
460 will print a header like:
461
462  Windows Registry Editor Version 5.00
463
464 followed by a blank line.  (Other headers are possible, see the
465 Wikipedia page on the Windows Registry).  If you want a header, you
466 need to write it out yourself.
467
468 =cut
469
470 sub reg_export
471 {
472     my $h = shift;
473     my $key = shift;
474
475     my $node = _node_lookup ($h, $key);
476     croak "$key: path not found in this hive" unless $node;
477
478     reg_export_node ($h, $node, @_);
479 }
480
481 =head2 reg_export_node
482
483  reg_export_node ($h, $node, $fh, ...);
484
485 This is exactly the same as L</reg_export> except that instead
486 of specifying the path to a key as a string, you pass a hivex
487 library C<$node> handle.
488
489 =cut
490
491 sub reg_export_node
492 {
493     local $_;
494     my $h = shift;
495     my $node = shift;
496     my $fh = shift;
497     my %params = @_;
498
499     confess "reg_export_node: \$node parameter was undef" unless defined $node;
500
501     # Get the canonical path of this node.
502     my $path = _node_canonical_path ($h, $node);
503
504     # Print the path.
505     print $fh "[";
506     my $prefix = $params{prefix};
507     if (defined $prefix) {
508         chop $prefix if substr ($prefix, -1, 1) eq "\\";
509         print $fh $prefix;
510     }
511     print $fh $path;
512     print $fh "]\n";
513
514     # Get the values.
515     my @values = $h->node_values ($node);
516
517     foreach (@values) {
518         use bytes;
519
520         my $key = $h->value_key ($_);
521         my ($type, $data) = $h->value_value ($_);
522         $_ = { key => $key, type => $type, data => $data }
523     }
524
525     @values = sort { $a->{key} cmp $b->{key} } @values;
526
527     # Print the values.
528     foreach (@values) {
529         my $key = $_->{key};
530         my $type = $_->{type};
531         my $data = $_->{data};
532
533         if ($key eq "") {
534             print $fh '@='    # default key
535         } else {
536             print $fh '"', _escape_quotes ($key), '"='
537         }
538
539         if ($type eq 4 && length ($data) == 4) { # only handle dword specially
540             my $dword = unpack ("V", $data);
541             printf $fh "dword:%08x\n", $dword
542         } else {
543             # Encode everything else as hex, see encoding section below.
544             printf $fh "hex(%x):", $type;
545             my $hex = join (",", map { sprintf "%02x", ord } split (//, $data));
546             print $fh "$hex\n"
547         }
548     }
549     print $fh "\n";
550
551     my @children = $h->node_children ($node);
552     @children = sort { $h->node_name ($a) cmp $h->node_name ($b) } @children;
553     reg_export_node ($h, $_, $fh, @_) foreach @children;
554 }
555
556 # Escape " and \ when printing keys.
557 sub _escape_quotes
558 {
559     local $_ = shift;
560     s/\\/\\\\/g;
561     s/"/\\"/g;
562     $_;
563 }
564
565 # Look up a node in the registry starting from the path.
566 # Return undef if it doesn't exist.
567
568 sub _node_lookup
569 {
570     local $_;
571     my $h = shift;
572     my $path = shift;
573
574     my @path = split /\\/, $path;
575     shift @path if @path > 0 && $path[0] eq "";
576
577     my $node = $h->root ();
578     foreach (@path) {
579         $node = $h->node_get_child ($node, $_);
580         return undef unless defined $node;
581     }
582
583     return $node;
584 }
585
586 # Return the canonical path of node in the hive.
587
588 sub _node_canonical_path
589 {
590     local $_;
591     my $h = shift;
592     my $node = shift;
593
594     return "\\" if $node == $h->root ();
595     $_ = $h->node_name ($node);
596     my $parent = $h->node_parent ($node);
597     my $path = _node_canonical_path ($h, $parent);
598     if ($path eq "\\") {
599         return "$path$_"
600     } else {
601         return "$path\\$_"
602     }
603 }
604
605 =head1 ENCODING STRINGS
606
607 The situation with encoding strings in the Registry on Windows is very
608 confused.  There are two main encodings that you would find in the
609 binary (hive) file, 7 bit ASCII and UTF-16LE.  (Other encodings are
610 possible, it's also possible to have arbitrary binary data incorrectly
611 marked with a string type).
612
613 The hive file itself doesn't contain any indication of string
614 encoding.  Windows probably guesses the encoding.
615
616 We think that regedit probably either guesses which encoding to use
617 based on the file encoding, or else has different defaults for
618 different versions of Windows.  Neither choice is appropriate for a
619 tool used in a real operating system.
620
621 When using L</reg_import>, you should specify the default encoding for
622 strings using the C<encoding> parameter.  If not specified, it
623 defaults to UTF-16LE.
624
625 The file itself that is imported should be in the local encoding for
626 files (usually UTF-8 on modern Linux systems).  This means if you
627 receive a regedit file from a Windows system, you may sometimes have
628 to reencode it:
629
630  iconv -f utf-16le -t utf-8 < input.reg | dos2unix > output.reg
631
632 When writing regedit files (L</reg_export>) we bypass this madness
633 completely.  I<All> strings (even pure ASCII) are written as hex bytes
634 so there is no doubt about how they should be encoded when they are
635 read back in.
636
637 =cut
638
639 1;
640
641 =head1 COPYRIGHT
642
643 Copyright (C) 2010 Red Hat Inc.
644
645 =head1 LICENSE
646
647 Please see the file COPYING.LIB for the full license.
648
649 =head1 SEE ALSO
650
651 L<Win::Hivex(3)>,
652 L<hivexregedit(1)>,
653 L<virt-win-reg(1)>,
654 L<iconv(1)>,
655 L<dos2unix(1)>,
656 L<unix2dos(1)>,
657 L<hivex(3)>,
658 L<hivexsh(1)>,
659 L<http://libguestfs.org>,
660 L<Sys::Guestfs(3)>.
661
662 =cut