use std::collections::HashMap;
#[cfg(feature = "serde-support")]
use serde::{Deserialize, Serialize};
pub type BinaryResult<T> = crate::Result<T>;
pub type ParsedBinary = Box<dyn BinaryFormatTrait>;
pub type ParseResult = BinaryResult<ParsedBinary>;
pub type ImportExportResult = BinaryResult<(Vec<Import>, Vec<Export>)>;
pub type ByteSliceResult<'a> = BinaryResult<&'a [u8]>;
pub type PatternMatchMap =
HashMap<crate::utils::patterns::PatternCategory, Vec<crate::utils::patterns::PatternMatch>>;
pub type HexPatternResult = BinaryResult<Vec<Option<u8>>>;
pub type HexPattern = Vec<Option<u8>>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub enum BinaryFormat {
Elf,
Pe,
MachO,
Java,
Wasm,
Raw,
#[default]
Unknown,
}
impl std::fmt::Display for BinaryFormat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
BinaryFormat::Elf => write!(f, "ELF"),
BinaryFormat::Pe => write!(f, "PE"),
BinaryFormat::MachO => write!(f, "Mach-O"),
BinaryFormat::Java => write!(f, "Java"),
BinaryFormat::Wasm => write!(f, "WebAssembly"),
BinaryFormat::Raw => write!(f, "Raw"),
BinaryFormat::Unknown => write!(f, "Unknown"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub enum Architecture {
X86,
X86_64,
Arm,
Arm64,
Mips,
Mips64,
PowerPC,
PowerPC64,
RiscV,
RiscV64,
Wasm,
Jvm,
#[default]
Unknown,
}
impl std::fmt::Display for Architecture {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Architecture::X86 => write!(f, "x86"),
Architecture::X86_64 => write!(f, "x86-64"),
Architecture::Arm => write!(f, "ARM"),
Architecture::Arm64 => write!(f, "ARM64"),
Architecture::Mips => write!(f, "MIPS"),
Architecture::Mips64 => write!(f, "MIPS64"),
Architecture::PowerPC => write!(f, "PowerPC"),
Architecture::PowerPC64 => write!(f, "PowerPC64"),
Architecture::RiscV => write!(f, "RISC-V"),
Architecture::RiscV64 => write!(f, "RISC-V64"),
Architecture::Wasm => write!(f, "WebAssembly"),
Architecture::Jvm => write!(f, "JVM"),
Architecture::Unknown => write!(f, "Unknown"),
}
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct BinaryMetadata {
pub size: usize,
pub format: BinaryFormat,
pub architecture: Architecture,
pub entry_point: Option<u64>,
pub base_address: Option<u64>,
pub timestamp: Option<u64>,
pub compiler_info: Option<String>,
pub endian: Endianness,
pub security_features: SecurityFeatures,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub enum Endianness {
Little,
Big,
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct SecurityFeatures {
pub nx_bit: bool,
pub aslr: bool,
pub stack_canary: bool,
pub cfi: bool,
pub fortify: bool,
pub pie: bool,
pub relro: bool,
pub signed: bool,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct Section {
pub name: String,
pub address: u64,
pub size: u64,
pub offset: u64,
pub permissions: SectionPermissions,
pub section_type: SectionType,
pub data: Option<Vec<u8>>,
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct SectionPermissions {
pub read: bool,
pub write: bool,
pub execute: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub enum SectionType {
Code,
Data,
ReadOnlyData,
Bss,
Debug,
Symbol,
String,
Relocation,
Dynamic,
Note,
Other(String),
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct Symbol {
pub name: String,
pub demangled_name: Option<String>,
pub address: u64,
pub size: u64,
pub symbol_type: SymbolType,
pub binding: SymbolBinding,
pub visibility: SymbolVisibility,
pub section_index: Option<usize>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub enum SymbolType {
Function,
Object,
Section,
File,
Common,
Thread,
Other(String),
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub enum SymbolBinding {
Local,
Global,
Weak,
Other(String),
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub enum SymbolVisibility {
Default,
Internal,
Hidden,
Protected,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct Import {
pub name: String,
pub library: Option<String>,
pub address: Option<u64>,
pub ordinal: Option<u16>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct Export {
pub name: String,
pub address: u64,
pub ordinal: Option<u16>,
pub forwarded_name: Option<String>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct Instruction {
pub address: u64,
pub bytes: Vec<u8>,
pub mnemonic: String,
pub operands: String,
pub category: InstructionCategory,
pub flow: ControlFlow,
pub size: usize,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub enum InstructionCategory {
Arithmetic,
Logic,
Memory,
Control,
System,
Crypto,
Vector,
Float,
Unknown,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub enum ControlFlow {
Sequential,
Jump(u64),
ConditionalJump(u64),
Call(u64),
Return,
Interrupt,
Unknown,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct BasicBlock {
pub id: usize,
pub start_address: u64,
pub end_address: u64,
pub instructions: Vec<Instruction>,
pub successors: Vec<usize>,
pub predecessors: Vec<usize>,
pub block_type: BlockType,
pub dominator: Option<usize>,
pub dominance_frontier: Vec<usize>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct ControlFlowGraph {
pub function: Function,
pub basic_blocks: Vec<BasicBlock>,
pub complexity: ComplexityMetrics,
pub loops: Vec<Loop>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct Function {
pub name: String,
pub start_address: u64,
pub end_address: u64,
pub size: u64,
pub function_type: FunctionType,
pub calling_convention: Option<String>,
pub parameters: Vec<Parameter>,
pub return_type: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub enum FunctionType {
Normal,
Constructor,
Destructor,
Operator,
Main,
Entrypoint,
Import,
Export,
Thunk,
Unknown,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct Parameter {
pub name: Option<String>,
pub param_type: String,
pub location: ParameterLocation,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub enum ParameterLocation {
Register(String),
Stack(i64),
Unknown,
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct ComplexityMetrics {
pub cyclomatic_complexity: u32,
pub basic_block_count: u32,
pub edge_count: u32,
pub nesting_depth: u32,
pub loop_count: u32,
pub cognitive_complexity: u32,
pub halstead_metrics: Option<HalsteadMetrics>,
pub maintainability_index: Option<f64>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct HalsteadMetrics {
pub n1: u32,
pub n2: u32,
pub capital_n1: u32,
pub capital_n2: u32,
pub vocabulary: u32,
pub length: u32,
pub calculated_length: f64,
pub volume: f64,
pub difficulty: f64,
pub effort: f64,
pub time: f64,
pub bugs: f64,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub enum LoopType {
Natural,
Irreducible,
DoWhile,
While,
For,
Infinite,
Unknown,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct Loop {
pub header_block: usize,
pub body_blocks: Vec<usize>,
pub exit_blocks: Vec<usize>,
pub loop_type: LoopType,
pub induction_variables: Vec<String>,
pub is_natural: bool,
pub nesting_level: u32,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub enum BlockType {
Entry,
Exit,
Normal,
LoopHeader,
LoopBody,
LoopExit,
Conditional,
Call,
Return,
Exception,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct EntropyAnalysis {
pub overall_entropy: f64,
pub section_entropy: HashMap<String, f64>,
pub high_entropy_regions: Vec<EntropyRegion>,
pub packing_indicators: PackingIndicators,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct EntropyRegion {
pub start: u64,
pub end: u64,
pub entropy: f64,
pub description: String,
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct PackingIndicators {
pub is_packed: bool,
pub packer_name: Option<String>,
pub compression_ratio: Option<f64>,
pub obfuscation_level: ObfuscationLevel,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub enum ObfuscationLevel {
#[default]
None,
Low,
Medium,
High,
Extreme,
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct SecurityIndicators {
pub suspicious_apis: Vec<String>,
pub anti_debug: Vec<String>,
pub anti_vm: Vec<String>,
pub crypto_indicators: Vec<String>,
pub network_indicators: Vec<String>,
pub filesystem_indicators: Vec<String>,
pub registry_indicators: Vec<String>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct CallGraph {
pub nodes: Vec<CallGraphNode>,
pub edges: Vec<CallGraphEdge>,
pub entry_points: Vec<u64>,
pub unreachable_functions: Vec<u64>,
pub statistics: CallGraphStatistics,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct CallGraphNode {
pub function_address: u64,
pub function_name: String,
pub node_type: NodeType,
pub complexity: u32,
pub in_degree: u32,
pub out_degree: u32,
pub is_recursive: bool,
pub call_depth: Option<u32>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub enum NodeType {
EntryPoint,
Library,
Internal,
External,
Indirect,
Virtual,
Unknown,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct CallGraphEdge {
pub caller: u64,
pub callee: u64,
pub call_type: CallType,
pub call_sites: Vec<CallSite>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub enum CallType {
Direct,
Indirect,
TailCall,
Virtual,
Recursive,
Conditional,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct CallSite {
pub address: u64,
pub instruction_bytes: Vec<u8>,
pub context: CallContext,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub enum CallContext {
Normal,
Exception,
Loop,
Conditional,
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct CallGraphStatistics {
pub total_functions: usize,
pub total_calls: usize,
pub direct_calls: usize,
pub indirect_calls: usize,
pub recursive_functions: usize,
pub leaf_functions: usize,
pub entry_points: usize,
pub unreachable_functions: usize,
pub max_call_depth: u32,
pub average_call_depth: f64,
pub cyclic_dependencies: usize,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct CallGraphConfig {
pub analyze_indirect_calls: bool,
pub detect_tail_calls: bool,
pub resolve_virtual_calls: bool,
pub follow_import_thunks: bool,
pub max_call_depth: Option<u32>,
pub include_library_calls: bool,
}
impl Default for CallGraphConfig {
fn default() -> Self {
Self {
analyze_indirect_calls: true,
detect_tail_calls: true,
resolve_virtual_calls: false,
follow_import_thunks: true,
max_call_depth: Some(50),
include_library_calls: false,
}
}
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct AnalysisResult {
pub format: BinaryFormat,
pub architecture: Architecture,
pub entry_point: Option<u64>,
pub metadata: BinaryMetadata,
pub sections: Vec<Section>,
pub symbols: Vec<Symbol>,
pub imports: Vec<Import>,
pub exports: Vec<Export>,
pub disassembly: Option<Vec<Instruction>>,
pub control_flow: Option<Vec<ControlFlowGraph>>,
pub entropy: Option<EntropyAnalysis>,
pub security: Option<SecurityIndicators>,
pub call_graph: Option<CallGraph>,
pub enhanced_control_flow: Option<EnhancedControlFlowAnalysis>,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct EnhancedControlFlowAnalysis {
pub control_flow_graphs: Vec<ControlFlowGraph>,
pub cognitive_complexity_summary: CognitiveComplexityStats,
pub loop_analysis_summary: LoopAnalysisStats,
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct CognitiveComplexityStats {
pub total_cognitive_complexity: u32,
pub average_cognitive_complexity: f64,
pub max_cognitive_complexity: u32,
pub most_complex_function: Option<String>,
pub functions_analyzed: usize,
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde-support", derive(Serialize, Deserialize))]
pub struct LoopAnalysisStats {
pub total_loops: usize,
pub natural_loops: usize,
pub irreducible_loops: usize,
pub nested_loops: usize,
pub max_nesting_depth: u32,
pub loops_by_type: HashMap<LoopType, usize>,
}
impl Default for BinaryMetadata {
fn default() -> Self {
Self {
size: 0,
format: BinaryFormat::Unknown,
architecture: Architecture::Unknown,
entry_point: None,
base_address: None,
timestamp: None,
compiler_info: None,
endian: Endianness::Little,
security_features: SecurityFeatures::default(),
}
}
}
pub trait BinaryFormatParser {
fn parse(data: &[u8]) -> ParseResult;
fn can_parse(data: &[u8]) -> bool;
}
pub trait BinaryFormatTrait: Send + Sync {
fn format_type(&self) -> BinaryFormat;
fn architecture(&self) -> Architecture;
fn entry_point(&self) -> Option<u64>;
fn sections(&self) -> &[Section];
fn symbols(&self) -> &[Symbol];
fn imports(&self) -> &[Import];
fn exports(&self) -> &[Export];
fn metadata(&self) -> &BinaryMetadata;
}