The lengthy program after the fold uses libguestfs and hivex to list out the services from a Windows guest. You point it to a Windows guest and it will produce a rather long list, like this:
# ./services.pl WindowsGuest [...] SysMain: Path: %systemroot%\system32\svchost.exe -k LocalSystemNetworkRestricted Start flag: autoload Service type: Win32 service using svchost Error control: ignore TabletInputService: Path: %SystemRoot%\System32\svchost.exe -k LocalSystemNetworkRestricted Group: PlugPlay Start flag: load on demand Service type: Win32 service using svchost Error control: normal TapiSrv: Path: %SystemRoot%\System32\svchost.exe -k NetworkService Start flag: load on demand Service type: Win32 service using svchost Error control: normal TBS: Path: %SystemRoot%\System32\svchost.exe -k LocalServiceAndNoImpersonation Start flag: load on demand Service type: Win32 service using svchost Error control: normal Tcpip: Path: System32\drivers\tcpip.sys Group: PNP_TDI Start flag: boot loader Service type: kernel device driver Error control: normal TCPIP6 (Microsoft IPv6 Protocol Driver): Microsoft IPv6 Protocol Driver Path: system32\DRIVERS\tcpip.sys Start flag: load on demand Service type: kernel device driver Error control: normal tcpipreg (TCP/IP Registry Compatibility): Provides compatibility for legacy applications which interact with TCP/IP through the registry. If this service is stopped, certain applications may have impaired functionality. Path: System32\drivers\tcpipreg.sys Start flag: autoload Service type: kernel device driver Error control: normal [...]
#!/usr/bin/perl -w use strict; use Sys::Guestfs; use Win::Hivex; use File::Temp qw(tempdir); # Open the guest disk image. my $guest = $ARGV[0] or die "Usage: $0 guestname\n"; my $g = Sys::Guestfs->new (); #$g->set_trace (1); $g->add_domain ($guest, readonly => 1); $g->launch (); # Look for a Windows operating system. my @roots = $g->inspect_os (); if (@roots == 0) { die "$0: $guest: no operating system found in the guest disk image\n" } my $root = $roots[0]; if ($g->inspect_get_type ($root) ne "windows") { die "$0: $guest: not a Windows guest\n" } $g->mount_ro ($root, "/"); # Download the HKLM\SYSTEM registry (hive file). my $systemroot = $g->inspect_get_windows_systemroot ($root); my $path = "$systemroot/system32/config/system"; $path = $g->case_sensitive_path ($path); my $tmpdir = tempdir (CLEANUP => 1); $g->download ($path, "$tmpdir/system"); # Use hivex to pull out registry keys of interest. my $h = Win::Hivex->open ("$tmpdir/system"); my $root_node = $h->root (); # Firstly get HKLM\SYSTEM\Select so we know which # ControlSetNNN is in use. my ($node, $val); $node = $h->node_get_child ($root_node, "Select"); $val = $h->node_get_value ($node, "Current"); my $cset = sprintf ("ControlSet%03d", $h->value_dword ($val)); # Then get HKLM\SYSTEM\$cset\Services $node = $h->node_get_child ($root_node, $cset); my $services_node = $h->node_get_child ($node, "Services"); # Get all the child nodes of HKLM\SYSTEM\$cset\Services # This is the list of services. my @nodes = $h->node_children ($services_node); # Iterate through the services, printing name and details. # http://support.microsoft.com/kb/103000 foreach $node (@nodes) { my $name = $h->node_name ($node); my $start; eval { $val = $h->node_get_value ($node, "Start"); $start = $h->value_dword ($val); }; # Ignore registry keys which don't have "Start". if (defined $start) { my ($display_name, $description, $group, $tag, $type, $error_control, $image_path); eval { $val = $h->node_get_value ($node, "DisplayName"); $display_name = $h->value_string ($val); # If the first character of DisplayName is # '@' then it seems to mean "refer to this # other DLL file for the name". if (substr ($display_name, 0, 1) eq '@') { $display_name = undef; } }; eval { $val = $h->node_get_value ($node, "Description"); $description = $h->value_string ($val); # Uses @ like DisplayName above. if (substr ($description, 0, 1) eq '@') { $description = undef; } else { chomp $description; } }; eval { $val = $h->node_get_value ($node, "Group"); $group = $h->value_string ($val); }; eval { $val = $h->node_get_value ($node, "Tag"); $tag = $h->value_dword ($val); }; eval { $val = $h->node_get_value ($node, "Type"); $type = $h->value_dword ($val); }; eval { $val = $h->node_get_value ($node, "ErrorControl"); $error_control = $h->value_dword ($val); }; eval { $val = $h->node_get_value ($node, "ImagePath"); $image_path = $h->value_string ($val); }; print "$name"; print " ($display_name)" if defined $display_name; print ":\n"; print " $description\n" if defined $description; print " Path: $image_path\n" if defined $image_path; print " Group: $group\n" if defined $group; print " Start flag: "; if ($start == 0x0) { print "boot loader"; } elsif ($start == 0x1) { print "I/O subsystem"; } elsif ($start == 0x2) { print "autoload"; } elsif ($start == 0x3) { print "load on demand"; } elsif ($start == 0x4) { print "disabled"; } else { printf "unknown (0x%x)", $start } print "\n"; if (defined $type) { print " Service type: "; if ($type == 0x1) { print "kernel device driver"; } elsif ($type == 0x2) { print "filesystem driver"; } elsif ($type == 0x4) { print "adapter arguments"; } elsif ($type == 0x10) { print "Win32 service"; } elsif ($type == 0x20) { print "Win32 service using svchost"; } else { printf "unknown (0x%x)", $type } print "\n"; } if (defined $error_control) { print " Error control: "; if ($error_control == 0x0) { print "ignore"; } elsif ($error_control == 0x1) { print "normal"; } elsif ($error_control == 0x2) { print "severe"; } elsif ($error_control == 0x3) { print "critical"; } else { printf "unknown (0x%x)", $error_control; } print "\n"; } } }
Cool! You should add some Perl examples to http://libguestfs.org/ 🙂
There’s a lot of real Perl code using the API, eg. here and here.