pub mod status;
use crate::elf::needed_libc::NeededLibC;
use crate::errors::Result;
use crate::parser::BinaryParser;
use crate::{archive, cmdline, elf, pe};
use self::status::{
DisplayInColorTerm, ELFFortifySourceStatus, PEControlFlowGuardLevel, YesNoUnknownStatus,
};
pub trait BinarySecurityOption<'t> {
fn check(&self, parser: &BinaryParser) -> Result<Box<dyn DisplayInColorTerm>>;
}
struct PEDllCharacteristicsBitOption {
name: &'static str,
mask_name: &'static str,
mask: u16,
present: bool,
}
impl<'t> BinarySecurityOption<'t> for PEDllCharacteristicsBitOption {
fn check(&self, parser: &BinaryParser) -> Result<Box<dyn DisplayInColorTerm>> {
if let goblin::Object::PE(ref pe) = parser.object() {
if let Some(bit_is_set) =
pe::dll_characteristics_bit_is_set(pe, self.mask_name, self.mask)
{
return Ok(Box::new(YesNoUnknownStatus::new(
self.name,
bit_is_set == self.present,
)));
}
}
Ok(Box::new(YesNoUnknownStatus::unknown(self.name)))
}
}
#[derive(Default)]
pub struct PEHasCheckSumOption;
impl<'t> BinarySecurityOption<'t> for PEHasCheckSumOption {
fn check(&self, parser: &BinaryParser) -> Result<Box<dyn DisplayInColorTerm>> {
let r = if let goblin::Object::PE(ref pe) = parser.object() {
pe::has_check_sum(pe)
} else {
None
};
Ok(Box::new(r.map_or_else(
|| YesNoUnknownStatus::unknown("CHECKSUM"),
|r| YesNoUnknownStatus::new("CHECKSUM", r),
)))
}
}
#[derive(Default)]
pub struct DataExecutionPreventionOption;
impl<'t> BinarySecurityOption<'t> for DataExecutionPreventionOption {
fn check(&self, parser: &BinaryParser) -> Result<Box<dyn DisplayInColorTerm>> {
if let goblin::Object::PE(_pe) = parser.object() {
PEDllCharacteristicsBitOption {
name: "DATA-EXEC-PREVENT",
mask_name: "IMAGE_DLLCHARACTERISTICS_NX_COMPAT",
mask: pe::IMAGE_DLLCHARACTERISTICS_NX_COMPAT,
present: true,
}
.check(parser)
} else {
Ok(Box::new(YesNoUnknownStatus::unknown("DATA-EXEC-PREVENT")))
}
}
}
#[derive(Default)]
pub struct PERunsOnlyInAppContainerOption;
impl<'t> BinarySecurityOption<'t> for PERunsOnlyInAppContainerOption {
fn check(&self, parser: &BinaryParser) -> Result<Box<dyn DisplayInColorTerm>> {
PEDllCharacteristicsBitOption {
name: "RUNS-IN-APP-CONTAINER",
mask_name: "IMAGE_DLLCHARACTERISTICS_APPCONTAINER",
mask: pe::IMAGE_DLLCHARACTERISTICS_APPCONTAINER,
present: true,
}
.check(parser)
}
}
#[derive(Default)]
pub struct RequiresIntegrityCheckOption;
impl<'t> BinarySecurityOption<'t> for RequiresIntegrityCheckOption {
fn check(&self, parser: &BinaryParser) -> Result<Box<dyn DisplayInColorTerm>> {
if let goblin::Object::PE(_pe) = parser.object() {
PEDllCharacteristicsBitOption {
name: "VERIFY-DIGITAL-CERT",
mask_name: "IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY",
mask: pe::IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY,
present: true,
}
.check(parser)
} else {
Ok(Box::new(YesNoUnknownStatus::unknown("VERIFY-DIGITAL-CERT")))
}
}
}
#[derive(Default)]
pub struct PEEnableManifestHandlingOption;
impl<'t> BinarySecurityOption<'t> for PEEnableManifestHandlingOption {
fn check(&self, parser: &BinaryParser) -> Result<Box<dyn DisplayInColorTerm>> {
PEDllCharacteristicsBitOption {
name: "CONSIDER-MANIFEST",
mask_name: "IMAGE_DLLCHARACTERISTICS_NO_ISOLATION",
mask: pe::IMAGE_DLLCHARACTERISTICS_NO_ISOLATION,
present: false,
}
.check(parser)
}
}
#[derive(Default)]
pub struct PEControlFlowGuardOption;
impl<'t> BinarySecurityOption<'t> for PEControlFlowGuardOption {
fn check(&self, parser: &BinaryParser) -> Result<Box<dyn DisplayInColorTerm>> {
let r = if let goblin::Object::PE(ref pe) = parser.object() {
pe::supports_control_flow_guard(pe)
} else {
PEControlFlowGuardLevel::Unknown
};
Ok(Box::new(r))
}
}
#[derive(Default)]
pub struct PEHandlesAddressesLargerThan2GBOption;
impl<'t> BinarySecurityOption<'t> for PEHandlesAddressesLargerThan2GBOption {
fn check(&self, parser: &BinaryParser) -> Result<Box<dyn DisplayInColorTerm>> {
let r = if let goblin::Object::PE(ref pe) = parser.object() {
YesNoUnknownStatus::new(
"HANDLES-ADDR-GT-2GB",
pe::handles_addresses_larger_than_2_gigabytes(pe),
)
} else {
YesNoUnknownStatus::unknown("HANDLES-ADDR-GT-2GB")
};
Ok(Box::new(r))
}
}
#[derive(Default)]
pub struct AddressSpaceLayoutRandomizationOption;
impl<'t> BinarySecurityOption<'t> for AddressSpaceLayoutRandomizationOption {
fn check(&self, parser: &BinaryParser) -> Result<Box<dyn DisplayInColorTerm>> {
match parser.object() {
goblin::Object::PE(ref pe) => Ok(Box::new(pe::supports_aslr(pe))),
goblin::Object::Elf(ref elf_obj) => Ok(Box::new(elf::supports_aslr(elf_obj))),
_ => Ok(Box::new(YesNoUnknownStatus::unknown("ASLR"))),
}
}
}
#[derive(Default)]
pub struct PESafeStructuredExceptionHandlingOption;
impl<'t> BinarySecurityOption<'t> for PESafeStructuredExceptionHandlingOption {
fn check(&self, parser: &BinaryParser) -> Result<Box<dyn DisplayInColorTerm>> {
let r = if let goblin::Object::PE(ref pe) = parser.object() {
YesNoUnknownStatus::new(
"SAFE-SEH",
pe::has_safe_structured_exception_handlers(parser, pe),
)
} else {
YesNoUnknownStatus::unknown("SAFE-SEH")
};
Ok(Box::new(r))
}
}
#[derive(Default)]
pub struct ELFReadOnlyAfterRelocationsOption;
impl<'t> BinarySecurityOption<'t> for ELFReadOnlyAfterRelocationsOption {
fn check(&self, parser: &BinaryParser) -> Result<Box<dyn DisplayInColorTerm>> {
let r = if let goblin::Object::Elf(ref elf) = parser.object() {
YesNoUnknownStatus::new(
"READ-ONLY-RELOC",
elf::becomes_read_only_after_relocations(elf),
)
} else {
YesNoUnknownStatus::unknown("READ-ONLY-RELOC")
};
Ok(Box::new(r))
}
}
#[derive(Default)]
pub struct ELFStackProtectionOption;
impl<'t> BinarySecurityOption<'t> for ELFStackProtectionOption {
fn check(&self, parser: &BinaryParser) -> Result<Box<dyn DisplayInColorTerm>> {
let r = match parser.object() {
goblin::Object::Elf(ref elf_obj) => {
YesNoUnknownStatus::new("STACK-PROT", elf::has_stack_protection(elf_obj))
}
goblin::Object::Archive(ref archive) => {
let r = archive::has_stack_protection(parser, archive)?;
YesNoUnknownStatus::new("STACK-PROT", r)
}
_ => YesNoUnknownStatus::unknown("STACK-PROT"),
};
Ok(Box::new(r))
}
}
#[derive(Default)]
pub struct ELFImmediateBindingOption;
impl<'t> BinarySecurityOption<'t> for ELFImmediateBindingOption {
fn check(&self, parser: &BinaryParser) -> Result<Box<dyn DisplayInColorTerm>> {
let r = if let goblin::Object::Elf(ref elf) = parser.object() {
YesNoUnknownStatus::new("IMMEDIATE-BIND", elf::requires_immediate_binding(elf))
} else {
YesNoUnknownStatus::unknown("IMMEDIATE-BIND")
};
Ok(Box::new(r))
}
}
pub struct ELFFortifySourceOption {
libc_spec: Option<cmdline::LibCSpec>,
}
impl ELFFortifySourceOption {
pub fn new(libc_spec: Option<cmdline::LibCSpec>) -> Self {
Self { libc_spec }
}
}
impl<'t> BinarySecurityOption<'t> for ELFFortifySourceOption {
fn check(&self, parser: &BinaryParser) -> Result<Box<dyn DisplayInColorTerm>> {
if let goblin::Object::Elf(ref elf) = parser.object() {
let libc = if let Some(spec) = self.libc_spec {
NeededLibC::from_spec(spec)
} else {
NeededLibC::find_needed_by_executable(elf)?
};
let result = ELFFortifySourceStatus::new(libc, elf)?;
Ok(Box::new(result))
} else {
Ok(Box::new(YesNoUnknownStatus::unknown("FORTIFY-SOURCE")))
}
}
}