#!/usr/bin/perl
#
#    reghexprint - prints hex entries of registry dumps (regutils package)
#    Copyright (C) 1998 Memorial University of Newfoundland
#    
#    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.
#    


#
# Script which takes a windows 9x registry dump and prints the hex values
# as characters - useful to location paths and such embedded in a hex value.
#
# (pod at end)
#

use strict;
use Getopt::Std;
use IO::Handle;
use IO::File;

push(@INC, '/usr/lib');
require 'regfilterLib.pl';

my $prog = $0;
$prog =~ s:.*/::;


my $Usage = "Usage: $prog [-pqV] [reg-dump ...]
	-p	only print printable characters; default is to print ? for
		non-printable characters
	-q	filter out hex dumps that don't contain any printable characters
	-V	Print version number and exit.
    Converts regedit style hex dumps to characters.
";

my %opt;
if (!&getopts('qpV', \%opt)) {
    print STDERR $Usage;
    exit 1;
}
if (defined $opt{'V'}) {
    print "$prog: version 0.10\n";
    exit 0;
}
my $quiteMode = defined $opt{'q'} ? $opt{'q'} : 0;
my $onlyPrintable = defined $opt{'p'} ? $opt{'p'} : 0;

my $any = 0;
my $open = 0;
my $sep = $onlyPrintable ? '' : ' ';
my($in, $file);
while (1) {
    if (!$open) {
	if (!$any && !@ARGV) {
	    $in = new IO::Handle;
	    if (!$in->fdopen('STDIN', 'r')) {
		die "$prog: can't dup STDIN - $!\n";
	    }
	    $file = 'stdin';
	} else {
	    last if (!@ARGV);
	    $file = $ARGV[0];
	    $in = new IO::File($file, 'r');
	    if (!defined $in) {
		die "$prog: can't open $file - $!\n";
	    }
	    shift;
	}
	$open = 1;
	$any = 1;
    }
    my $key = &regfilter::readKey($in);
    if (!defined $key) {
	die "$prog: error reading key from $file - $regfilter::errorString\n";
    }
    if (!%$key) {
	$open = 0;
	next;
    }
    my $keyPrinted = 0;
    my $field;
    foreach $field (@{$key->{'entries'}}) {
	if ($field->{'value'} =~ /^hex/) {
	    my $str = '';
	    my $strX = '';
	    my $val = $field->{'value'};
	    $val =~ s/^hex(|\([0-9a-fA-F]+\))://;
	    my $i;
	    foreach $i (split(',', $val)) {
		if ($i =~ /^[0-9a-fA-F]{2}$/) {
		    my $c = chr(hex($i));
		    if ($c lt ' ' || $c gt '~') {
			$str .= '?';
		    } else {
			$str .= $c;
			$strX .= $c;
		    }
		}
	    }
	    next if ($quiteMode && $strX eq '');
	    if (!$keyPrinted) {
		print "\n[$key->{'key'}]\n";
		$keyPrinted = 1;
	    }
	    print "$field->{'name'}=";
	    print "$str" if !$onlyPrintable;
	    print "$sep($strX)" if $str ne $strX || $onlyPrintable;
	    print "\n";
	}
    }
}

exit(0);

__END__

=head1 NAME

reghexprint - prints hex entries in windows 9x registry dumps as characters

=head1 SYNOPSYS

B<reghexprint> [B<-p>] [B<-f>] [B<-V>] [reg-dump ...]

=head1 DESCRIPTION

B<reghexprint> scans a windows 9x registry dump (such as is produced
by B<regedit> or B<regdiff>) for entries that are encoded in hex
(I<i.e.>, ones preceded by C<hex:>) and prints the bytes as characters.
Non-printable characters are printed as a question mark.

Useful when scanning a registry dump for file paths and the like -
occasionally, these are encoded in hex fields and are therefore not
readily noticed.

=head1 OPTIONS

=over 4

=item B<-p>

Print only the printable characters - non-printable characters are completely
stripped.

=item B<-q>

Quite mode - only print hex entries that contain some printable characters.

=item B<-V>

Prints the version number - the program then exits
immediately.

=back


=head1 SEE ALSO

L<regedit>, L<regdiff>.

=head1 AUTHOR

Michael Rendell, Memorial University of Newfoundland (michael@cs.mun.ca).
