Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ tqdm>=4.64.0
capstone>=5.0.0
lief>=0.12.0
r2pipe>=1.6.5
frida>=16.0.0
angr>=9.2.0

# Data analysis and machine learning
numpy>=1.22.0
Expand Down
498 changes: 474 additions & 24 deletions src/analysis/dynamic_analyzer.py

Large diffs are not rendered by default.

49 changes: 48 additions & 1 deletion src/core/binary_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,13 @@ def _check_command(self, command: str) -> bool:
except (subprocess.SubprocessError, FileNotFoundError):
return False

def load(self, binary_path: Union[str, Path]) -> BinaryInfo:
def load(self, binary_path: Union[str, Path], auto_unpack: bool = True) -> BinaryInfo:
"""
Load and analyze a binary file.

Args:
binary_path: Path to the binary file
auto_unpack: Whether to automatically unpack if binary is detected as packed

Returns:
BinaryInfo object containing information about the binary
Expand All @@ -154,6 +155,10 @@ def load(self, binary_path: Union[str, Path]) -> BinaryInfo:

logger.info(f"Loading binary: {binary_path}")

# Check if binary is packed and unpack if needed
if auto_unpack:
binary_path = self._check_and_unpack(binary_path)

# Use LIEF if available for better analysis
if LIEF_AVAILABLE:
return self._load_with_lief(binary_path)
Expand Down Expand Up @@ -226,6 +231,48 @@ def _load_with_lief(self, binary_path: Path) -> BinaryInfo:
logger.info("Falling back to basic analysis")
return self._load_with_fallback(binary_path)

def _check_and_unpack(self, binary_path: Path) -> Path:
"""
Check if binary is packed and unpack if necessary.

Args:
binary_path: Path to the binary file

Returns:
Path to the binary (original or unpacked)
"""
try:
from src.unpacking import SymbolicUnpacker

unpacker = SymbolicUnpacker()
if not unpacker.is_available():
logger.debug("Angr not available for unpacking")
return binary_path

# Check if binary is packed
packer = unpacker.detect_packer(binary_path)
if not packer:
logger.debug("Binary does not appear to be packed")
return binary_path

logger.info(f"Detected packed binary with packer: {packer}")

# Attempt to unpack
result = unpacker.unpack(binary_path)
if result.success and result.unpacked_path:
logger.info(f"Successfully unpacked binary to: {result.unpacked_path}")
return result.unpacked_path
else:
logger.warning(f"Failed to unpack binary: {result.error_message}")
return binary_path

except ImportError:
logger.debug("Unpacking module not available")
return binary_path
except Exception as e:
logger.error(f"Error during unpacking: {e}")
return binary_path

def _load_with_fallback(self, binary_path: Path) -> BinaryInfo:
"""
Load and analyze a binary file using basic analysis.
Expand Down
22 changes: 20 additions & 2 deletions src/core/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def _run(self) -> Dict[str, Any]:

# Load binary
start_time = time.time()
binary_info = self.binary_loader.load(self.binary_path)
binary_info = self.binary_loader.load(self.binary_path, auto_unpack=True)
stage_times["binary_loading"] = time.time() - start_time

# Store binary metadata
Expand Down Expand Up @@ -138,6 +138,24 @@ def _run(self) -> Dict[str, Any]:

# Store data structure information
self.results["data_structures"] = data_structures

# Obfuscation optimization (iterative, post-decompilation)
try:
from src.optimization import ObfuscationOptimizer
optimizer = ObfuscationOptimizer()
if optimizer.is_available():
start_time = time.time()
report = optimizer.optimize(self.binary_path)
stage_times["obfuscation_optimization"] = time.time() - start_time
self.results["obfuscation_optimization"] = {
"iterations": report.iterations,
"changes_applied": report.changes_applied,
"passes_run": report.passes_run,
"details": report.details,
}
except Exception:
# Non-fatal: continue pipeline if optimizer unavailable or fails
pass

# Generate function summaries with LLM if enabled
if self.function_summarizer:
Expand Down Expand Up @@ -225,7 +243,7 @@ def run(self) -> Dict[str, Any]:

# Load binary
start_time = time.time()
binary_info = self.binary_loader.load(self.binary_path)
binary_info = self.binary_loader.load(self.binary_path, auto_unpack=True)
stage_times["binary_loading"] = time.time() - start_time

# Store binary metadata
Expand Down
6 changes: 5 additions & 1 deletion src/decompilers/decompiler_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from src.decompilers.ida_decompiler import IDADecompiler
from src.decompilers.binary_ninja_decompiler import BinaryNinjaDecompiler
from src.decompilers.mock_decompiler import MockDecompiler
from src.decompilers.internal_ir_decompiler import InternalIRDecompiler

logger = logging.getLogger("re-architect.decompilers.factory")

Expand Down Expand Up @@ -66,6 +67,9 @@ def create(self, decompiler_name: str = "auto") -> BaseDecompiler:
elif decompiler_name == "mock":
logger.info("Creating Mock decompiler for testing")
return MockDecompiler()
elif decompiler_name == "internal" or decompiler_name == "ir":
logger.info("Creating Internal IR decompiler")
return InternalIRDecompiler()
elif decompiler_name == "auto":
# We'll pick one based on availability later when we have binary info
logger.info("Creating auto-selected decompiler (will choose when binary is available)")
Expand All @@ -82,7 +86,7 @@ def _create_auto_decompiler(self) -> BaseDecompiler:
Decompiler instance (defaults to Ghidra if available)
"""
# Try to create decompilers in order of preference
for decompiler_class in [GhidraDecompiler, IDADecompiler, BinaryNinjaDecompiler]:
for decompiler_class in [InternalIRDecompiler, GhidraDecompiler, IDADecompiler, BinaryNinjaDecompiler]:
try:
decompiler = decompiler_class()
if decompiler.is_available():
Expand Down
Loading
Loading