3 # Copyright (C) 2010 Red Hat Inc.
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 use Sys::Guestfs::Lib qw(open_guest get_partitions resolve_windows_path
24 inspect_all_partitions inspect_partition
25 inspect_operating_systems mount_operating_system);
27 use Win::Hivex::Regedit qw(reg_import reg_export);
31 use File::Temp qw/tempdir/;
32 use Locale::TextDomain 'libguestfs';
38 virt-win-reg - Export and merge Windows Registry entries from a Windows guest
42 virt-win-reg domname 'HKLM\Path\To\Subkey'
44 virt-win-reg domname 'HKLM\Path\To\Subkey' name
46 virt-win-reg domname 'HKLM\Path\To\Subkey' @
48 virt-win-reg --merge domname [input.reg ...]
50 virt-win-reg [--options] disk.img ... # instead of domname
54 You must I<not> use C<virt-win-reg> with the C<--merge> option on live
55 virtual machines. If you do this, you I<will> get irreversible disk
56 corruption in the VM. C<virt-win-reg> tries to stop you from doing
57 this, but doesn't catch all cases.
59 Modifying the Windows Registry is an inherently risky operation. The format
60 is deliberately obscure and undocumented, and Registry changes
61 can leave the system unbootable. Therefore when using the C<--merge>
62 option, make sure you have a reliable backup first.
66 This program can export and merge Windows Registry entries from a
69 The first parameter is the libvirt guest name or the raw disk image of
72 If C<--merge> is I<not> specified, then the chosen registry
73 key is displayed/exported (recursively). For example:
75 $ virt-win-reg Windows7 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft'
77 You can also display single values from within registry keys,
80 $ cvkey='HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion'
81 $ virt-win-reg Windows7 $cvkey ProductName
84 With C<--merge>, you can merge a textual regedit file into
87 $ virt-win-reg --merge Windows7 changes.reg
89 =head2 SUPPORTED SYSTEMS
91 The program currently supports Windows NT-derived guests starting with
92 Windows XP through to at least Windows 7.
94 Registry support is done for C<HKEY_LOCAL_MACHINE\SAM>,
95 C<HKEY_LOCAL_MACHINE\SECURITY>, C<HKEY_LOCAL_MACHINE\SOFTWARE>,
96 C<HKEY_LOCAL_MACHINE\SYSTEM> and C<HKEY_USERS\.DEFAULT>.
98 You can use C<HKLM> as a shorthand for C<HKEY_LOCAL_MACHINE>, and
99 C<HKU> for C<HKEY_USERS>.
101 C<HKEY_USERS\$SID> and C<HKEY_CURRENT_USER> are B<not> supported at
106 This program is only meant for simple access to the registry. If you
107 want to do complicated things with the registry, we suggest you
108 download the Registry hive files from the guest using L<libguestfs(3)>
109 or L<guestfish(1)> and access them locally, eg. using L<hivex(3)>,
110 L<hivexsh(1)> or L<hivexregedit(1)>.
114 C<virt-win-reg> expects that regedit files have already been reencoded
115 in the local encoding. Usually on Linux hosts, this means UTF-8 with
116 Unix-style line endings. Since Windows regedit files are often in
117 UTF-16LE with Windows-style line endings, you may need to reencode the
118 whole file before or after processing.
120 To reencode a file from Windows format to Linux (before processing it
121 with the C<--merge> option), you would do something like this:
123 iconv -f utf-16le -t utf-8 < win.reg | dos2unix > linux.reg
125 To go in the opposite direction, after exporting and before sending
126 the file to a Windows user, do something like this:
128 unix2dos linux.reg | iconv -f utf-8 -t utf-16le > win.reg
130 For more information about encoding, see L<Win::Hivex::Regedit(3)>.
132 If you are unsure about the current encoding, use the L<file(1)>
133 command. Recent versions of Windows regedit.exe produce a UTF-16LE
134 file with Windows-style (CRLF) line endings, like this:
137 software.reg: Little-endian UTF-16 Unicode text, with very long lines,
138 with CRLF line terminators
140 This file would need conversion before you could C<--merge> it.
144 Be careful when passing parameters containing C<\> (backslash) in the
145 shell. Usually you will have to use 'single quotes' or double
146 backslashes (but not both) to protect them from the shell.
148 Paths and value names are case-insensitive.
150 =head2 CurrentControlSet etc.
152 Registry keys like C<CurrentControlSet> don't really exist in the
153 Windows Registry at the level of the hive file, and therefore you
156 C<CurrentControlSet> is usually an alias for C<ControlSet001>. In
157 some circumstances it might refer to another control set. The way
158 to find out is to look at the C<HKLM\SYSTEM\Select> key:
160 # virt-win-reg WindowsGuest 'HKLM\SYSTEM\Select'
161 [HKEY_LOCAL_MACHINE\SYSTEM\Select]
162 "Current"=dword:00000001
163 "Default"=dword:00000001
164 "Failed"=dword:00000000
165 "LastKnownGood"=dword:00000002
167 "Default" is the one which Windows will choose when it boots.
169 Similarly, other C<Current...> keys in the path may need to
190 Display version number and exit.
198 Enable debugging messages.
204 =item B<--connect URI> | B<-c URI>
206 If using libvirt, connect to the given I<URI>. If omitted, then we
207 connect to the default libvirt hypervisor.
209 If you specify guest block devices directly, then libvirt is not used
216 =item B<--format> raw
218 Specify the format of disk images given on the command line. If this
219 is omitted then the format is autodetected from the content of the
222 If disk images are requested from libvirt, then this program asks
223 libvirt for this information. In this case, the value of the format
224 parameter is ignored.
226 If working with untrusted raw-format guest disk images, you should
227 ensure the format is always specified.
235 In merge mode, this merges a textual regedit file into the Windows
236 Registry of the virtual machine. If this flag is I<not> given then
237 virt-win-reg displays or exports Registry entries instead.
239 Note that C<--merge> is I<unsafe> to use on live virtual machines, and
240 will result in disk corruption. However exporting (without this flag)
247 =item B<--encoding> UTF-16LE|ASCII
249 When merging (only), you may need to specify the encoding for strings
250 to be used in the hive file. This is explained in detail in
251 L<Win::Hivex::Regedit(3)/ENCODING STRINGS>.
253 The default is to use UTF-16LE, which should work with recent versions
260 GetOptions ("help|?" => \$help,
261 "version" => \$version,
262 "connect|c=s" => \$uri,
263 "debug|d" => \$debug,
264 "format=s" => \$format,
266 "encoding=s" => \$encoding,
268 pod2usage (1) if $help;
270 my $g = Sys::Guestfs->new ();
271 my %h = $g->version ();
272 print "$h{major}.$h{minor}.$h{release}$h{extra}\n";
276 # virt-win-reg only takes a single disk image ...
277 die __"no libvirt domain name or disk image given\n" if @ARGV == 0;
278 my $domname_or_image = shift @ARGV;
280 warn "launching libguestfs ..." if $debug;
282 my @lib_args = ([$domname_or_image]);
283 push @lib_args, address => $uri if $uri;
284 push @lib_args, rw => 1 if $merge;
285 push @lib_args, format => $format if defined $format;
286 my $g = open_guest (@lib_args);
289 warn "inspecting guest ..." if $debug;
291 # List of possible filesystems.
292 my @partitions = get_partitions ($g);
294 # Now query each one to build up a picture of what's in it.
296 inspect_all_partitions ($g, \@partitions,
297 use_windows_registry => 0);
299 my $oses = inspect_operating_systems ($g, \%fses);
301 my @roots = keys %$oses;
302 die __"multiboot operating systems are not supported by virt-win-reg" if @roots > 1;
303 my $root_dev = $roots[0];
305 my $os = $oses->{$root_dev};
306 my $ro = $merge ? 0 : 1;
307 mount_operating_system ($g, $os, $ro);
309 # Create a working directory to store the downloaded registry files.
310 my $tmpdir = tempdir (CLEANUP => 1);
312 # Only used when merging to map downloaded hive names to hive handles.
315 if (!$merge) { # Export mode.
316 die __"expecting 1 or 2 more parameters, subkey path and optionally the value to export\n"
317 if @ARGV < 1 || @ARGV > 2;
319 my $path = shift @ARGV;
320 my $name = shift @ARGV; # or undef
322 # Map this to the hive name. This function dies on failure.
323 my ($hivename, $prefix);
324 ($hivename, $path, $prefix) = map_path_to_hive ($path);
326 # Download the chosen hive.
327 download_hive ($hivename);
330 my $h = Win::Hivex->open ("$tmpdir/$hivename", debug => $debug);
334 warn "exporting $path from $hivename with prefix $prefix ..." if $debug;
335 reg_export ($h, $path, \*STDOUT, prefix => $prefix);
337 # Export a single key using hivexget.
338 my @args = ("hivexget", "$tmpdir/$hivename", $path, $name);
339 warn "running ", join (" ", @args), " ..." if $debug;
340 system (@args) == 0 or die "hivexget failed: $?"
343 else { # Import mode.
345 reg_import (\*STDIN, \&import_mapper, encoding => $encoding);
348 open my $fh, $_ or die "open: $_: $!";
349 reg_import ($fh, \&import_mapper, encoding => $encoding);
353 # Now we've done importing, commit all the hive handles and
355 $_->commit (undef) foreach values %hives;
358 # Look in the tmpdir for all the hive files which have been
359 # downloaded / modified by the import mapper, and upload
361 opendir my $dh, $tmpdir or die "$tmpdir: $!";
362 foreach (readdir $dh) {
375 # map function passed to reg_import.
380 my ($hivename, $path, $prefix) = map_path_to_hive ($_);
382 # Need to download this hive?
383 unless (-f "$tmpdir/$hivename") {
384 download_hive ($hivename);
386 my $h = Win::Hivex->open ("$tmpdir/$hivename",
387 write => 1, debug => $debug);
388 $hives{$hivename} = $h;
391 return ($hives{$hivename}, $path);
394 # Given a path, map that to the name of the hive and the true path
399 my ($hivename, $prefix);
401 if (/^\\?(?:HKEY_LOCAL_MACHINE|HKLM)\\SAM(\\.*)?$/i) {
403 $_ = defined $1 ? $1 : "\\";
404 $prefix = "HKEY_LOCAL_MACHINE\\SAM";
406 elsif (/^\\?(?:HKEY_LOCAL_MACHINE|HKLM)\\SECURITY(\\.*)?$/i) {
407 $hivename = "security";
408 $_ = defined $1 ? $1 : "\\";
409 $prefix = "HKEY_LOCAL_MACHINE\\SECURITY";
411 elsif (/^\\?(?:HKEY_LOCAL_MACHINE|HKLM)\\SOFTWARE(\\.*)?$/i) {
412 $hivename = "software";
413 $_ = defined $1 ? $1 : "\\";
414 $prefix = "HKEY_LOCAL_MACHINE\\SOFTWARE";
416 elsif (/^\\?(?:HKEY_LOCAL_MACHINE|HKLM)\\SYSTEM(\\.*)?$/i) {
417 $hivename = "system";
418 $_ = defined $1 ? $1 : "\\";
419 $prefix = "HKEY_LOCAL_MACHINE\\SYSTEM";
421 elsif (/^\\?(?:HKEY_USERS|HKU)\\.DEFAULT(\\.*)?$/i) {
422 $hivename = "default";
423 $_ = defined $1 ? $1 : "\\";
424 $prefix = "HKEY_LOCAL_MACHINE\\.DEFAULT";
427 die __x("virt-win-reg: {p}: not a supported Windows Registry path\n",
431 return ($hivename, $_, $prefix);
434 # Download a named hive file. Die on failure.
438 my $hivename = shift;
440 my $systemroot = $os->{root}->{systemroot} || "/windows";
441 my $winfile_before = "$systemroot/system32/config/$hivename";
443 eval { $winfile = $g->case_sensitive_path ($winfile_before); };
445 die __x("virt-win-reg: {p}: file not found in guest: {err}\n",
446 p => $winfile_before, err => $@);
449 warn "downloading $winfile ..." if $debug;
450 eval { $g->download ($winfile, "$tmpdir/$hivename"); };
452 die __x("virt-win-reg: {p}: could not download registry file: {err}\n",
453 p => $winfile, err => $@);
457 # Upload a named hive file. Die on failure.
461 my $hivename = shift;
463 my $systemroot = $os->{root}->{systemroot} || "/windows";
464 my $winfile_before = "$systemroot/system32/config/$hivename";
466 eval { $winfile = $g->case_sensitive_path ($winfile_before); };
468 die __x("virt-win-reg: {p}: file not found in guest: {err}\n",
469 p => $winfile_before, err => $@);
472 warn "uploading $winfile ..." if $debug;
473 eval { $g->upload ("$tmpdir/$hivename", $winfile); };
475 die __x("virt-win-reg: {p}: could not upload registry file: {err}\n",
476 p => $winfile, err => $@);
482 Libvirt guest names can contain arbitrary characters, some of which
483 have meaning to the shell such as C<#> and space. You may need to
484 quote or escape these characters on the command line. See the shell
485 manual page L<sh(1)> for details.
496 L<Sys::Guestfs::Lib(3)>,
498 L<Win::Hivex::Regedit(3)>,
500 L<http://libguestfs.org/>.
504 When reporting bugs, please enable debugging and capture the
507 export LIBGUESTFS_DEBUG=1
508 virt-win-reg --debug [... rest ...] > /tmp/virt-win-reg.log 2>&1
510 Attach /tmp/virt-win-reg.log to a new bug report at
511 L<https://bugzilla.redhat.com/>
515 Richard W.M. Jones L<http://people.redhat.com/~rjones/>
519 Copyright (C) 2010 Red Hat Inc.
521 This program is free software; you can redistribute it and/or modify
522 it under the terms of the GNU General Public License as published by
523 the Free Software Foundation; either version 2 of the License, or
524 (at your option) any later version.
526 This program is distributed in the hope that it will be useful,
527 but WITHOUT ANY WARRANTY; without even the implied warranty of
528 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
529 GNU General Public License for more details.
531 You should have received a copy of the GNU General Public License
532 along with this program; if not, write to the Free Software
533 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.