line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Parse::Win32Registry::WinNT::Security; |
2
|
|
|
|
|
|
|
|
3
|
13
|
|
|
13
|
|
72
|
use strict; |
|
13
|
|
|
|
|
30
|
|
|
13
|
|
|
|
|
439
|
|
4
|
13
|
|
|
13
|
|
67
|
use warnings; |
|
13
|
|
|
|
|
26
|
|
|
13
|
|
|
|
|
363
|
|
5
|
|
|
|
|
|
|
|
6
|
13
|
|
|
13
|
|
62
|
use base qw(Parse::Win32Registry::Entry); |
|
13
|
|
|
|
|
21
|
|
|
13
|
|
|
|
|
1107
|
|
7
|
|
|
|
|
|
|
|
8
|
13
|
|
|
13
|
|
70
|
use Carp; |
|
13
|
|
|
|
|
23
|
|
|
13
|
|
|
|
|
839
|
|
9
|
13
|
|
|
13
|
|
69
|
use Parse::Win32Registry::Base qw(:all); |
|
13
|
|
|
|
|
24
|
|
|
13
|
|
|
|
|
3805
|
|
10
|
|
|
|
|
|
|
|
11
|
13
|
|
|
13
|
|
75
|
use constant SK_HEADER_LENGTH => 0x18; |
|
13
|
|
|
|
|
22
|
|
|
13
|
|
|
|
|
674
|
|
12
|
13
|
|
|
13
|
|
72
|
use constant OFFSET_TO_FIRST_HBIN => 0x1000; |
|
13
|
|
|
|
|
25
|
|
|
13
|
|
|
|
|
9751
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
sub new { |
15
|
14
|
|
|
14
|
0
|
358
|
my $class = shift; |
16
|
14
|
|
|
|
|
26
|
my $regfile = shift; |
17
|
14
|
|
|
|
|
25
|
my $offset = shift; # offset to sk record relative to start of file |
18
|
|
|
|
|
|
|
|
19
|
14
|
50
|
|
|
|
62
|
croak 'Missing registry file' if !defined $regfile; |
20
|
14
|
50
|
|
|
|
44
|
croak 'Missing offset' if !defined $offset; |
21
|
|
|
|
|
|
|
|
22
|
14
|
50
|
|
|
|
60
|
if (defined(my $cache = $regfile->{_security_cache})) { |
23
|
14
|
100
|
|
|
|
51
|
if (exists $cache->{$offset}) { |
24
|
2
|
|
|
|
|
16
|
return $cache->{$offset}; |
25
|
|
|
|
|
|
|
} |
26
|
|
|
|
|
|
|
} |
27
|
|
|
|
|
|
|
|
28
|
12
|
|
|
|
|
72
|
my $fh = $regfile->get_filehandle; |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
# 0x00 dword = security length (negative = allocated) |
31
|
|
|
|
|
|
|
# 0x04 word = 'sk' signature |
32
|
|
|
|
|
|
|
# 0x08 dword = offset to previous sk |
33
|
|
|
|
|
|
|
# 0x0c dword = offset to next sk |
34
|
|
|
|
|
|
|
# 0x10 dword = ref count |
35
|
|
|
|
|
|
|
# 0x14 dword = length of security descriptor |
36
|
|
|
|
|
|
|
# 0x18 = start of security descriptor |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# Extracted offsets are always relative to first hbin |
39
|
|
|
|
|
|
|
|
40
|
12
|
|
|
|
|
69
|
sysseek($fh, $offset, 0); |
41
|
12
|
|
|
|
|
104
|
my $bytes_read = sysread($fh, my $sk_header, SK_HEADER_LENGTH); |
42
|
12
|
100
|
|
|
|
37
|
if ($bytes_read != SK_HEADER_LENGTH) { |
43
|
1
|
|
|
|
|
6
|
warnf('Could not read security at 0x%x', $offset); |
44
|
1
|
|
|
|
|
12
|
return; |
45
|
|
|
|
|
|
|
} |
46
|
|
|
|
|
|
|
|
47
|
11
|
|
|
|
|
505
|
my ($length, |
48
|
|
|
|
|
|
|
$sig, |
49
|
|
|
|
|
|
|
$offset_to_previous, |
50
|
|
|
|
|
|
|
$offset_to_next, |
51
|
|
|
|
|
|
|
$ref_count, |
52
|
|
|
|
|
|
|
$sd_length, |
53
|
|
|
|
|
|
|
) = unpack('Va2x2VVVV', $sk_header); |
54
|
|
|
|
|
|
|
|
55
|
11
|
50
|
|
|
|
39
|
$offset_to_previous += OFFSET_TO_FIRST_HBIN |
56
|
|
|
|
|
|
|
if $offset_to_previous != 0xffffffff; |
57
|
11
|
50
|
|
|
|
31
|
$offset_to_next += OFFSET_TO_FIRST_HBIN |
58
|
|
|
|
|
|
|
if $offset_to_next != 0xffffffff; |
59
|
|
|
|
|
|
|
|
60
|
11
|
|
|
|
|
145
|
my $allocated = 0; |
61
|
11
|
50
|
|
|
|
32
|
if ($length > 0x7fffffff) { |
62
|
11
|
|
|
|
|
16
|
$allocated = 1; |
63
|
11
|
|
|
|
|
22
|
$length = (0xffffffff - $length) + 1; |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
# allocated should be true |
66
|
|
|
|
|
|
|
|
67
|
11
|
100
|
|
|
|
44
|
if ($sig ne 'sk') { |
68
|
1
|
|
|
|
|
3
|
warnf('Invalid signature for security at 0x%x', $offset); |
69
|
1
|
|
|
|
|
13
|
return; |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
|
72
|
10
|
|
|
|
|
69
|
$bytes_read = sysread($fh, my $sd_data, $sd_length); |
73
|
10
|
100
|
|
|
|
43
|
if ($bytes_read != $sd_length) { |
74
|
1
|
|
|
|
|
5
|
warnf('Could not read security descriptor for security at 0x%x', |
75
|
|
|
|
|
|
|
$offset); |
76
|
1
|
|
|
|
|
12
|
return; |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
9
|
|
|
|
|
47
|
my $sd = unpack_security_descriptor($sd_data); |
80
|
9
|
100
|
|
|
|
37
|
if (!defined $sd) { |
81
|
1
|
|
|
|
|
4
|
warnf('Invalid security descriptor for security at 0x%x', |
82
|
|
|
|
|
|
|
$offset); |
83
|
|
|
|
|
|
|
# Abandon security object if security descriptor is invalid |
84
|
1
|
|
|
|
|
16
|
return; |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
8
|
|
|
|
|
16
|
my $self = {}; |
88
|
8
|
|
|
|
|
23
|
$self->{_regfile} = $regfile; |
89
|
8
|
|
|
|
|
26
|
$self->{_offset} = $offset; |
90
|
8
|
|
|
|
|
18
|
$self->{_length} = $length; |
91
|
8
|
|
|
|
|
67
|
$self->{_allocated} = $allocated; |
92
|
8
|
|
|
|
|
24
|
$self->{_tag} = $sig; |
93
|
8
|
|
|
|
|
23
|
$self->{_offset_to_previous} = $offset_to_previous; |
94
|
8
|
|
|
|
|
17
|
$self->{_offset_to_next} = $offset_to_next; |
95
|
8
|
|
|
|
|
26
|
$self->{_ref_count} = $ref_count; |
96
|
8
|
|
|
|
|
17
|
$self->{_security_descriptor_length} = $sd_length; |
97
|
8
|
|
|
|
|
16
|
$self->{_security_descriptor} = $sd; |
98
|
8
|
|
|
|
|
33
|
bless $self, $class; |
99
|
|
|
|
|
|
|
|
100
|
8
|
50
|
|
|
|
186
|
if (defined(my $cache = $regfile->{_security_cache})) { |
101
|
8
|
|
|
|
|
24
|
$cache->{$offset} = $self; |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
|
104
|
8
|
|
|
|
|
53
|
return $self; |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
sub get_previous { |
108
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
109
|
0
|
|
|
|
|
0
|
my $regfile = $self->{_regfile}; |
110
|
0
|
|
|
|
|
0
|
my $offset_to_previous = $self->{_offset_to_previous}; |
111
|
|
|
|
|
|
|
|
112
|
0
|
|
|
|
|
0
|
return Parse::Win32Registry::WinNT::Security->new($regfile, |
113
|
|
|
|
|
|
|
$offset_to_previous); |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
sub get_next { |
117
|
7
|
|
|
7
|
0
|
15
|
my $self = shift; |
118
|
7
|
|
|
|
|
17
|
my $regfile = $self->{_regfile}; |
119
|
7
|
|
|
|
|
21
|
my $offset_to_next = $self->{_offset_to_next}; |
120
|
|
|
|
|
|
|
|
121
|
7
|
|
|
|
|
33
|
return Parse::Win32Registry::WinNT::Security->new($regfile, |
122
|
|
|
|
|
|
|
$offset_to_next); |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
sub get_reference_count { |
126
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
127
|
|
|
|
|
|
|
|
128
|
0
|
|
|
|
|
0
|
return $self->{_ref_count}; |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
sub get_security_descriptor { |
132
|
7
|
|
|
7
|
0
|
13
|
my $self = shift; |
133
|
|
|
|
|
|
|
|
134
|
7
|
|
|
|
|
37
|
return $self->{_security_descriptor}; |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
sub as_string { |
138
|
2
|
|
|
2
|
0
|
6
|
my $self = shift; |
139
|
|
|
|
|
|
|
|
140
|
2
|
|
|
|
|
9
|
return '(security entry)'; |
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
sub parse_info { |
144
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
145
|
|
|
|
|
|
|
|
146
|
0
|
|
|
|
|
|
my $info = sprintf '0x%x sk len=0x%x alloc=%d prev=0x%x,next=0x%x refs=%d', |
147
|
|
|
|
|
|
|
$self->{_offset}, |
148
|
|
|
|
|
|
|
$self->{_length}, |
149
|
|
|
|
|
|
|
$self->{_allocated}, |
150
|
|
|
|
|
|
|
$self->{_offset_to_previous}, |
151
|
|
|
|
|
|
|
$self->{_offset_to_next}, |
152
|
|
|
|
|
|
|
$self->{_ref_count}; |
153
|
|
|
|
|
|
|
|
154
|
0
|
|
|
|
|
|
return $info; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
1; |