mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-14 17:06:16 +00:00
178 lines
4.9 KiB
Perl
178 lines
4.9 KiB
Perl
package Parse::Win32Registry::Win95::Value;
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use base qw(Parse::Win32Registry::Value);
|
|
|
|
use Carp;
|
|
use Encode;
|
|
use Parse::Win32Registry::Base qw(:all);
|
|
|
|
use constant RGDB_VALUE_HEADER_LENGTH => 0xc;
|
|
|
|
sub new {
|
|
my $class = shift;
|
|
my $regfile = shift;
|
|
my $offset = shift; # offset to RGDB value entry
|
|
|
|
croak 'Missing registry file' if !defined $regfile;
|
|
croak 'Missing offset' if !defined $offset;
|
|
|
|
my $fh = $regfile->get_filehandle;
|
|
|
|
# RGDB Value Entry
|
|
# 0x00 dword = value type
|
|
# 0x04
|
|
# 0x08 word = value name length
|
|
# 0x0a word = value data length
|
|
# 0x0c = value name [for name length bytes]
|
|
# + value data [for data length bytes]
|
|
# Value type may just be a word, not a dword;
|
|
# following word always appears to be zero.
|
|
|
|
sysseek($fh, $offset, 0);
|
|
my $bytes_read = sysread($fh, my $rgdb_value_entry,
|
|
RGDB_VALUE_HEADER_LENGTH);
|
|
if ($bytes_read != RGDB_VALUE_HEADER_LENGTH) {
|
|
warnf('Could not read RGDB value at 0x%x', $offset);
|
|
return;
|
|
}
|
|
|
|
my ($type,
|
|
$name_length,
|
|
$data_length) = unpack('Vx4vv', $rgdb_value_entry);
|
|
|
|
$bytes_read = sysread($fh, my $name, $name_length);
|
|
if ($bytes_read != $name_length) {
|
|
warnf('Could not read name for RGDB value at 0x%x', $offset);
|
|
return;
|
|
}
|
|
$name = decode($Parse::Win32Registry::Base::CODEPAGE, $name);
|
|
|
|
$bytes_read = sysread($fh, my $data, $data_length);
|
|
if ($bytes_read != $data_length) {
|
|
warnf('Could not read data for RGDB value at 0x%x', $offset);
|
|
return;
|
|
}
|
|
|
|
my $self = {};
|
|
$self->{_regfile} = $regfile;
|
|
$self->{_offset} = $offset;
|
|
$self->{_length} = RGDB_VALUE_HEADER_LENGTH + $name_length + $data_length;
|
|
$self->{_allocated} = 1;
|
|
$self->{_tag} = 'rgdb value';
|
|
$self->{_name} = $name;
|
|
$self->{_name_length} = $name_length;
|
|
$self->{_type} = $type;
|
|
$self->{_data} = $data;
|
|
$self->{_data_length} = $data_length;
|
|
bless $self, $class;
|
|
|
|
return $self;
|
|
}
|
|
|
|
sub get_data {
|
|
my $self = shift;
|
|
|
|
my $type = $self->get_type;
|
|
|
|
my $data = $self->{_data};
|
|
return if !defined $data; # actually, Win95 value data is always defined
|
|
|
|
# apply decoding to appropriate data types
|
|
if ($type == REG_DWORD) {
|
|
if (length($data) == 4) {
|
|
$data = unpack('V', $data);
|
|
}
|
|
else {
|
|
# incorrect length for dword data
|
|
$data = undef;
|
|
}
|
|
}
|
|
elsif ($type == REG_DWORD_BIG_ENDIAN) {
|
|
if (length($data) == 4) {
|
|
$data = unpack('N', $data);
|
|
}
|
|
else {
|
|
# incorrect length for dword data
|
|
$data = undef;
|
|
}
|
|
}
|
|
elsif ($type == REG_SZ || $type == REG_EXPAND_SZ) {
|
|
# Snip off any terminating null.
|
|
# Typically, REG_SZ values will not have a terminating null,
|
|
# while REG_EXPAND_SZ values will have a terminating null
|
|
chop $data if substr($data, -1, 1) eq "\0";
|
|
}
|
|
elsif ($type == REG_MULTI_SZ) {
|
|
# Snip off any terminating nulls
|
|
chop $data if substr($data, -1, 1) eq "\0";
|
|
chop $data if substr($data, -1, 1) eq "\0";
|
|
my @multi_sz = split("\0", $data, -1);
|
|
# Make sure there is at least one empty string
|
|
@multi_sz = ('') if @multi_sz == 0;
|
|
return wantarray ? @multi_sz : join($", @multi_sz);
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
sub as_regedit_export {
|
|
my $self = shift;
|
|
my $version = shift || 5;
|
|
|
|
my $name = $self->get_name;
|
|
my $export = $name eq '' ? '@=' : '"' . $name . '"=';
|
|
|
|
my $type = $self->get_type;
|
|
|
|
# XXX
|
|
# if (!defined $self->{_data}) {
|
|
# $name = $name eq '' ? '@' : qq{"$name"};
|
|
# return qq{; $name=(invalid data)\n};
|
|
# }
|
|
|
|
if ($type == REG_SZ) {
|
|
$export .= '"' . $self->get_data . '"';
|
|
$export .= "\n";
|
|
}
|
|
elsif ($type == REG_BINARY) {
|
|
$export .= 'hex:';
|
|
$export .= format_octets($self->{_data}, length($export));
|
|
}
|
|
elsif ($type == REG_DWORD) {
|
|
my $data = $self->get_data;
|
|
$export .= defined($data)
|
|
? sprintf("dword:%08x", $data)
|
|
: "dword:";
|
|
$export .= "\n";
|
|
}
|
|
elsif ($type == REG_EXPAND_SZ || $type == REG_MULTI_SZ) {
|
|
my $data = $version == 4
|
|
? $self->{_data} # raw data
|
|
: encode("UCS-2LE", $self->{_data}); # ansi->unicode
|
|
$export .= sprintf("hex(%x):", $type);
|
|
$export .= format_octets($data, length($export));
|
|
}
|
|
else {
|
|
$export .= sprintf("hex(%x):", $type);
|
|
$export .= format_octets($self->{_data}, length($export));
|
|
}
|
|
return $export;
|
|
}
|
|
|
|
sub parse_info {
|
|
my $self = shift;
|
|
|
|
my $info = sprintf '0x%x rgdb value len=0x%x "%s" type=%d data,len=0x%x',
|
|
$self->{_offset},
|
|
$self->{_length},
|
|
$self->{_name},
|
|
$self->{_type},
|
|
$self->{_data_length};
|
|
return $info;
|
|
}
|
|
|
|
1;
|