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
|
// Reference:
// https://learn.microsoft.com/en-us/windows-hardware/drivers/install/authenticode
// https://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/Authenticode_PE.docx
// Authenticode works by omiting sections of the PE binary from the digest
// those sections are:
// - checksum
// - data directory entry for certtable
// - certtable
use core::ops::Range;
use super::PE;
impl PE<'_> {
/// [`authenticode_ranges`] returns the various ranges of the binary that are relevant for
/// signature.
pub fn authenticode_ranges(&self) -> ExcludedSectionsIter<'_> {
ExcludedSectionsIter {
pe: self,
state: IterState::default(),
}
}
}
/// [`ExcludedSections`] holds the various ranges of the binary that are expected to be
/// excluded from the authenticode computation.
#[derive(Debug, Clone, Default)]
pub(super) struct ExcludedSections {
checksum: Range<usize>,
datadir_entry_certtable: Range<usize>,
certtable: Option<Range<usize>>,
}
impl ExcludedSections {
pub(super) fn new(
checksum: Range<usize>,
datadir_entry_certtable: Range<usize>,
certtable: Option<Range<usize>>,
) -> Self {
Self {
checksum,
datadir_entry_certtable,
certtable,
}
}
}
pub struct ExcludedSectionsIter<'s> {
pe: &'s PE<'s>,
state: IterState,
}
#[derive(Debug, PartialEq)]
enum IterState {
Initial,
DatadirEntry(usize),
CertTable(usize),
Final(usize),
Done,
}
impl Default for IterState {
fn default() -> Self {
Self::Initial
}
}
impl<'s> Iterator for ExcludedSectionsIter<'s> {
type Item = &'s [u8];
fn next(&mut self) -> Option<Self::Item> {
let bytes = &self.pe.bytes;
if let Some(sections) = self.pe.authenticode_excluded_sections.as_ref() {
loop {
match self.state {
IterState::Initial => {
self.state = IterState::DatadirEntry(sections.checksum.end);
return Some(&bytes[..sections.checksum.start]);
}
IterState::DatadirEntry(start) => {
self.state = IterState::CertTable(sections.datadir_entry_certtable.end);
return Some(&bytes[start..sections.datadir_entry_certtable.start]);
}
IterState::CertTable(start) => {
if let Some(certtable) = sections.certtable.as_ref() {
self.state = IterState::Final(certtable.end);
return Some(&bytes[start..certtable.start]);
} else {
self.state = IterState::Final(start)
}
}
IterState::Final(start) => {
self.state = IterState::Done;
return Some(&bytes[start..]);
}
IterState::Done => return None,
}
}
} else {
loop {
match self.state {
IterState::Initial => {
self.state = IterState::Done;
return Some(bytes);
}
IterState::Done => return None,
_ => {
self.state = IterState::Done;
}
}
}
}
}
}
|