mod analysis;
mod api;
mod codegen;
mod detection;
mod pipeline;
#[cfg(test)]
mod tests;
use std::time::Instant;
use crate::{
compiler::{
AlgebraicSimplificationPass, BlockMergingPass, ConstantPropagationPass,
ControlFlowSimplificationPass, CopyPropagationPass, DeadCodeEliminationPass,
GlobalValueNumberingPass, InliningPass, JumpThreadingPass, LicmPass, OpaquePredicatePass,
PassPhase, PassScheduler, ProxyDevirtualizationPass, ReassociationPass,
StrengthReductionPass, ValueRangePropagationPass,
},
deobfuscation::{
config::EngineConfig,
context::AnalysisContext,
passes::DecryptionPass,
techniques::{
Detections, ObfuscatorMatcher, Technique, TechniqueRegistry, TechniqueResults,
},
},
};
struct PipelineRun<'a> {
engine: &'a DeobfuscationEngine,
detections: Detections,
results: TechniqueResults,
start: Instant,
iterations: usize,
}
pub struct DeobfuscationEngine {
config: EngineConfig,
registry: TechniqueRegistry,
matcher: ObfuscatorMatcher,
}
impl Default for DeobfuscationEngine {
fn default() -> Self {
Self::new(EngineConfig::default())
}
}
impl DeobfuscationEngine {
#[must_use]
pub fn new(config: EngineConfig) -> Self {
let registry = TechniqueRegistry::with_config(config.detection_nop_threshold);
Self {
config,
registry,
matcher: ObfuscatorMatcher::default(),
}
}
pub fn register_technique(&mut self, technique: Box<dyn Technique>) {
self.registry.register(technique);
}
pub fn technique_registry(&self) -> &TechniqueRegistry {
&self.registry
}
fn create_scheduler(&self) -> PassScheduler {
let mut scheduler = PassScheduler::new(
self.config.iterations.max_ssa_iterations,
self.config.iterations.stable_iterations,
self.config.iterations.max_phase_iterations,
);
if self.config.passes.opaque_predicate_removal {
scheduler.add(Box::new(OpaquePredicatePass::new()), PassPhase::Simplify);
scheduler.add(
Box::new(ValueRangePropagationPass::new(
self.config.passes.value_range_max_iterations,
)),
PassPhase::Simplify,
);
}
if self.config.passes.control_flow_simplification {
scheduler.add(
Box::new(ControlFlowSimplificationPass::new(
self.config.passes.control_flow_max_iterations,
)),
PassPhase::Simplify,
);
scheduler.add(Box::new(JumpThreadingPass::new()), PassPhase::Simplify);
}
if self.config.passes.inlining {
scheduler.add(
Box::new(InliningPass::new(self.config.passes.inline_threshold)),
PassPhase::Inline,
);
}
scheduler.add(
Box::new(ProxyDevirtualizationPass::new()),
PassPhase::Normalize,
);
if self.config.passes.dead_code_elimination {
scheduler.add(
Box::new(DeadCodeEliminationPass::new(
self.config.passes.dce_max_iterations,
)),
PassPhase::Normalize,
);
scheduler.add(
Box::new(BlockMergingPass::new(
self.config.passes.block_merge_max_iterations,
)),
PassPhase::Normalize,
);
scheduler.add(Box::new(LicmPass::new()), PassPhase::Normalize);
}
if self.config.passes.constant_propagation {
scheduler.add(Box::new(ReassociationPass::new()), PassPhase::Normalize);
scheduler.add(
Box::new(ConstantPropagationPass::new(
self.config.passes.const_prop_max_iterations,
)),
PassPhase::Normalize,
);
scheduler.add(
Box::new(GlobalValueNumberingPass::new()),
PassPhase::Normalize,
);
}
if self.config.passes.copy_propagation {
scheduler.add(
Box::new(CopyPropagationPass::new(
self.config.passes.copy_prop_max_iterations,
)),
PassPhase::Normalize,
);
}
if self.config.passes.strength_reduction {
scheduler.add(Box::new(StrengthReductionPass::new()), PassPhase::Normalize);
scheduler.add(
Box::new(AlgebraicSimplificationPass::new()),
PassPhase::Normalize,
);
}
scheduler
}
pub(crate) fn has_pending_byte_transforms(&self, detections: &Detections) -> bool {
self.registry.techniques().iter().any(|tech| {
detections.is_detected(tech.id())
&& !detections.is_transformed(tech.id())
&& tech.requires_regeneration()
})
}
fn create_deob_passes(&self, ctx: &AnalysisContext, scheduler: &mut PassScheduler) {
if self.config.passes.string_decryption {
scheduler.add(Box::new(DecryptionPass::new(ctx)), PassPhase::Value);
}
}
}