From: Richard Jones Date: Wed, 3 Feb 2010 18:04:31 +0000 (+0000) Subject: hivexsh: Add 'setval' and 'commit' commands. X-Git-Tag: 1.1.0~31 X-Git-Url: http://git.annexia.org/?p=hivex.git;a=commitdiff_plain;h=72a03b2cd32299ece4fb179ab179ce8689c6d0ce hivexsh: Add 'setval' and 'commit' commands. This adds the 'setval' and 'commit' commands to the hivex shell. Also adds some example scripts showing use of these. --- diff --git a/hivex/Makefile.am b/hivex/Makefile.am index 312cc3c..987cfc9 100644 --- a/hivex/Makefile.am +++ b/hivex/Makefile.am @@ -32,6 +32,7 @@ libhivex_la_CPPFLAGS = -I$(top_srcdir)/gnulib/lib bin_PROGRAMS = hivexml hivexsh bin_SCRIPTS = hivexget +noinst_SCRIPTS = example1 example2 example3 hivexml_SOURCES = \ hivexml.c @@ -44,7 +45,9 @@ hivexml_CFLAGS = \ $(WARN_CFLAGS) $(WERROR_CFLAGS) hivexsh_SOURCES = \ - hivexsh.c + hivexsh.c \ + hivex.h \ + byte_conversions.h hivexsh_LDADD = libhivex.la ../gnulib/lib/libgnu.la $(LIBREADLINE) hivexsh_CFLAGS = \ diff --git a/hivex/example1 b/hivex/example1 new file mode 100755 index 0000000..5b1313f --- /dev/null +++ b/hivex/example1 @@ -0,0 +1,40 @@ +#!/bin/bash - +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +set -e + +# Example program which loads and saves a hive. +# +# The intention of this example is just to check that we can do this +# without corrupting the hive (header etc). +# +# NB: The copy of the hive will not be absolutely identical. The +# sequence numbers in the header will change. If we implement the +# last modified field in the header, then that and the checksum will +# also change. + +if [ $# -ne 2 ]; then + echo "$0 input output" + exit 1 +fi + +d=`dirname $0` + +$d/hivexsh -w < Unload Hive. +# +# Don't replace the original Windows hive, else you'll break things :-) + +if [ $# -ne 0 ]; then + echo "$0: no arguments required" + exit 1 +fi + +d=`dirname $0` + +$d/hivexsh -w < Unload Hive. +# +# Don't replace the original Windows hive, else you'll break things :-) + +if [ $# -ne 0 ]; then + echo "$0: no arguments required" + exit 1 +fi + +d=`dirname $0` + +$d/hivexsh -w < 1000) { + fprintf (stderr, _("%s: %s: integer out of range\n"), + "setval", "nrvals"); + return -1; + } + + struct hive_set_value *values = + calloc (nrvals, sizeof (struct hive_set_value)); + if (values == NULL) { + perror ("calloc"); + exit (EXIT_FAILURE); + } + + int ret = -1; + + /* Read nrvals * 2 lines of input, nrvals * (key, value) pairs, as + * explained in the man page. + */ + int prompt = isatty (0) ? 2 : 0; + int i, j; + for (i = 0; i < nrvals; ++i) { + /* Read key. */ + char *buf = rl_gets (" key> "); + if (!buf) { + fprintf (stderr, _("hivexsh: setval: unexpected end of input\n")); + quit = 1; + goto error; + } + + /* Note that buf will be overwritten by the next call to rl_gets. */ + if (STREQ (buf, "@")) + values[i].key = strdup (""); + else + values[i].key = strdup (buf); + if (values[i].key == NULL) { + perror ("strdup"); + exit (EXIT_FAILURE); + } + + /* Read value. */ + buf = rl_gets ("value> "); + if (!buf) { + fprintf (stderr, _("hivexsh: setval: unexpected end of input\n")); + quit = 1; + goto error; + } + + if (STREQ (buf, "none")) { + values[i].t = hive_t_none; + values[i].len = 0; + } + else if (STRPREFIX (buf, "string:")) { + buf += 7; + values[i].t = hive_t_string; + int nr_chars = strlen (buf); + values[i].len = 2 * (nr_chars + 1); + values[i].value = malloc (values[i].len); + if (!values[i].value) { + perror ("malloc"); + exit (EXIT_FAILURE); + } + for (j = 0; j <= /* sic */ nr_chars; ++j) { + if (buf[j] & 0x80) { + fprintf (stderr, _("hivexsh: string(utf16le): only 7 bit ASCII strings are supported for input\n")); + goto error; + } + values[i].value[2*j] = buf[j]; + values[i].value[2*j+1] = '\0'; + } + } + else if (STRPREFIX (buf, "expandstring:")) { + buf += 13; + values[i].t = hive_t_string; + int nr_chars = strlen (buf); + values[i].len = 2 * (nr_chars + 1); + values[i].value = malloc (values[i].len); + if (!values[i].value) { + perror ("malloc"); + exit (EXIT_FAILURE); + } + for (j = 0; j <= /* sic */ nr_chars; ++j) { + if (buf[j] & 0x80) { + fprintf (stderr, _("hivexsh: string(utf16le): only 7 bit ASCII strings are supported for input\n")); + goto error; + } + values[i].value[2*j] = buf[j]; + values[i].value[2*j+1] = '\0'; + } + } + else if (STRPREFIX (buf, "dword:")) { + buf += 6; + values[i].t = hive_t_dword; + values[i].len = 4; + values[i].value = malloc (4); + if (!values[i].value) { + perror ("malloc"); + exit (EXIT_FAILURE); + } + long n; + xerr = xstrtol (buf, NULL, 0, &n, ""); + if (xerr != LONGINT_OK) { + fprintf (stderr, _("%s: %s: invalid integer parameter (%s returned %d)\n"), + "setval", "dword", "xstrtol", xerr); + goto error; + } + if (n < 0 || n > UINT32_MAX) { + fprintf (stderr, _("%s: %s: integer out of range\n"), + "setval", "dword"); + goto error; + } + uint32_t u32 = htole32 (n); + memcpy (values[i].value, &u32, 4); + } + else if (STRPREFIX (buf, "qword:")) { + buf += 6; + values[i].t = hive_t_qword; + values[i].len = 8; + values[i].value = malloc (8); + if (!values[i].value) { + perror ("malloc"); + exit (EXIT_FAILURE); + } + long long n; + xerr = xstrtoll (buf, NULL, 0, &n, ""); + if (xerr != LONGINT_OK) { + fprintf (stderr, _("%s: %s: invalid integer parameter (%s returned %d)\n"), + "setval", "dword", "xstrtoll", xerr); + goto error; + } +#if 0 + if (n < 0 || n > UINT64_MAX) { + fprintf (stderr, _("%s: %s: integer out of range\n"), + "setval", "dword"); + goto error; + } +#endif + uint64_t u64 = htole64 (n); + memcpy (values[i].value, &u64, 4); + } + else if (STRPREFIX (buf, "hex:")) { + /* Read the type. */ + buf += 4; + size_t len = strcspn (buf, ":"); + char *nextbuf; + if (buf[len] == '\0') /* "hex:t" */ + nextbuf = &buf[len]; + else { /* "hex:t:..." */ + buf[len] = '\0'; + nextbuf = &buf[len+1]; + } + + long t; + xerr = xstrtol (buf, NULL, 0, &t, ""); + if (xerr != LONGINT_OK) { + fprintf (stderr, _("%s: %s: invalid integer parameter (%s returned %d)\n"), + "setval", "hex", "xstrtol", xerr); + goto error; + } + if (t < 0 || t > UINT32_MAX) { + fprintf (stderr, _("%s: %s: integer out of range\n"), + "setval", "hex"); + goto error; + } + values[i].t = t; + + /* Read the hex data. */ + buf = nextbuf; + + /* The allocation length is an overestimate, but it doesn't matter. */ + values[i].value = malloc (1 + strlen (buf) / 2); + if (!values[i].value) { + perror ("malloc"); + exit (EXIT_FAILURE); + } + values[i].len = 0; + + while (*buf) { + int c = 0; + + for (j = 0; *buf && j < 2; buf++) { + if (c_isxdigit (*buf)) { /* NB: ignore non-hex digits. */ + c <<= 4; + c |= get_xdigit (*buf); + j++; + } + } + + if (j == 2) values[i].value[values[i].len++] = c; + else if (j == 1) { + fprintf (stderr, _("hivexsh: setval: trailing garbage after hex string\n")); + goto error; + } + } + } + else { + fprintf (stderr, + _("hivexsh: setval: cannot parse value string, please refer to the man page hivexsh(1) for help: %s\n"), + buf); + goto error; + } + } + + ret = hivex_node_set_values (h, cwd, nrvals, values, 0); + + error: + /* Free values array. */ + for (i = 0; i < nrvals; ++i) { + free (values[i].key); + free (values[i].value); + } + free (values); + + return ret; +} diff --git a/hivex/hivexsh.pod b/hivex/hivexsh.pod index d13c70b..e7e8d94 100644 --- a/hivex/hivexsh.pod +++ b/hivex/hivexsh.pod @@ -61,6 +61,18 @@ script, use: #!/usr/bin/hivexsh -f +=item B<-w> + +If this option is given, then writes are allowed to the hive +(see L command below, and the discussion of +modifying hives in L). + +B Even if you specify this option, nothing is written +to a hive unless you call the L command. If you exit the +shell without committing, all changes will be discarded. + +If this option is not given, then write commands are disabled. + =back =head1 COMMANDS @@ -94,6 +106,19 @@ C<..> may be used to go to the parent directory. Close the currently loaded hive. +If you modified the hive, all uncommitted writes are lost when you +call this command (or if the shell exits). You have to call C +to write changes. + +=item B [newfile] + +Commit changes to the hive. If the optional C parameter is +supplied, then the hive is written to that file, else the original +file is overwritten. + +Note that you have to specify the C<-w> flag, otherwise no writes are +allowed. + =item B | B Exit the shell. @@ -116,6 +141,60 @@ 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. +=item B nrvals + +This command replaces all (key, value) pairs at the current node with +the values in subsequent input. C is the number of values +(ie. (key, value) pairs), and any existing values at this node are +deleted. So C just deletes any values at the current node. + +The command reads 2 * nrvals lines of input, with each pair of +lines of input corresponding to a key and a value to add. + +For example, the following setval command replaces whatever is at the +current node with two (key, value) pairs. The default key is set to +the UTF16-LE-encoded string "abcd". The other value is named +"ANumber" and is a little-endian DWORD 0x12345678. + + setval 2 + @ + string:abcd + ANumber + dword:12345678 + +The first line of each pair is the key (the special key C<@> means +the default key, but you can also use a blank line). + +The second line of each pair is the value, which has a special format +C with possible types summarized in the table below: + + none No data is stored, and the type is set to 0. + + string:abc "abc" is stored as a UTF16-LE-encoded + string (type 1). Note that only 7 bit + ASCII strings are supported as input. + + expandstring:... Same as string but with type 2. + + dword:0x01234567 A DWORD (type 4) with the hex value + 0x01234567. You can also use decimal + or octal numbers here. + + qword:0x0123456789abcdef + A QWORD (type 11) with the hex value + 0x0123456789abcdef. You can also use + decimal or octal numbers here. + + hex:: + hex:1:41,00,42,00,43,00,44,00,00,00 + This is the generic way to enter any + value. is the integer value type. + is a list of pairs of hex + digits which are treated as bytes. + (Any non-hex-digits here are ignored, + so you can separate bytes with commas + or spaces if you want). + =back =head1 EXAMPLE