1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
//! Key security (sk) structure.
//!
//! Key security items contain security descriptors for registry keys.
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::io::{self, Cursor, Read, Write};
use crate::error::{Error, Result};
use crate::structures::signatures;
/// Key security structure (sk).
#[derive(Debug, Clone)]
pub struct KeySecurity {
/// Signature: "sk"
pub signature: [u8; 2],
/// Reserved.
pub reserved: u16,
/// Forward link to next security item.
pub flink: u32,
/// Backward link to previous security item.
pub blink: u32,
/// Reference count (number of keys using this security descriptor).
pub reference_count: u32,
/// Security descriptor size in bytes.
pub security_descriptor_size: u32,
/// Security descriptor data.
pub security_descriptor: Vec<u8>,
}
impl KeySecurity {
/// Size of the fixed part of the key security item (excluding descriptor).
pub const FIXED_SIZE: usize = 20;
/// Parse a key security item from a byte slice.
pub fn parse(data: &[u8]) -> Result<Self> {
if data.len() < Self::FIXED_SIZE {
return Err(Error::BufferTooSmall {
needed: Self::FIXED_SIZE,
available: data.len(),
});
}
let mut cursor = Cursor::new(data);
let mut signature = [0u8; 2];
cursor.read_exact(&mut signature)?;
if &signature != signatures::KEY_SECURITY {
return Err(Error::InvalidSignature {
expected: "sk".to_string(),
found: String::from_utf8_lossy(&signature).to_string(),
});
}
let reserved = cursor.read_u16::<LittleEndian>()?;
let flink = cursor.read_u32::<LittleEndian>()?;
let blink = cursor.read_u32::<LittleEndian>()?;
let reference_count = cursor.read_u32::<LittleEndian>()?;
let security_descriptor_size = cursor.read_u32::<LittleEndian>()?;
// Read security descriptor
let sd_start = Self::FIXED_SIZE;
let sd_end = sd_start + security_descriptor_size as usize;
if data.len() < sd_end {
return Err(Error::BufferTooSmall {
needed: sd_end,
available: data.len(),
});
}
let security_descriptor = data[sd_start..sd_end].to_vec();
Ok(Self {
signature,
reserved,
flink,
blink,
reference_count,
security_descriptor_size,
security_descriptor,
})
}
/// Write the key security item to a writer.
pub fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
writer.write_all(&self.signature)?;
writer.write_u16::<LittleEndian>(self.reserved)?;
writer.write_u32::<LittleEndian>(self.flink)?;
writer.write_u32::<LittleEndian>(self.blink)?;
writer.write_u32::<LittleEndian>(self.reference_count)?;
writer.write_u32::<LittleEndian>(self.security_descriptor_size)?;
writer.write_all(&self.security_descriptor)?;
Ok(())
}
/// Create a new key security item.
/// Note: flink and blink should be set to point to itself initially,
/// representing a list header with no entries.
pub fn new(security_descriptor: Vec<u8>) -> Self {
let size = security_descriptor.len() as u32;
Self {
signature: *signatures::KEY_SECURITY,
reserved: 0,
// flink and blink are set to 0 initially, but should be updated
// to point to the cell's own offset when placed in the hive.
// For a list header with no entries, flink and blink point to itself.
flink: 0,
blink: 0,
reference_count: 1,
security_descriptor_size: size,
security_descriptor,
}
}
/// Create a new key security item with proper self-referencing flink/blink.
/// The offset parameter should be the cell offset where this security item is stored.
pub fn new_at_offset(security_descriptor: Vec<u8>, offset: u32) -> Self {
let size = security_descriptor.len() as u32;
Self {
signature: *signatures::KEY_SECURITY,
reserved: 0,
// For a list header, flink and blink point to itself
flink: offset,
blink: offset,
reference_count: 1,
security_descriptor_size: size,
security_descriptor,
}
}
/// Update flink/blink to point to own offset (makes this a self-contained list header).
pub fn set_self_referencing(&mut self, offset: u32) {
self.flink = offset;
self.blink = offset;
}
/// Link this security item into an existing list.
/// This updates the item to be inserted after the item at `prev_offset`.
pub fn link_after(&mut self, prev_offset: u32, next_offset: u32) {
self.blink = prev_offset;
self.flink = next_offset;
}
/// Create a minimal security descriptor allowing full access.
pub fn new_default() -> Self {
// This is a minimal self-relative security descriptor with:
// - DACL present, allowing Everyone full access
// - Owner: Administrators
// - Group: Administrators
// Minimal security descriptor structure
let sd = vec![
0x01, // Revision
0x00, // Sbz1
0x04, 0x80, // Control (SE_SELF_RELATIVE | SE_DACL_PRESENT)
0x14, 0x00, 0x00, 0x00, // Owner offset
0x24, 0x00, 0x00, 0x00, // Group offset
0x00, 0x00, 0x00, 0x00, // SACL offset (none)
0x34, 0x00, 0x00, 0x00, // DACL offset
// Owner SID (S-1-5-32-544 Administrators)
0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x20, 0x02,
0x00, 0x00, // Group SID (S-1-5-32-544 Administrators)
0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x20, 0x00, 0x00, 0x00, 0x20, 0x02,
0x00, 0x00, // DACL
0x02, // AclRevision
0x00, // Sbz1
0x1C, 0x00, // AclSize
0x01, 0x00, // AceCount
0x00, 0x00, // Sbz2
// ACE (Allow Everyone Full Access)
0x00, // AceType (ACCESS_ALLOWED_ACE_TYPE)
0x00, // AceFlags
0x14, 0x00, // AceSize
0xFF, 0x01, 0x1F, 0x00, // AccessMask (KEY_ALL_ACCESS)
// SID (S-1-1-0 Everyone)
0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
];
Self::new(sd)
}
/// Get the total size needed for this key security item.
pub fn total_size(&self) -> usize {
Self::FIXED_SIZE + self.security_descriptor.len()
}
/// Serialize to bytes.
pub fn to_bytes(&self) -> Vec<u8> {
let mut buffer = Vec::new();
self.write(&mut buffer).unwrap();
buffer
}
/// Increment reference count.
pub fn add_ref(&mut self) {
self.reference_count += 1;
}
/// Decrement reference count. Returns true if still referenced.
pub fn release(&mut self) -> bool {
if self.reference_count > 0 {
self.reference_count -= 1;
}
self.reference_count > 0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_key_security_creation() {
let sd = vec![1, 2, 3, 4, 5];
let ks = KeySecurity::new(sd.clone());
assert_eq!(ks.security_descriptor, sd);
assert_eq!(ks.reference_count, 1);
}
#[test]
fn test_key_security_roundtrip() {
let ks = KeySecurity::new_default();
let bytes = ks.to_bytes();
let parsed = KeySecurity::parse(&bytes).unwrap();
assert_eq!(parsed.security_descriptor, ks.security_descriptor);
}
#[test]
fn test_reference_count() {
let mut ks = KeySecurity::new_default();
assert_eq!(ks.reference_count, 1);
ks.add_ref();
assert_eq!(ks.reference_count, 2);
assert!(ks.release());
assert_eq!(ks.reference_count, 1);
assert!(!ks.release());
assert_eq!(ks.reference_count, 0);
}
}