c69fda8e693ef12c55d250692add62eff96d7233
[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 .= "\0"; # Value strings are implicitly ASCIIZ.
289         $data = encode ($encoding, $data);
290     } elsif (m/^str\(([[:xdigit:]]+)\):(".*")$/) {
291         $type = hex ($1);
292         $data = _parse_quoted_string ($2);
293         return undef unless defined $data;
294         $data .= "\0"; # Value strings are implicitly ASCIIZ.
295         $data = encode ($encoding, $data);
296     } elsif (m/^(".*")$/) {
297         $type = 1;
298         $data = _parse_quoted_string ($1);
299         return undef unless defined $data;
300         $data .= "\0"; # Value strings are implicitly ASCIIZ.
301         $data = encode ($encoding, $data);
302     } else {
303         return undef;
304     }
305
306     my %h = ( key => $key, t => $type, value => $data );
307     return \%h;
308 }
309
310 sub _dword_le
311 {
312     pack ("V", $_[0]);
313 }
314
315 sub _data_from_hex_digits
316 {
317     local $_ = shift;
318     s/[,[:space:]]//g;
319     pack ("H*", $_)
320 }
321
322 sub _merge_node
323 {
324     local $_;
325     my $hmap = shift;
326     my $params = shift;
327     my $path = shift;
328     my $newvalues = shift;
329     my $delvalues = shift;
330
331     my $h;
332     ($h, $path) = _map_handle ($hmap, $path);
333
334     my $node = _node_lookup ($h, $path);
335     if (!defined $node) {       # Need to create this node.
336         my $name = $path;
337         $name = $1 if $path =~ /([^\\]+)$/;
338         my $parentpath = $path;
339         $parentpath =~ s/[^\\]+$//;
340         my $parent = _node_lookup ($h, $parentpath);
341         if (!defined $parent) {
342             confess "reg_import: cannot create $path since parent $parentpath does not exist"
343         }
344         $node = $h->node_add_child ($parent, $name);
345     }
346
347     # Get the current set of values at this node.
348     my @values = $h->node_values ($node);
349
350     # Delete values in @delvalues original and values that are going
351     # to be replaced.
352     my @delvalues = @$delvalues;
353     foreach (@$newvalues) {
354         push @delvalues, $_->{key};
355     }
356     @values = grep { ! _imember ($h->value_key ($_), @delvalues) } @values;
357
358     # Get the actual values from the hive.
359     @values = map {
360         my $key = $h->value_key ($_);
361         my ($type, $data) = $h->value_value ($_);
362         my %h = ( key => $key, t => $type, value => $data );
363         $_ = \%h;
364     } @values;
365
366     # Add the new values.
367     push @values, @$newvalues;
368
369     $h->node_set_values ($node, \@values);
370 }
371
372 sub _delete_node
373 {
374     local $_;
375     my $hmap = shift;
376     my $params = shift;
377     my $path = shift;
378
379     my $h;
380     ($h, $path) = _map_handle ($hmap, $path);
381
382     my $node = _node_lookup ($h, $path);
383     # Not an error to delete a non-existant node.
384     return unless defined $node;
385
386     # However you cannot delete the root node.
387     confess "reg_import: the root node of a hive cannot be deleted"
388         if $node == $h->root ();
389
390     $h->node_delete_child ($node);
391 }
392
393 # Call the map function, if necessary.
394 sub _map_handle
395 {
396     local $_; # called function may use this
397     my $hmap = shift;
398     my $path = shift;
399     my $h = $hmap;
400
401     if (ref ($hmap) eq "CODE") {
402         ($h, $path) = &$hmap ($path);
403     }
404     return ($h, $path);
405 }
406
407 sub _imember
408 {
409     local $_;
410     my $item = shift;
411
412     foreach (@_) {
413         return 1 if lc ($_) eq lc ($item);
414     }
415     return 0;
416 }
417
418 sub _unexpected
419 {
420     local $_ = shift;
421     my $lineno = shift;
422
423     "reg_import: parse error: unexpected text found at line $lineno near\n$_"
424 }
425
426 sub _parse_error
427 {
428     local $_ = shift;
429     my $lineno = shift;
430
431     "reg_import: parse error: at line $lineno near\n$_"
432 }
433
434 =head2 reg_export
435
436  reg_export ($h, $key, $fh, [prefix => $prefix]);
437
438 This function exports the registry keys starting at the root
439 C<$key> and recursively downwards into the file handle C<$fh>.
440
441 C<$key> is a case-insensitive path of the node to start from, relative
442 to the root of the hive.  It is an error if this path does not exist.
443 Path elements should be separated by backslash characters.
444
445 C<$prefix> is prefixed to each key name.  The usual use for this is to
446 make key names appear as they would on Windows.  For example the key
447 C<\Foo> in the SOFTWARE Registry, with $prefix
448 C<HKEY_LOCAL_MACHINE\SOFTWARE>, would be written as:
449
450  [HKEY_LOCAL_MACHINE\SOFTWARE\Foo]
451  "Key 1"=...
452  "Key 2"=...
453
454 The output is written as pure 7 bit ASCII, with line endings which are
455 the default for the local host.  You may need to convert the file's
456 encoding using L<iconv(1)> and line endings using L<unix2dos(1)> if
457 sending to a Windows user.  Strings are always encoded as hex bytes.
458 See L</ENCODING STRINGS> below.
459
460 Nodes and keys are sorted alphabetically in the output.
461
462 This function does I<not> print a header.  The real regedit program
463 will print a header like:
464
465  Windows Registry Editor Version 5.00
466
467 followed by a blank line.  (Other headers are possible, see the
468 Wikipedia page on the Windows Registry).  If you want a header, you
469 need to write it out yourself.
470
471 =cut
472
473 sub reg_export
474 {
475     my $h = shift;
476     my $key = shift;
477
478     my $node = _node_lookup ($h, $key);
479     croak "$key: path not found in this hive" unless $node;
480
481     reg_export_node ($h, $node, @_);
482 }
483
484 =head2 reg_export_node
485
486  reg_export_node ($h, $node, $fh, ...);
487
488 This is exactly the same as L</reg_export> except that instead
489 of specifying the path to a key as a string, you pass a hivex
490 library C<$node> handle.
491
492 =cut
493
494 sub reg_export_node
495 {
496     local $_;
497     my $h = shift;
498     my $node = shift;
499     my $fh = shift;
500     my %params = @_;
501
502     confess "reg_export_node: \$node parameter was undef" unless defined $node;
503
504     # Get the canonical path of this node.
505     my $path = _node_canonical_path ($h, $node);
506
507     # Print the path.
508     print $fh "[";
509     my $prefix = $params{prefix};
510     if (defined $prefix) {
511         chop $prefix if substr ($prefix, -1, 1) eq "\\";
512         print $fh $prefix;
513     }
514     print $fh $path;
515     print $fh "]\n";
516
517     # Get the values.
518     my @values = $h->node_values ($node);
519
520     foreach (@values) {
521         use bytes;
522
523         my $key = $h->value_key ($_);
524         my ($type, $data) = $h->value_value ($_);
525         $_ = { key => $key, type => $type, data => $data }
526     }
527
528     @values = sort { $a->{key} cmp $b->{key} } @values;
529
530     # Print the values.
531     foreach (@values) {
532         my $key = $_->{key};
533         my $type = $_->{type};
534         my $data = $_->{data};
535
536         if ($key eq "") {
537             print $fh '@='    # default key
538         } else {
539             print $fh '"', _escape_quotes ($key), '"='
540         }
541
542         if ($type eq 4 && length ($data) == 4) { # only handle dword specially
543             my $dword = unpack ("V", $data);
544             printf $fh "dword:%08x\n", $dword
545         } else {
546             # Encode everything else as hex, see encoding section below.
547             printf $fh "hex(%x):", $type;
548             my $hex = join (",", map { sprintf "%02x", ord } split (//, $data));
549             print $fh "$hex\n"
550         }
551     }
552     print $fh "\n";
553
554     my @children = $h->node_children ($node);
555     @children = sort { $h->node_name ($a) cmp $h->node_name ($b) } @children;
556     reg_export_node ($h, $_, $fh, @_) foreach @children;
557 }
558
559 # Escape " and \ when printing keys.
560 sub _escape_quotes
561 {
562     local $_ = shift;
563     s/\\/\\\\/g;
564     s/"/\\"/g;
565     $_;
566 }
567
568 # Look up a node in the registry starting from the path.
569 # Return undef if it doesn't exist.
570
571 sub _node_lookup
572 {
573     local $_;
574     my $h = shift;
575     my $path = shift;
576
577     my @path = split /\\/, $path;
578     shift @path if @path > 0 && $path[0] eq "";
579
580     my $node = $h->root ();
581     foreach (@path) {
582         $node = $h->node_get_child ($node, $_);
583         return undef unless defined $node;
584     }
585
586     return $node;
587 }
588
589 # Return the canonical path of node in the hive.
590
591 sub _node_canonical_path
592 {
593     local $_;
594     my $h = shift;
595     my $node = shift;
596
597     return "\\" if $node == $h->root ();
598     $_ = $h->node_name ($node);
599     my $parent = $h->node_parent ($node);
600     my $path = _node_canonical_path ($h, $parent);
601     if ($path eq "\\") {
602         return "$path$_"
603     } else {
604         return "$path\\$_"
605     }
606 }
607
608 =head1 ENCODING STRINGS
609
610 The situation with encoding strings in the Registry on Windows is very
611 confused.  There are two main encodings that you would find in the
612 binary (hive) file, 7 bit ASCII and UTF-16LE.  (Other encodings are
613 possible, it's also possible to have arbitrary binary data incorrectly
614 marked with a string type).
615
616 The hive file itself doesn't contain any indication of string
617 encoding.  Windows probably guesses the encoding.
618
619 We think that regedit probably either guesses which encoding to use
620 based on the file encoding, or else has different defaults for
621 different versions of Windows.  Neither choice is appropriate for a
622 tool used in a real operating system.
623
624 When using L</reg_import>, you should specify the default encoding for
625 strings using the C<encoding> parameter.  If not specified, it
626 defaults to UTF-16LE.
627
628 The file itself that is imported should be in the local encoding for
629 files (usually UTF-8 on modern Linux systems).  This means if you
630 receive a regedit file from a Windows system, you may sometimes have
631 to reencode it:
632
633  iconv -f utf-16le -t utf-8 < input.reg | dos2unix > output.reg
634
635 When writing regedit files (L</reg_export>) we bypass this madness
636 completely.  I<All> strings (even pure ASCII) are written as hex bytes
637 so there is no doubt about how they should be encoded when they are
638 read back in.
639
640 =cut
641
642 1;
643
644 =head1 COPYRIGHT
645
646 Copyright (C) 2010 Red Hat Inc.
647
648 =head1 LICENSE
649
650 Please see the file COPYING.LIB for the full license.
651
652 =head1 SEE ALSO
653
654 L<Win::Hivex(3)>,
655 L<hivexregedit(1)>,
656 L<virt-win-reg(1)>,
657 L<iconv(1)>,
658 L<dos2unix(1)>,
659 L<unix2dos(1)>,
660 L<hivex(3)>,
661 L<hivexsh(1)>,
662 L<http://libguestfs.org>,
663 L<Sys::Guestfs(3)>.
664
665 =cut