1use vmi_core::{Va, VmiError, VmiState, VmiVa, driver::VmiRead, trace::Hex};
2
3use super::{HCELL_INDEX_SIZE, WindowsHive, WindowsHiveCellIndex};
4use crate::{ArchAdapter, KeyValueIterator, WindowsError, WindowsOs, offset};
5
6const CM_KEY_VALUE_SPECIAL_SIZE: u32 = 0x8000_0000;
9
10const CM_KEY_VALUE_BIG: u32 = 0x3FD8;
17
18const HSYS_VERSION_4: u32 = 4;
23
24const CM_BIG_DATA_SIGNATURE: u16 = 0x6264; pub struct WindowsKeyValue<'a, Driver>
36where
37 Driver: VmiRead,
38 Driver::Architecture: ArchAdapter<Driver>,
39{
40 vmi: VmiState<'a, WindowsOs<Driver>>,
42
43 hive_va: Va,
45
46 va: Va,
48}
49
50impl<Driver> VmiVa for WindowsKeyValue<'_, Driver>
51where
52 Driver: VmiRead,
53 Driver::Architecture: ArchAdapter<Driver>,
54{
55 fn va(&self) -> Va {
56 self.va
57 }
58}
59
60bitflags::bitflags! {
61 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
63 pub struct WindowsKeyValueFlags: u16 {
64 const COMP_NAME = 0x0001;
66 }
67}
68
69#[derive(Debug, Clone, Copy, PartialEq, Eq)]
73pub enum WindowsKeyValueType {
74 None,
80
81 Sz,
87
88 ExpandSz,
94
95 Binary,
101
102 Dword,
108
109 DwordBigEndian,
115
116 Link,
122
123 MultiSz,
129
130 ResourceList,
136
137 FullResourceDescriptor,
143
144 ResourceRequirementsList,
150
151 Qword,
157
158 Unknown(u32),
160}
161
162impl From<WindowsKeyValueType> for u32 {
163 fn from(value: WindowsKeyValueType) -> Self {
164 match value {
165 WindowsKeyValueType::None => 0,
166 WindowsKeyValueType::Sz => 1,
167 WindowsKeyValueType::ExpandSz => 2,
168 WindowsKeyValueType::Binary => 3,
169 WindowsKeyValueType::Dword => 4,
170 WindowsKeyValueType::DwordBigEndian => 5,
171 WindowsKeyValueType::Link => 6,
172 WindowsKeyValueType::MultiSz => 7,
173 WindowsKeyValueType::ResourceList => 8,
174 WindowsKeyValueType::FullResourceDescriptor => 9,
175 WindowsKeyValueType::ResourceRequirementsList => 10,
176 WindowsKeyValueType::Qword => 11,
177 WindowsKeyValueType::Unknown(raw) => raw,
178 }
179 }
180}
181
182impl From<u32> for WindowsKeyValueType {
183 fn from(value: u32) -> Self {
184 match value {
185 0 => Self::None,
186 1 => Self::Sz,
187 2 => Self::ExpandSz,
188 3 => Self::Binary,
189 4 => Self::Dword,
190 5 => Self::DwordBigEndian,
191 6 => Self::Link,
192 7 => Self::MultiSz,
193 8 => Self::ResourceList,
194 9 => Self::FullResourceDescriptor,
195 10 => Self::ResourceRequirementsList,
196 11 => Self::Qword,
197 other => Self::Unknown(other),
198 }
199 }
200}
201
202#[derive(Debug, Clone)]
208pub enum WindowsKeyValueData {
209 None,
211
212 Sz(String),
214
215 ExpandSz(String),
217
218 Binary(Vec<u8>),
220
221 Dword(u32),
223
224 DwordBigEndian(u32),
226
227 Link(String),
229
230 MultiSz(Vec<String>),
232
233 ResourceList(Vec<u8>),
235
236 FullResourceDescriptor(Vec<u8>),
238
239 ResourceRequirementsList(Vec<u8>),
241
242 Qword(u64),
244
245 Unknown {
247 ty: u32,
249
250 bytes: Vec<u8>,
252 },
253}
254
255impl WindowsKeyValueData {
256 fn from_raw(value_type: WindowsKeyValueType, bytes: Vec<u8>) -> Self {
258 if bytes.is_empty() {
259 return Self::from_empty(value_type);
260 }
261
262 fn decode_utf16(bytes: &[u8]) -> String {
265 let (chunks, _) = bytes.as_chunks::<2>();
266 let units = chunks
267 .iter()
268 .map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]]))
269 .collect::<Vec<_>>();
270 let end = units.iter().rposition(|&ch| ch != 0).map_or(0, |i| i + 1);
271 String::from_utf16_lossy(&units[..end])
272 }
273
274 fn decode_utf16_multi(bytes: &[u8]) -> Vec<String> {
277 let (chunks, _) = bytes.as_chunks::<2>();
278 let units = chunks
279 .iter()
280 .map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]]))
281 .collect::<Vec<_>>();
282
283 units
284 .split(|&ch| ch == 0)
285 .filter(|slice| !slice.is_empty())
286 .map(String::from_utf16_lossy)
287 .collect()
288 }
289
290 fn decode_u32_le(bytes: &[u8]) -> u32 {
293 let mut buffer = [0u8; 4];
294 let n = bytes.len().min(4);
295 buffer[..n].copy_from_slice(&bytes[..n]);
296 u32::from_le_bytes(buffer)
297 }
298
299 fn decode_u32_be(bytes: &[u8]) -> u32 {
302 let mut buffer = [0u8; 4];
303 let n = bytes.len().min(4);
304 buffer[..n].copy_from_slice(&bytes[..n]);
305 u32::from_be_bytes(buffer)
306 }
307
308 fn decode_u64_le(bytes: &[u8]) -> u64 {
311 let mut buffer = [0u8; 8];
312 let n = bytes.len().min(8);
313 buffer[..n].copy_from_slice(&bytes[..n]);
314 u64::from_le_bytes(buffer)
315 }
316
317 match value_type {
318 WindowsKeyValueType::None => Self::None,
319 WindowsKeyValueType::Sz => Self::Sz(decode_utf16(&bytes)),
320 WindowsKeyValueType::ExpandSz => Self::ExpandSz(decode_utf16(&bytes)),
321 WindowsKeyValueType::Link => Self::Link(decode_utf16(&bytes)),
322 WindowsKeyValueType::MultiSz => Self::MultiSz(decode_utf16_multi(&bytes)),
323 WindowsKeyValueType::Binary => Self::Binary(bytes),
324 WindowsKeyValueType::Dword => Self::Dword(decode_u32_le(&bytes)),
325 WindowsKeyValueType::DwordBigEndian => Self::DwordBigEndian(decode_u32_be(&bytes)),
326 WindowsKeyValueType::Qword => Self::Qword(decode_u64_le(&bytes)),
327 WindowsKeyValueType::ResourceList => Self::ResourceList(bytes),
328 WindowsKeyValueType::FullResourceDescriptor => Self::FullResourceDescriptor(bytes),
329 WindowsKeyValueType::ResourceRequirementsList => Self::ResourceRequirementsList(bytes),
330 WindowsKeyValueType::Unknown(raw) => Self::Unknown { ty: raw, bytes },
331 }
332 }
333
334 fn from_empty(value_type: WindowsKeyValueType) -> Self {
336 match value_type {
337 WindowsKeyValueType::None => Self::None,
338 WindowsKeyValueType::Sz => Self::Sz(String::new()),
339 WindowsKeyValueType::ExpandSz => Self::ExpandSz(String::new()),
340 WindowsKeyValueType::Link => Self::Link(String::new()),
341 WindowsKeyValueType::MultiSz => Self::MultiSz(Vec::new()),
342 WindowsKeyValueType::Binary => Self::Binary(Vec::new()),
343 WindowsKeyValueType::ResourceList => Self::ResourceList(Vec::new()),
344 WindowsKeyValueType::FullResourceDescriptor => Self::FullResourceDescriptor(Vec::new()),
345 WindowsKeyValueType::ResourceRequirementsList => {
346 Self::ResourceRequirementsList(Vec::new())
347 }
348 WindowsKeyValueType::Dword | WindowsKeyValueType::DwordBigEndian => Self::Unknown {
349 ty: u32::from(value_type),
350 bytes: Vec::new(),
351 },
352 WindowsKeyValueType::Qword => Self::Unknown {
353 ty: u32::from(value_type),
354 bytes: Vec::new(),
355 },
356 WindowsKeyValueType::Unknown(raw) => Self::Unknown {
357 ty: raw,
358 bytes: Vec::new(),
359 },
360 }
361 }
362}
363
364impl<'a, Driver> WindowsKeyValue<'a, Driver>
365where
366 Driver: VmiRead,
367 Driver::Architecture: ArchAdapter<Driver>,
368{
369 pub const SIGNATURE: u16 = 0x6b76; pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, hive_va: Va, va: Va) -> Self {
378 Self { vmi, hive_va, va }
379 }
380
381 pub fn signature(&self) -> Result<u16, VmiError> {
387 let CM_KEY_VALUE = offset!(self.vmi, _CM_KEY_VALUE);
388
389 self.vmi.read_u16(self.va + CM_KEY_VALUE.Signature.offset())
390 }
391
392 pub fn flags(&self) -> Result<WindowsKeyValueFlags, VmiError> {
398 let CM_KEY_VALUE = offset!(self.vmi, _CM_KEY_VALUE);
399
400 let flags = self.vmi.read_u16(self.va + CM_KEY_VALUE.Flags.offset())?;
401 Ok(WindowsKeyValueFlags::from_bits_truncate(flags))
402 }
403
404 pub fn value_type(&self) -> Result<WindowsKeyValueType, VmiError> {
410 let CM_KEY_VALUE = offset!(self.vmi, _CM_KEY_VALUE);
411
412 let ty = self.vmi.read_u32(self.va + CM_KEY_VALUE.Type.offset())?;
413 Ok(WindowsKeyValueType::from(ty))
414 }
415
416 pub fn name(&self) -> Result<String, VmiError> {
424 let CM_KEY_VALUE = offset!(self.vmi, _CM_KEY_VALUE);
425
426 let flags = self.flags()?;
427 let name_length = self
428 .vmi
429 .read_u16(self.va + CM_KEY_VALUE.NameLength.offset())?;
430 let name_va = self.va + CM_KEY_VALUE.Name.offset();
431
432 if flags.contains(WindowsKeyValueFlags::COMP_NAME) {
433 self.vmi.read_string_limited(name_va, name_length as usize)
434 }
435 else {
436 self.vmi
437 .read_string_utf16_limited(name_va, name_length as usize)
438 }
439 }
440
441 pub fn data_bytes(&self) -> Result<Vec<u8>, VmiError> {
453 let CM_KEY_VALUE = offset!(self.vmi, _CM_KEY_VALUE);
454
455 let data_length_raw = self
456 .vmi
457 .read_u32(self.va + CM_KEY_VALUE.DataLength.offset())?;
458
459 if data_length_raw & CM_KEY_VALUE_SPECIAL_SIZE != 0 {
460 let size = ((data_length_raw & !CM_KEY_VALUE_SPECIAL_SIZE) as usize).min(4);
461 let mut buffer = vec![0u8; size];
462 self.vmi
463 .read(self.va + CM_KEY_VALUE.Data.offset(), &mut buffer)?;
464 return Ok(buffer);
465 }
466
467 let data_length = data_length_raw as usize;
468 if data_length == 0 {
469 return Ok(Vec::new());
470 }
471
472 let data_index = self.vmi.read_u32(self.va + CM_KEY_VALUE.Data.offset())?;
476 let hive = WindowsHive::new(self.vmi, self.hive_va);
477 let data_va = match hive.cell(WindowsHiveCellIndex::new(data_index))? {
478 Some(data_va) => data_va,
479 None => return Err(WindowsError::CorruptedStruct("CM_KEY_VALUE.Data").into()),
480 };
481
482 if hive.version()? >= HSYS_VERSION_4 && data_length_raw > CM_KEY_VALUE_BIG {
483 return self.read_big_data(&hive, data_va, data_length);
484 }
485
486 let mut buffer = vec![0u8; data_length];
487 self.vmi.read(data_va, &mut buffer)?;
488 Ok(buffer)
489 }
490
491 pub fn data(&self) -> Result<WindowsKeyValueData, VmiError> {
496 let value_type = self.value_type()?;
497 let bytes = self.data_bytes()?;
498
499 Ok(WindowsKeyValueData::from_raw(value_type, bytes))
500 }
501
502 fn read_big_data(
511 &self,
512 hive: &WindowsHive<'a, Driver>,
513 big_data_va: Va,
514 total_length: usize,
515 ) -> Result<Vec<u8>, VmiError> {
516 let CM_BIG_DATA = offset!(self.vmi, _CM_BIG_DATA);
517
518 let signature = self
519 .vmi
520 .read_u16(big_data_va + CM_BIG_DATA.Signature.offset())?;
521 if signature != CM_BIG_DATA_SIGNATURE {
522 tracing::warn!(
523 signature = %Hex(signature),
524 expected = %Hex(CM_BIG_DATA_SIGNATURE),
525 hive = %hive.va(),
526 cell = %big_data_va,
527 "cell classified as _CM_BIG_DATA but signature mismatches"
528 );
529 }
530
531 let count = self
532 .vmi
533 .read_u16(big_data_va + CM_BIG_DATA.Count.offset())? as usize;
534 let list_index = self.vmi.read_u32(big_data_va + CM_BIG_DATA.List.offset())?;
535
536 let list_va = match hive.cell(WindowsHiveCellIndex::new(list_index))? {
539 Some(list_va) => list_va,
540 None => return Err(WindowsError::CorruptedStruct("CM_BIG_DATA.List").into()),
541 };
542
543 let segment_size = CM_KEY_VALUE_BIG as usize;
544 let mut buffer = Vec::with_capacity(total_length);
545 let mut remaining = total_length;
546
547 for i in 0..count {
548 if remaining == 0 {
549 break;
550 }
551
552 let segment_index = self.vmi.read_u32(list_va + (i as u64) * HCELL_INDEX_SIZE)?;
553 let segment_va = match hive.cell(WindowsHiveCellIndex::new(segment_index))? {
554 Some(segment_va) => segment_va,
555 None => return Err(WindowsError::CorruptedStruct("CM_BIG_DATA.List[]").into()),
556 };
557
558 let chunk = remaining.min(segment_size);
559 let start = buffer.len();
560 buffer.resize(start + chunk, 0);
561
562 self.vmi
563 .read(segment_va, &mut buffer[start..start + chunk])?;
564
565 remaining -= chunk;
566 }
567
568 Ok(buffer)
569 }
570}
571
572pub(super) fn values_iterator<'a, Driver>(
574 vmi: VmiState<'a, WindowsOs<Driver>>,
575 hive_va: Va,
576 list_index: WindowsHiveCellIndex,
577 count: u32,
578) -> Result<KeyValueIterator<'a, Driver>, VmiError>
579where
580 Driver: VmiRead,
581 Driver::Architecture: ArchAdapter<Driver>,
582{
583 if count == 0 || list_index.is_nil() {
584 return Ok(KeyValueIterator::empty(vmi, hive_va));
585 }
586
587 let hive = WindowsHive::new(vmi, hive_va);
590 let list_va = match hive.cell(list_index)? {
591 Some(list_va) => list_va,
592 None => return Err(WindowsError::CorruptedStruct("CM_KEY_NODE.ValueList.List").into()),
593 };
594
595 Ok(KeyValueIterator::new(vmi, hive_va, list_va, count))
596}