Skip to main content

binsec/check/
pe.rs

1//! ### PE-Specific Compilation Checks:
2//!
3//! * TODO
4//!
5//! ### PE-Specific Exploit Mitigations:
6//!
7//! * Data Execution Prevention (DEP / NX)
8//! * Dynamic Base
9//! * Structured Exception Handling (SEH)
10//! * Code Integrity
11//! * Control Flow Guard
12
13use 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    // TODO: PE compiler-runtime detection is not implemented yet.
38    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        // context independent mitigations
112        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        // context dependent mitigations: some don't work without existence of other checks
127        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    // TODO
141    fn instrumentation(&self) -> GenericMap {
142        GenericMap::new()
143    }
144}