1use goblin::pe::characteristic::{IMAGE_FILE_DEBUG_STRIPPED, IMAGE_FILE_RELOCS_STRIPPED};
14use goblin::pe::PE;
15use serde_json::json;
16
17use crate::check::{Analyze, GenericMap};
18use crate::BinResult;
19
20use super::UniversalCompilationProperties;
21
22impl UniversalCompilationProperties for PE<'_> {
23 fn binary_type(&self) -> &str {
24 match self.is_lib {
25 true => "DLL",
26 false => "EXE",
27 }
28 }
29
30 fn is_stripped(&self) -> bool {
31 matches!(
32 self.header.coff_header.characteristics & IMAGE_FILE_DEBUG_STRIPPED,
33 0
34 )
35 }
36
37 fn compiler_runtime(&self, _bytes: &[u8]) -> Option<String> {
39 None
40 }
41}
42
43trait PeMitigations {
44 fn dll_characteristics(&self) -> u16;
45 fn data_execution_prevention(&self) -> bool;
46 fn dynamic_base(&self) -> bool;
47 fn structured_exception_handling(&self) -> bool;
48 fn isolation_aware_execution(&self) -> bool;
49 fn aslr(&self) -> bool;
50 fn high_entropy(&self) -> bool;
51 fn control_flow_guard(&self) -> bool;
52 fn code_integrity(&self) -> bool;
53}
54
55impl PeMitigations for PE<'_> {
56 fn dll_characteristics(&self) -> u16 {
57 if let Some(optional_header) = self.header.optional_header {
58 return optional_header.windows_fields.dll_characteristics;
59 }
60 0
61 }
62
63 fn data_execution_prevention(&self) -> bool {
64 matches!(self.dll_characteristics() & 0x0100, 0)
65 }
66
67 fn dynamic_base(&self) -> bool {
68 matches!(self.dll_characteristics() & 0x0040, 0)
69 }
70
71 fn structured_exception_handling(&self) -> bool {
72 matches!(self.dll_characteristics() & 0x0400, 0)
73 }
74
75 fn isolation_aware_execution(&self) -> bool {
76 matches!(self.dll_characteristics() & 0x0200, 0)
77 }
78
79 fn aslr(&self) -> bool {
80 self.dynamic_base()
81 && matches!(
82 self.header.coff_header.characteristics & IMAGE_FILE_RELOCS_STRIPPED,
83 0
84 )
85 }
86
87 fn high_entropy(&self) -> bool {
88 self.aslr() && matches!(self.dll_characteristics() & 0x0020, 0)
89 }
90
91 fn control_flow_guard(&self) -> bool {
92 self.aslr() && matches!(self.dll_characteristics() & 0x4000, 0)
93 }
94
95 fn code_integrity(&self) -> bool {
96 self.aslr() && matches!(self.dll_characteristics() & 0x0080, 0)
97 }
98}
99
100impl Analyze for PE<'_> {
101 fn compilation(&self, _bytes: &[u8]) -> BinResult<GenericMap> {
102 let mut comp_map = GenericMap::new();
103 comp_map.insert("Binary Type".to_string(), json!(self.binary_type()));
104 comp_map.insert("Debug Stripped".to_string(), json!(self.is_stripped()));
105 Ok(comp_map)
106 }
107
108 fn mitigations(&self) -> GenericMap {
109 let mut mitigation_checks: GenericMap = GenericMap::new();
110
111 mitigation_checks.insert(
113 "Data Execution Protection (DEP)".to_string(),
114 json!(self.data_execution_prevention()),
115 );
116 mitigation_checks.insert("Dynamic Base".to_string(), json!(self.dynamic_base()));
117 mitigation_checks.insert(
118 "Structured Exception Handling (SEH)".to_string(),
119 json!(!self.structured_exception_handling()),
120 );
121 mitigation_checks.insert(
122 "Isolation-Aware Execution".to_string(),
123 json!(!self.isolation_aware_execution()),
124 );
125
126 mitigation_checks.insert(
128 "Address Space Layout Randomization (ASLR)".to_string(),
129 json!(self.aslr()),
130 );
131 mitigation_checks.insert("High Entropy".to_string(), json!(self.high_entropy()));
132 mitigation_checks.insert(
133 "Control Flow Guard (CFG)".to_string(),
134 json!(self.control_flow_guard()),
135 );
136 mitigation_checks.insert("Code Integrity".to_string(), json!(self.code_integrity()));
137 mitigation_checks
138 }
139
140 fn instrumentation(&self) -> GenericMap {
142 GenericMap::new()
143 }
144}