mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-12 07:56:16 +00:00
208 lines
5.5 KiB
Perl
208 lines
5.5 KiB
Perl
package Parse::Win32Registry::Win95::Key;
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use base qw(Parse::Win32Registry::Key);
|
|
|
|
use Carp;
|
|
use Parse::Win32Registry::Base qw(:all);
|
|
use Parse::Win32Registry::Win95::Value;
|
|
|
|
use constant RGKN_ENTRY_LENGTH => 0x1c;
|
|
use constant OFFSET_TO_RGKN_BLOCK => 0x20;
|
|
|
|
sub new {
|
|
my $class = shift;
|
|
my $regfile = shift;
|
|
my $offset = shift; # offset to RGKN key entry relative to start of RGKN
|
|
my $parent_key_path = shift; # parent key path (optional)
|
|
|
|
croak 'Missing registry file' if !defined $regfile;
|
|
croak 'Missing offset' if !defined $offset;
|
|
|
|
my $fh = $regfile->get_filehandle;
|
|
|
|
# RGKN Key Entry
|
|
# 0x00 dword
|
|
# 0x04 dword
|
|
# 0x08 dword
|
|
# 0x0c dword = offset to parent RGKN entry
|
|
# 0x10 dword = offset to first child RGKN entry
|
|
# 0x14 dword = offset to next sibling RGKN entry
|
|
# 0x18 dword = entry id of RGDB entry
|
|
|
|
# Extracted offsets are relative to the start of the RGKN block
|
|
|
|
# Any offset of 0xffffffff marks the end of a list.
|
|
# An entry id of 0xffffffff means the RGKN entry has no RGDB entry.
|
|
# This occurs for the root key of the registry file.
|
|
|
|
sysseek($fh, $offset, 0);
|
|
my $bytes_read = sysread($fh, my $rgkn_entry, RGKN_ENTRY_LENGTH);
|
|
if ($bytes_read != RGKN_ENTRY_LENGTH) {
|
|
warnf('Could not read RGKN key at 0x%x', $offset);
|
|
return;
|
|
}
|
|
|
|
my ($offset_to_parent,
|
|
$offset_to_first_child,
|
|
$offset_to_next_sibling,
|
|
$key_id) = unpack('x12VVVV', $rgkn_entry);
|
|
|
|
$offset_to_parent += OFFSET_TO_RGKN_BLOCK
|
|
if $offset_to_parent != 0xffffffff;
|
|
$offset_to_first_child += OFFSET_TO_RGKN_BLOCK
|
|
if $offset_to_first_child != 0xffffffff;
|
|
$offset_to_next_sibling += OFFSET_TO_RGKN_BLOCK
|
|
if $offset_to_next_sibling != 0xffffffff;
|
|
|
|
my $self = {};
|
|
$self->{_regfile} = $regfile;
|
|
$self->{_offset} = $offset;
|
|
$self->{_length} = RGKN_ENTRY_LENGTH;
|
|
$self->{_allocated} = 1;
|
|
$self->{_tag} = 'rgkn key';
|
|
$self->{_offset_to_parent} = $offset_to_parent;
|
|
$self->{_offset_to_first_child} = $offset_to_first_child;
|
|
$self->{_offset_to_next_sibling} = $offset_to_next_sibling;
|
|
$self->{_id} = $key_id;
|
|
bless $self, $class;
|
|
|
|
# Look up corresponding rgdb entry
|
|
my $index = $regfile->{_rgdb_index};
|
|
croak 'Missing rgdb index' if !defined $index;
|
|
if (exists $index->{$key_id}) {
|
|
my $rgdb_key = $index->{$key_id};
|
|
$self->{_rgdb_key} = $rgdb_key;
|
|
$self->{_name} = $rgdb_key->get_name;
|
|
}
|
|
else {
|
|
$self->{_name} = '';
|
|
# Only the root key should have no matching RGDB entry
|
|
if (!$self->is_root) {
|
|
warnf('Could not find RGDB entry for RGKN key at 0x%x', $offset);
|
|
}
|
|
}
|
|
|
|
my $name = $self->{_name};
|
|
$self->{_key_path} = defined($parent_key_path)
|
|
? "$parent_key_path\\$name"
|
|
: $name;
|
|
|
|
return $self;
|
|
}
|
|
|
|
sub get_timestamp {
|
|
return undef;
|
|
}
|
|
|
|
sub get_timestamp_as_string {
|
|
return iso8601(undef);
|
|
}
|
|
|
|
sub get_class_name {
|
|
return undef;
|
|
}
|
|
|
|
sub is_root {
|
|
my $self = shift;
|
|
|
|
my $offset = $self->{_offset};
|
|
my $regfile = $self->{_regfile};
|
|
|
|
my $rgkn_block = $regfile->get_rgkn;
|
|
my $offset_to_root_key = $rgkn_block->{_offset_to_root_key};
|
|
|
|
# This gives better results than checking id == 0xffffffff
|
|
return $offset == $offset_to_root_key;
|
|
}
|
|
|
|
sub get_parent {
|
|
my $self = shift;
|
|
|
|
my $regfile = $self->{_regfile};
|
|
my $offset_to_parent = $self->{_offset_to_parent};
|
|
my $key_path = $self->{_key_path};
|
|
|
|
return if $self->is_root;
|
|
|
|
my $grandparent_key_path;
|
|
my @keys = split(/\\/, $key_path, -1);
|
|
if (@keys > 2) {
|
|
$grandparent_key_path = join("\\", @keys[0..$#keys-2]);
|
|
}
|
|
|
|
return Parse::Win32Registry::Win95::Key->new($regfile,
|
|
$offset_to_parent,
|
|
$grandparent_key_path);
|
|
}
|
|
|
|
sub get_security {
|
|
return undef;
|
|
}
|
|
|
|
sub as_string {
|
|
my $self = shift;
|
|
|
|
return $self->get_path;
|
|
}
|
|
|
|
sub parse_info {
|
|
my $self = shift;
|
|
|
|
my $info = sprintf '0x%x rgkn key len=0x%x par=0x%x,child=0x%x,next=0x%x id=0x%x',
|
|
$self->{_offset},
|
|
$self->{_length},
|
|
$self->{_offset_to_parent},
|
|
$self->{_offset_to_first_child},
|
|
$self->{_offset_to_next_sibling},
|
|
$self->{_id};
|
|
return $info;
|
|
}
|
|
|
|
sub get_subkey_iterator {
|
|
my $self = shift;
|
|
|
|
my $regfile = $self->{_regfile};
|
|
my $key_path = $self->{_key_path};
|
|
|
|
my $offset_to_next_key = $self->{_offset_to_first_child};
|
|
|
|
my $end_of_file = $regfile->get_length;
|
|
my $rgkn_block = $regfile->get_rgkn;
|
|
my $end_of_rgkn_block = $rgkn_block->get_offset + $rgkn_block->get_length;
|
|
|
|
return Parse::Win32Registry::Iterator->new(sub {
|
|
if ($offset_to_next_key == 0xffffffff) {
|
|
return; # no more subkeys
|
|
}
|
|
if ($offset_to_next_key > $end_of_rgkn_block) {
|
|
return;
|
|
}
|
|
if (my $key = Parse::Win32Registry::Win95::Key->new($regfile,
|
|
$offset_to_next_key, $key_path))
|
|
{
|
|
$offset_to_next_key = $key->{_offset_to_next_sibling};
|
|
return $key;
|
|
}
|
|
else {
|
|
return; # no more subkeys
|
|
}
|
|
});
|
|
}
|
|
|
|
sub get_value_iterator {
|
|
my $self = shift;
|
|
|
|
my $rgdb_key = $self->{_rgdb_key};
|
|
if (defined $rgdb_key) {
|
|
return $rgdb_key->get_value_iterator;
|
|
}
|
|
else {
|
|
return Parse::Win32Registry::Iterator->new(sub {});
|
|
}
|
|
}
|
|
|
|
1;
|