From 15a5511e038f53ade23fa998985ecd4de39b60d5 Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Fri, 29 Jan 2010 12:18:30 +0000 Subject: [PATCH] hivex: Add 'hivexsh' program (shell for navigating registry hives). --- .gitignore | 2 + hivex/Makefile.am | 35 ++- hivex/hivexget.c | 4 +- hivex/hivexget.pod | 1 + hivex/hivexml.pod | 1 + hivex/hivexsh.c | 779 +++++++++++++++++++++++++++++++++++++++++++++++++++++ hivex/hivexsh.pod | 179 ++++++++++++ po/POTFILES.in | 1 + tools/virt-win-reg | 1 + 9 files changed, 997 insertions(+), 6 deletions(-) create mode 100644 hivex/hivexsh.c create mode 100644 hivex/hivexsh.pod diff --git a/.gitignore b/.gitignore index 5b4d356..a80f1ec 100644 --- a/.gitignore +++ b/.gitignore @@ -83,12 +83,14 @@ haskell/Guestfs.hs hivex/*.1 hivex/*.3 hivex/hivexget +hivex/hivexsh hivex/hivexml html/guestfish.1.html html/guestfs.3.html html/guestmount.1.html html/hivex.3.html html/hivexget.1.html +html/hivexsh.1.html html/hivexml.1.html html/recipes.html html/virt-cat.1.html diff --git a/hivex/Makefile.am b/hivex/Makefile.am index 31275ea..90fd716 100644 --- a/hivex/Makefile.am +++ b/hivex/Makefile.am @@ -15,7 +15,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -EXTRA_DIST = hivex.pod hivexml.pod hivexget.pod LICENSE +EXTRA_DIST = hivex.pod hivexml.pod hivexget.pod hivexsh.pod LICENSE lib_LTLIBRARIES = libhivex.la @@ -27,7 +27,7 @@ libhivex_la_LDFLAGS = -version-info 0:0:0 libhivex_la_CFLAGS = \ $(WARN_CFLAGS) $(WERROR_CFLAGS) -bin_PROGRAMS = hivexml hivexget +bin_PROGRAMS = hivexml hivexget hivexsh hivexml_SOURCES = \ hivexml.c @@ -48,7 +48,17 @@ hivexget_CFLAGS = \ -DLOCALEBASEDIR=\""$(datadir)/locale"\" \ $(WARN_CFLAGS) $(WERROR_CFLAGS) -man_MANS = hivex.3 hivexml.1 hivexget.1 +hivexsh_SOURCES = \ + hivexsh.c + +hivexsh_LDADD = libhivex.la ../gnulib/lib/libgnu.la $(LIBREADLINE) +hivexsh_CFLAGS = \ + -I$(top_srcdir)/gnulib/lib \ + -I$(top_srcdir)/src \ + -DLOCALEBASEDIR=\""$(datadir)/locale"\" \ + $(WARN_CFLAGS) $(WERROR_CFLAGS) + +man_MANS = hivex.3 hivexml.1 hivexget.1 hivexsh.1 hivex.3: hivex.pod $(POD2MAN) \ @@ -74,10 +84,19 @@ hivexget.1: hivexget.pod --release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \ $< > $@-t; mv $@-t $@ +hivexsh.1: hivexsh.pod + $(POD2MAN) \ + --section 1 \ + -c "Windows Registry" \ + --name "hivexsh" \ + --release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \ + $< > $@-t; mv $@-t $@ + noinst_DATA = \ $(top_builddir)/html/hivex.3.html \ $(top_builddir)/html/hivexml.1.html \ - $(top_builddir)/html/hivexget.1.html + $(top_builddir)/html/hivexget.1.html \ + $(top_builddir)/html/hivexsh.1.html $(top_builddir)/html/hivex.3.html: hivex.pod mkdir -p $(top_builddir)/html @@ -102,3 +121,11 @@ $(top_builddir)/html/hivexget.1.html: hivexget.pod --htmldir html \ --outfile html/hivexget.1.html \ hivex/hivexget.pod + +$(top_builddir)/html/hivexsh.1.html: hivexsh.pod + mkdir -p $(top_builddir)/html + cd $(top_builddir) && pod2html \ + --css 'pod.css' \ + --htmldir html \ + --outfile html/hivexsh.1.html \ + hivex/hivexsh.pod diff --git a/hivex/hivexget.c b/hivex/hivexget.c index fd49293..4f2419c 100644 --- a/hivex/hivexget.c +++ b/hivex/hivexget.c @@ -60,7 +60,7 @@ main (int argc, char *argv[]) } if (path[1] == '\\') { doubled: - fprintf (stderr, _("hivexget: %s: \\ characters in path are doubled - are you escaping the path parameter correctly?\n"), path); + fprintf (stderr, _("%s: %s: \\ characters in path are doubled - are you escaping the path parameter correctly?\n"), "hivexget", path); exit (EXIT_FAILURE); } @@ -118,7 +118,7 @@ main (int argc, char *argv[]) if (errno) goto error; /* else key not found */ - fprintf (stderr, _("hivexget: %s: key not found\n"), key); + fprintf (stderr, _("%s: %s: key not found\n"), "hivexget", key); exit (EXIT_NOT_FOUND); } diff --git a/hivex/hivexget.pod b/hivex/hivexget.pod index fa390e0..4fbac13 100644 --- a/hivex/hivexget.pod +++ b/hivex/hivexget.pod @@ -65,6 +65,7 @@ If it's a numeric value, it is printed as a decimal number. L, L, +L, L, L, L, diff --git a/hivex/hivexml.pod b/hivex/hivexml.pod index 448c4f6..d6a87b4 100644 --- a/hivex/hivexml.pod +++ b/hivex/hivexml.pod @@ -35,6 +35,7 @@ skips over any parts of the Registry that we cannot read. L, L, +L, L, L, L, diff --git a/hivex/hivexsh.c b/hivex/hivexsh.c new file mode 100644 index 0000000..1cecaad --- /dev/null +++ b/hivex/hivexsh.c @@ -0,0 +1,779 @@ +/* hivexsh - Hive shell. + * Copyright (C) 2009 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_LIBREADLINE +#include +#include +#endif + +#ifdef HAVE_GETTEXT +#include "gettext.h" +#define _(str) dgettext(PACKAGE, (str)) +//#define N_(str) dgettext(PACKAGE, (str)) +#else +#define _(str) str +//#define N_(str) str +#endif + +#define STREQ(a,b) (strcmp((a),(b)) == 0) +#define STRCASEEQ(a,b) (strcasecmp((a),(b)) == 0) +#define STRNEQ(a,b) (strcmp((a),(b)) != 0) +//#define STRCASENEQ(a,b) (strcasecmp((a),(b)) != 0) +//#define STREQLEN(a,b,n) (strncmp((a),(b),(n)) == 0) +//#define STRCASEEQLEN(a,b,n) (strncasecmp((a),(b),(n)) == 0) +//#define STRNEQLEN(a,b,n) (strncmp((a),(b),(n)) != 0) +//#define STRCASENEQLEN(a,b,n) (strncasecmp((a),(b),(n)) != 0) +//#define STRPREFIX(a,b) (strncmp((a),(b),strlen((b))) == 0) + +#include "c-ctype.h" + +#include "hivex.h" + +static int quit = 0; +static hive_h *h = NULL; +static char *prompt_string = NULL; /* Prompt string. */ +static char *loaded = NULL; /* Basename of loaded file, if any. */ +static hive_node_h cwd; /* Current node. */ +static int open_flags = 0; /* Flags used when loading a hive file. */ + +static void usage (void) __attribute__((noreturn)); +static void print_node_path (hive_node_h, FILE *); +static void set_prompt_string (void); +static void initialize_readline (void); +static void cleanup_readline (void); +static void add_history_line (const char *); +static char *rl_gets (int prompt); +static void sort_strings (char **strings, int len); +static int dispatch (char *cmd, char *args); +static int cmd_cd (char *path); +static int cmd_close (char *path); +static int cmd_help (char *args); +static int cmd_load (char *hivefile); +static int cmd_ls (char *args); +static int cmd_lsval (char *args); + +static void +usage (void) +{ + fprintf (stderr, "hivexsh [-df] [hivefile]\n"); + exit (EXIT_FAILURE); +} + +int +main (int argc, char *argv[]) +{ + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEBASEDIR); + textdomain (PACKAGE); + + int c; + const char *filename = NULL; + + set_prompt_string (); + + while ((c = getopt (argc, argv, "df")) != EOF) { + switch (c) { + case 'd': + open_flags |= HIVEX_OPEN_DEBUG; + break; + case 'f': + filename = optarg; + break; + default: + usage (); + } + } + + if (optind < argc) { + if (optind + 1 != argc) + usage (); + if (cmd_load (argv[optind]) == -1) + exit (EXIT_FAILURE); + } + + /* -f filename parameter */ + if (filename) { + close (0); + if (open (filename, O_RDONLY) == -1) { + perror (filename); + exit (EXIT_FAILURE); + } + } + + /* Main loop. */ + initialize_readline (); + int prompt = isatty (0); + + if (prompt) + printf (_( +"\n" +"Welcome to hivexsh, the hivex interactive shell for examining\n" +"Windows Registry binary hive files.\n" +"\n" +"Type: 'help' for help summary\n" +" 'quit' to quit the shell\n" +"\n")); + + while (!quit) { + char *buf = rl_gets (prompt); + if (!buf) { + quit = 1; + printf ("\n"); + break; + } + + while (*buf && c_isspace (*buf)) + buf++; + + /* Ignore blank line. */ + if (!*buf) continue; + + /* If the next character is '#' then this is a comment. */ + if (*buf == '#') continue; + + /* Parsing is very simple - much simpler than guestfish. This is + * because Registry keys often contain spaces, and we don't want + * to bother with quoting. Therefore here we just split at the + * first whitespace into "cmdarg(s)". We let the + * command decide how to deal with arg(s), if at all. + */ + size_t len = strcspn (buf, " \t"); + + if (len == 0) continue; + + char *cmd = buf; + char *args; + size_t i = 0; + + if (buf[len] == '\0') { + /* This is mostly safe. Although the cmd_* functions do sometimes + * modify args, then shouldn't do so when args is "". + */ + args = (char *) ""; + goto got_command; + } + + buf[len] = '\0'; + args = buf + len + 1 + strspn (&buf[len+1], " \t"); + + len = strlen (args); + while (len > 0 && c_isspace (args[len-1])) { + args[len-1] = '\0'; + len--; + } + + got_command: + /*printf ("command: '%s' args: '%s'\n", cmd, args)*/; + int r = dispatch (cmd, args); + if (!prompt && r == -1) + exit (EXIT_FAILURE); + } + + cleanup_readline (); + free (prompt_string); + free (loaded); + if (h) hivex_close (h); + exit (0); +} + +/* Set the prompt string. This is called whenever it could change, eg. + * after loading a file or changing directory. + */ +static void +set_prompt_string (void) +{ + free (prompt_string); + prompt_string = NULL; + + FILE *fp; + char *ptr; + size_t size; + fp = open_memstream (&ptr, &size); + if (fp == NULL) { + perror ("open_memstream"); + exit (1); + } + + if (h) { + assert (loaded != NULL); + assert (cwd != 0); + + fputs (loaded, fp); + print_node_path (cwd, fp); + } + + fprintf (fp, "> "); + fclose (fp); + prompt_string = ptr; +} + +/* Print the \full\path of a node. */ +static void +print_node_path (hive_node_h node, FILE *fp) +{ + hive_node_h root = hivex_root (h); + + if (node == root) { + fputc ('\\', fp); + return; + } + + hive_node_h parent = hivex_node_parent (h, node); + if (parent == 0) { + fprintf (stderr, _("hivexsh: error getting parent of node %zu\n"), node); + return; + } + print_node_path (parent, fp); + + if (parent != root) + fputc ('\\', fp); + + char *name = hivex_node_name (h, node); + if (name == NULL) { + fprintf (stderr, _("hivexsh: error getting node name of node %zx\n"), node); + return; + } + + fputs (name, fp); + free (name); +} + +static char *line_read = NULL; + +static char * +rl_gets (int prompt) +{ +#ifdef HAVE_LIBREADLINE + + if (prompt) { + if (line_read) { + free (line_read); + line_read = NULL; + } + + line_read = readline (prompt_string); + + if (line_read && *line_read) + add_history_line (line_read); + + return line_read; + } + +#endif /* HAVE_LIBREADLINE */ + + static char buf[8192]; + int len; + + if (prompt) + printf ("%s", prompt_string); + line_read = fgets (buf, sizeof buf, stdin); + + if (line_read) { + len = strlen (line_read); + if (len > 0 && buf[len-1] == '\n') buf[len-1] = '\0'; + } + + return line_read; +} + +#ifdef HAVE_LIBREADLINE +static char histfile[1024]; +static int nr_history_lines = 0; +#endif + +static void +initialize_readline (void) +{ +#ifdef HAVE_LIBREADLINE + const char *home; + + home = getenv ("HOME"); + if (home) { + snprintf (histfile, sizeof histfile, "%s/.hivexsh", home); + using_history (); + (void) read_history (histfile); + } + + rl_readline_name = "hivexsh"; +#endif +} + +static void +cleanup_readline (void) +{ +#ifdef HAVE_LIBREADLINE + int fd; + + if (histfile[0] != '\0') { + fd = open (histfile, O_WRONLY|O_CREAT, 0644); + if (fd == -1) { + perror (histfile); + return; + } + close (fd); + + (void) append_history (nr_history_lines, histfile); + } +#endif +} + +static void +add_history_line (const char *line) +{ +#ifdef HAVE_LIBREADLINE + add_history (line); + nr_history_lines++; +#endif +} + +static int +compare (const void *vp1, const void *vp2) +{ + char * const *p1 = (char * const *) vp1; + char * const *p2 = (char * const *) vp2; + return strcasecmp (*p1, *p2); +} + +static void +sort_strings (char **strings, int len) +{ + qsort (strings, len, sizeof (char *), compare); +} + +static int +dispatch (char *cmd, char *args) +{ + if (STRCASEEQ (cmd, "help")) + return cmd_help (args); + else if (STRCASEEQ (cmd, "load")) + return cmd_load (args); + else if (STRCASEEQ (cmd, "exit") || + STRCASEEQ (cmd, "q") || + STRCASEEQ (cmd, "quit")) { + quit = 1; + return 0; + } + + /* If no hive file is loaded (!h) then only the small selection of + * commands above will work. + */ + if (!h) { + fprintf (stderr, _("hivexsh: you must load a hive file first using 'load hivefile'\n")); + return -1; + } + + if (STRCASEEQ (cmd, "cd")) + return cmd_cd (args); + else if (STRCASEEQ (cmd, "close") || STRCASEEQ (cmd, "unload")) + return cmd_close (args); + else if (STRCASEEQ (cmd, "ls")) + return cmd_ls (args); + else if (STRCASEEQ (cmd, "lsval")) + return cmd_lsval (args); + else { + fprintf (stderr, _("hivexsh: unknown command '%s', use 'help' for help summary\n"), + cmd); + return -1; + } +} + +static int +cmd_load (char *hivefile) +{ + if (STREQ (hivefile, "")) { + fprintf (stderr, _("hivexsh: load: no hive file name given to load\n")); + return -1; + } + + if (h) hivex_close (h); + h = NULL; + + free (loaded); + loaded = NULL; + + cwd = 0; + + h = hivex_open (hivefile, open_flags); + if (h == NULL) { + fprintf (stderr, + _( +"hivexsh: failed to open hive file: %s: %m\n" +"\n" +"If you think this file is a valid Windows binary hive file (_not_\n" +"a regedit *.reg file) then please run this command again using the\n" +"hivexsh option '-d' and attach the complete output _and_ the hive file\n" +"which fails into a bug report at https://bugzilla.redhat.com/\n" +"\n"), + hivefile); + return -1; + } + + /* Get the basename of the file for the prompt. */ + char *p = strrchr (hivefile, '/'); + if (p) + loaded = strdup (p+1); + else + loaded = strdup (hivefile); + if (!loaded) { + perror ("strdup"); + exit (EXIT_FAILURE); + } + + cwd = hivex_root (h); + + set_prompt_string (); + + return 0; +} + +static int +cmd_close (char *args) +{ + if (STRNEQ (args, "")) { + fprintf (stderr, _("hivexsh: '%s' command should not be given arguments\n"), + "close"); + return -1; + } + + if (h) hivex_close (h); + h = NULL; + + free (loaded); + loaded = NULL; + + cwd = 0; + + set_prompt_string (); + + return 0; +} + +static int +cmd_cd (char *path) +{ + if (STREQ (path, "")) { + print_node_path (cwd, stdout); + fputc ('\n', stdout); + return 0; + } + + if (path[0] == '\\' && path[1] == '\\') { + fprintf (stderr, _("%s: %s: \\ characters in path are doubled - are you escaping the path parameter correctly?\n"), "hivexsh", path); + return -1; + } + + hive_node_h new_cwd = cwd; + hive_node_h root = hivex_root (h); + + if (path[0] == '\\') { + new_cwd = root; + path++; + } + + while (path[0]) { + size_t len = strcspn (path, "\\"); + if (len == 0) { + path++; + continue; + } + + char *elem = path; + path = path[len] == '\0' ? &path[len] : &path[len+1]; + elem[len] = '\0'; + + if (len == 1 && STREQ (elem, ".")) + continue; + + if (len == 2 && STREQ (elem, "..")) { + if (new_cwd != root) + new_cwd = hivex_node_parent (h, new_cwd); + continue; + } + + new_cwd = hivex_node_get_child (h, new_cwd, elem); + if (new_cwd == 0) { + fprintf (stderr, _("hivexsh: cd: subkey '%s' not found\n"), + elem); + return -1; + } + } + + if (new_cwd != cwd) { + cwd = new_cwd; + set_prompt_string (); + } + + return 0; +} + +static int +cmd_help (char *args) +{ + printf (_( +"Navigate through the hive's keys using the 'cd' command, as if it\n" +"contained a filesystem, and use 'ls' to list the subkeys of the\n" +"current key. Full documentation is in the hivexsh(1) manual page.\n")); + + return 0; +} + +static int +cmd_ls (char *args) +{ + if (STRNEQ (args, "")) { + fprintf (stderr, _("hivexsh: '%s' command should not be given arguments\n"), + "ls"); + return -1; + } + + /* Get the subkeys. */ + hive_node_h *children = hivex_node_children (h, cwd); + if (children == NULL) { + perror ("ls"); + return -1; + } + + /* Get names for each subkey. */ + size_t len; + for (len = 0; children[len] != 0; ++len) + ; + + char **names = calloc (len, sizeof (char *)); + if (names == NULL) { + perror ("malloc"); + exit (1); + } + + int ret = -1; + size_t i; + for (i = 0; i < len; ++i) { + names[i] = hivex_node_name (h, children[i]); + if (names[i] == NULL) { + perror ("hivex_node_name"); + goto error; + } + } + + /* Sort the names. */ + sort_strings (names, len); + + for (i = 0; i < len; ++i) + printf ("%s\n", names[i]); + + ret = 0; + error: + free (children); + for (i = 0; i < len; ++i) + free (names[i]); + free (names); + return ret; +} + +static int +cmd_lsval (char *key) +{ + if (STRNEQ (key, "")) { + hive_value_h value; + + errno = 0; + if (STREQ (key, "@")) /* default key written as "@" */ + value = hivex_node_get_value (h, cwd, ""); + else + value = hivex_node_get_value (h, cwd, key); + + if (value == 0) { + if (errno) + goto error; + /* else key not found */ + fprintf (stderr, _("%s: %s: key not found\n"), "hivexsh", key); + return -1; + } + + /* Print the value. */ + hive_type t; + size_t len; + if (hivex_value_type (h, value, &t, &len) == -1) + goto error; + + switch (t) { + case hive_t_string: + case hive_t_expand_string: + case hive_t_link: { + char *str = hivex_value_string (h, value); + if (!str) + goto error; + + puts (str); /* note: this adds a single \n character */ + free (str); + break; + } + + case hive_t_dword: + case hive_t_dword_be: { + int32_t j = hivex_value_dword (h, value); + printf ("%" PRIi32 "\n", j); + break; + } + + case hive_t_qword: { + int64_t j = hivex_value_qword (h, value); + printf ("%" PRIi64 "\n", j); + break; + } + + case hive_t_multiple_strings: { + char **strs = hivex_value_multiple_strings (h, value); + if (!strs) + goto error; + size_t j; + for (j = 0; strs[j] != NULL; ++j) { + puts (strs[j]); + free (strs[j]); + } + free (strs); + break; + } + + case hive_t_none: + case hive_t_binary: + case hive_t_resource_list: + case hive_t_full_resource_description: + case hive_t_resource_requirements_list: + default: { + char *data = hivex_value_value (h, value, &t, &len); + if (!data) + goto error; + + if (fwrite (data, 1, len, stdout) != len) + goto error; + + free (data); + break; + } + } /* switch */ + } else { + /* No key specified, so print all keys in this node. We do this + * in a format which looks like the output of regedit, although + * this isn't a particularly useful format. + */ + hive_value_h *values; + + values = hivex_node_values (h, cwd); + if (values == NULL) + goto error; + + size_t i; + for (i = 0; values[i] != 0; ++i) { + char *key = hivex_value_key (h, values[i]); + if (!key) goto error; + + if (*key) { + putchar ('"'); + size_t j; + for (j = 0; key[j] != 0; ++j) { + if (key[j] == '"' || key[j] == '\\') + putchar ('\\'); + putchar (key[j]); + } + putchar ('"'); + } else + printf ("\"@\""); /* default key in regedit files */ + putchar ('='); + free (key); + + hive_type t; + size_t len; + if (hivex_value_type (h, values[i], &t, &len) == -1) + goto error; + + switch (t) { + case hive_t_string: + case hive_t_expand_string: + case hive_t_link: { + char *str = hivex_value_string (h, values[i]); + if (!str) + goto error; + + if (t != hive_t_string) + printf ("str(%d):", t); + putchar ('"'); + size_t j; + for (j = 0; str[j] != 0; ++j) { + if (str[j] == '"' || str[j] == '\\') + putchar ('\\'); + putchar (str[j]); + } + putchar ('"'); + free (str); + break; + } + + case hive_t_dword: + case hive_t_dword_be: { + int32_t j = hivex_value_dword (h, values[i]); + printf ("dword:%08" PRIx32 "\"", j); + break; + } + + case hive_t_qword: /* sic */ + case hive_t_none: + case hive_t_binary: + case hive_t_multiple_strings: + case hive_t_resource_list: + case hive_t_full_resource_description: + case hive_t_resource_requirements_list: + default: { + char *data = hivex_value_value (h, values[i], &t, &len); + if (!data) + goto error; + + printf ("hex(%d):", t); + size_t j; + for (j = 0; j < len; ++j) { + if (j > 0) + putchar (','); + printf ("%02x", data[j]); + } + break; + } + } /* switch */ + + putchar ('\n'); + } /* for */ + + free (values); + } + + return 0; + + error: + perror ("hivexsh: lsval"); + return -1; +} diff --git a/hivex/hivexsh.pod b/hivex/hivexsh.pod new file mode 100644 index 0000000..d13c70b --- /dev/null +++ b/hivex/hivexsh.pod @@ -0,0 +1,179 @@ +=encoding utf8 + +=head1 NAME + +hivexsh - Windows Registry hive shell + +=head1 SYNOPSIS + + hivexsh [-options] [hivefile] + +=head1 DESCRIPTION + +This program provides a simple shell for navigating Windows Registry +'hive' files. It uses the hivex library for access to these binary +files. + +Firstly you will need to provide a hive file from a Windows operating +system. The hive files are usually located in +C and have names like C, +C etc (without any file extension). For more information +about hive files, read L. For information about downloading +files from virtual machines, read L and L. + +You can provide the name of the hive file to examine on the command +line. For example: + + hivexsh software + +Or you can start C without any arguments, and immediately use +the C command to load a hive: + + $ hivexsh + + Welcome to hivexsh, the hivex interactive shell for examining + Windows Registry binary hive files. + + Type: 'help' for help with commands + 'quit' to quit the shell + + > load software + software\> + +Navigate through the hive's keys using the C command, as if it +contained a filesystem, and use C to list the subkeys of the +current key. Other commands are listed below. + +=head1 OPTIONS + +=over 4 + +=item B<-d> + +Enable lots of debug messages. If you find a Registry file that this +program cannot parse, please enable this option and post the complete +output I the Registry hive file in your bug report. + +=item B<-f> filename + +Read commands from C instead of stdin. To write a hivexsh +script, use: + + #!/usr/bin/hivexsh -f + +=back + +=head1 COMMANDS + +=over 4 + +=item B path + +Change to the subkey C. Use Windows-style backslashes to +separate path elements, and start with a backslash in order to start +from the root of the hive. For example: + + cd \Classes\* + +moves from the root node, to the C node, to the C<*> node. +If you were already at the root node, you could do this instead: + + cd Classes\* + +or even: + + cd Classes + cd * + +Path elements (node names) are matched case insensitively, and +characters like space, C<*>, and C have I special significance. + +C<..> may be used to go to the parent directory. + +=item B | B + +Close the currently loaded hive. + +=item B | B + +Exit the shell. + +=item B hivefile + +Load the binary hive named C. The currently loaded hive, if +any, is closed. The current directory is changed back to the root +node. + +=item B + +List the subkeys of the current hive Registry key. Note this command +does not take any arguments. + +=item B [key] + +List the (key, value) pairs of the current hive Registry key. If no +argument is given then all pairs are displayed. If C is given, +then the value of the named key is displayed. If C<@> is given, then +the value of the default key is displayed. + +=back + +=head1 EXAMPLE + + $ guestfish --ro -i Windows7 + > download win:c:\windows\system32\config\software software + > quit + + $ hivexsh software + + Welcome to hivexsh, the hivex interactive shell for examining + Windows Registry binary hive files. + + Type: 'help' for help with commands + 'quit' to quit the shell + + software\> ls + ATI Technologies + Classes + Clients + Intel + Microsoft + ODBC + Policies + RegisteredApplications + Sonic + Wow6432Node + software\> quit + +=head1 SEE ALSO + +L, +L, +L, +L, +L, +L, +L, +L. + +=head1 AUTHORS + +Richard W.M. Jones (C) + +=head1 COPYRIGHT + +Copyright (C) 2009-2010 Red Hat Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. diff --git a/po/POTFILES.in b/po/POTFILES.in index 85892e8..3ac88a0 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -83,6 +83,7 @@ fuse/guestmount.c hivex/hivex.c hivex/hivexget.c hivex/hivexml.c +hivex/hivexsh.c inspector/virt-inspector java/com_redhat_et_libguestfs_GuestFS.c ocaml/guestfs_c.c diff --git a/tools/virt-win-reg b/tools/virt-win-reg index e11ac34..8f248d7 100755 --- a/tools/virt-win-reg +++ b/tools/virt-win-reg @@ -277,6 +277,7 @@ for ($i = 0; $i < @ARGV; ++$i) { L, L, +L, L, L, L, -- 1.8.3.1