///|
pub fn PEImage::security_diagnostics(self : Self) -> Array[Diagnostic] {
let diagnostics = []
if !has_bit(self.dll_characteristics, 0x0040) {
diagnostics.push({
severity: Warning,
code: "pe.no-aslr",
message: "DYNAMIC_BASE is not set; the image does not opt into ASLR",
})
}
if !has_bit(self.dll_characteristics, 0x0100) {
diagnostics.push({
severity: Warning,
code: "pe.no-nx",
message: "NX_COMPAT is not set; executable memory may remain writable",
})
}
if !has_bit(self.dll_characteristics, 0x4000) {
diagnostics.push({
severity: Warning,
code: "pe.no-cfg",
message: "GUARD_CF is not set; Control Flow Guard metadata is absent",
})
}
if self.is_64_bit() && !has_bit(self.dll_characteristics, 0x0020) {
diagnostics.push({
severity: Info,
code: "pe.no-high-entropy-va",
message: "HIGH_ENTROPY_VA is not set for this 64-bit image",
})
}
for section in self.sections {
if has_bit(section.characteristics.to_int(), 0x80000000) &&
has_bit(section.characteristics.to_int(), 0x20000000) {
diagnostics.push({
severity: Critical,
code: "pe.rwx-section",
message: "section '\{section.name}' is both writable and executable",
})
}
}
if self.entry_point != 0UL {
let mut executable_entry = false
for section in self.sections {
let start = section.virtual_address
let span = if section.virtual_size > section.raw_size {
section.virtual_size
} else {
section.raw_size
}
if self.entry_point >= start &&
self.entry_point < start + span.to_uint64() &&
has_bit(section.characteristics.to_int(), 0x20000000) {
executable_entry = true
}
}
if !executable_entry {
diagnostics.push({
severity: Warning,
code: "pe.entrypoint-not-executable",
message: "AddressOfEntryPoint is not inside an executable section",
})
}
}
let signed = match self.directory(4) {
Some(directory) => directory.virtual_address != 0UL && directory.size != 0
None => false
}
if signed {
diagnostics.push({
severity: Info,
code: "pe.certificate-table",
message: "certificate table is present; this tool does not validate signatures",
})
} else {
diagnostics.push({
severity: Warning,
code: "pe.unsigned",
message: "no Authenticode certificate table is present",
})
}
diagnostics
}
///|
fn has_bit(value : Int32, mask : Int32) -> Bool {
(value & mask) != 0
}