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
pub use byteorder::{LittleEndian, ReadBytesExt};
use crate::error::Error;
use crate::utils::read_len_prefixed_utf16_string;
use crate::Offset;
use log::trace;
use std::borrow::Cow;
use std::io::{Cursor, Seek, SeekFrom};
use crate::evtx_chunk::EvtxChunk;
use quick_xml::events::{BytesEnd, BytesStart};
#[derive(Debug, PartialEq, PartialOrd, Clone)]
pub struct BinXmlName<'a>(pub Cow<'a, str>);
pub type StringHashOffset = (String, u16, Offset);
impl<'a> BinXmlName<'a> {
pub fn from_static_string(s: &'static str) -> Self {
BinXmlName(Cow::Borrowed(s))
}
pub fn from_binxml_stream(
cursor: &mut Cursor<&'a [u8]>,
chunk: Option<&'a EvtxChunk<'a>>,
) -> Result<BinXmlName<'a>, Error> {
let name_offset = try_read!(cursor, u32);
if let Some((name, _, n_bytes_read)) =
chunk.and_then(|chunk| chunk.string_cache.get_string_and_hash(name_offset))
{
if name_offset == cursor.position() as u32 {
cursor.seek(SeekFrom::Current(i64::from(*n_bytes_read)))?;
}
return Ok(BinXmlName(Cow::Borrowed(name)));
}
let (name, _, _) = Self::from_stream_at_offset(cursor, name_offset)?;
Ok(BinXmlName(Cow::Owned(name)))
}
pub fn from_stream(cursor: &mut Cursor<&'a [u8]>) -> Result<StringHashOffset, Error> {
let position_before_read = cursor.position();
let _ = try_read!(cursor, u32);
let name_hash = try_read!(cursor, u16);
let name = read_len_prefixed_utf16_string(cursor, true)
.map_err(|e| Error::utf16_decode_error(e, cursor.position()))?
.unwrap_or_else(String::new);
let position_after_read = cursor.position();
Ok((
name,
name_hash,
(position_after_read - position_before_read) as Offset,
))
}
fn from_stream_at_offset(
cursor: &mut Cursor<&'a [u8]>,
offset: Offset,
) -> Result<StringHashOffset, Error> {
if offset != cursor.position() as u32 {
trace!(
"Current offset {}, seeking to {}",
cursor.position(),
offset
);
let position_before_seek = cursor.position();
cursor.seek(SeekFrom::Start(u64::from(offset)))?;
let (name, hash, n_bytes_read) = Self::from_stream(cursor)?;
trace!("Restoring cursor to {}", position_before_seek);
cursor.seek(SeekFrom::Start(position_before_seek as u64))?;
Ok((name, hash, n_bytes_read))
} else {
trace!("Name is at current offset");
let (name, hash, n_bytes_read) = Self::from_stream(cursor)?;
Ok((name, hash, n_bytes_read))
}
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl<'a> Into<quick_xml::events::BytesStart<'a>> for &'a BinXmlName<'a> {
fn into(self) -> BytesStart<'a> {
BytesStart::borrowed_name(self.0.as_bytes())
}
}
impl<'a> Into<quick_xml::events::BytesEnd<'a>> for BinXmlName<'a> {
fn into(self) -> BytesEnd<'a> {
let inner = self.0.as_bytes();
BytesEnd::owned(inner.to_vec())
}
}