use goblin::elf::dynamic::{tag_to_str, Dyn};
use goblin::elf::{header, program_header, Elf};
use serde_json::json;
use crate::check::{Analyze, GenericMap};
use crate::errors::BinResult;
use crate::rules;
const GLIBC: &str = "GLIBC_2.";
impl Analyze for Elf<'_> {
fn run_compilation_checks(&self, bytes: &[u8]) -> BinResult<GenericMap> {
let mut comp_map: GenericMap = GenericMap::new();
comp_map.insert(
"Binary Type".to_string(),
json!(header::et_to_str(self.header.e_type)),
);
let runtime = self.detect_compiler_runtime(rules::ELF_COMPILER_RULES, bytes)?;
comp_map.insert("Compiler Runtime".to_string(), json!(runtime));
let static_exec: bool = !self
.program_headers
.iter()
.any(|ph| program_header::pt_to_str(ph.p_type) == "PT_INTERP");
comp_map.insert("Statically Compiled".to_string(), json!(static_exec));
if let Some(linker) = self.interpreter {
comp_map.insert("Linker Path".to_string(), json!(linker));
}
let mut glibcs: Vec<f64> = vec![];
for sym in self.dynstrtab.to_vec().unwrap() {
if sym.starts_with(GLIBC) {
let ver_str: &str = sym.strip_prefix(GLIBC).unwrap();
let version: f64 = ver_str.parse::<f64>().unwrap();
glibcs.push(version);
}
}
let min_ver = glibcs.iter().fold(f64::INFINITY, |a, &b| a.min(b));
comp_map.insert(
"Minimum Libc Version".to_string(),
json!(format!("2.{:?}", min_ver)),
);
comp_map.insert(
"Stripped Executable".to_string(),
json!(self.syms.is_empty()),
);
Ok(comp_map)
}
fn run_mitigation_checks(&self) -> GenericMap {
let mut mitigate_map: GenericMap = GenericMap::new();
let mut nx_bit: bool = false;
let mut relro: String = "NONE".to_string();
let mut stack_canary: bool = false;
let mut fortify_source: bool = false;
for ph in self.program_headers.iter() {
if program_header::pt_to_str(ph.p_type) == "PT_GNU_STACK" && ph.p_flags == 6 {
nx_bit = true;
}
if program_header::pt_to_str(ph.p_type) == "PT_GNU_RELRO" {
if let Some(segs) = &self.dynamic {
let dyn_seg: Option<Dyn> = segs
.dyns
.iter()
.find(|tag| tag_to_str(tag.d_tag) == "DT_BIND_NOW")
.cloned();
if dyn_seg.is_some() {
relro = "FULL".to_string();
} else {
relro = "PARTIAL".to_string();
}
}
}
}
mitigate_map.insert("Executable Stack (NX Bit)".to_string(), json!(nx_bit));
mitigate_map.insert("Read-Only Relocatable (RELRO)".to_string(), json!(relro));
mitigate_map.insert(
"Position Independent Executable / ASLR".to_string(),
json!(matches!(self.header.e_type, 3)),
);
for _sym in self.syms.iter() {
let _symbol = self.strtab.get(_sym.st_name);
if let Some(Ok(symbol)) = _symbol {
if symbol == "__stack_chk_fail" {
stack_canary = true;
} else if symbol.ends_with("_chk") {
fortify_source = true;
}
}
}
mitigate_map.insert("Stack Canary".to_string(), json!(stack_canary));
mitigate_map.insert("FORTIFY_SOURCE".to_string(), json!(fortify_source));
mitigate_map
}
}