Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
42 changes: 25 additions & 17 deletions src/extraction/macho_load_commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,31 @@
//!
//! # Examples
//!
//! ```rust
//! ```rust,no_run
//! use std::error::Error;
//! use stringy::extraction::macho_load_commands::extract_load_command_strings;
//! use stringy::types::{Tag, StringSource};
//!
//! let macho_data = std::fs::read("example.dylib")?;
//! let strings = extract_load_command_strings(&macho_data);
//! fn main() -> Result<(), Box<dyn Error>> {
//! let macho_data = std::fs::read("example.dylib")?;
//! let strings = extract_load_command_strings(&macho_data);
//!
//! // Filter dylib paths
//! let dylib_paths: Vec<_> = strings.iter()
//! .filter(|s| s.tags.contains(&Tag::DylibPath))
//! .collect();
//! // Filter dylib paths
//! let dylib_paths: Vec<_> = strings.iter()
//! .filter(|s| s.tags.contains(&Tag::DylibPath))
//! .collect();
//!
//! // Filter rpaths
//! let rpaths: Vec<_> = strings.iter()
//! .filter(|s| s.tags.contains(&Tag::Rpath))
//! .collect();
//! // Filter rpaths
//! let rpaths: Vec<_> = strings.iter()
//! .filter(|s| s.tags.contains(&Tag::Rpath))
//! .collect();
//!
//! // Filter framework paths
//! let framework_paths: Vec<_> = strings.iter()
//! .filter(|s| s.tags.contains(&Tag::FrameworkPath))
//! .collect();
//! // Filter framework paths
//! let framework_paths: Vec<_> = strings.iter()
//! .filter(|s| s.tags.contains(&Tag::FrameworkPath))
//! .collect();
//! Ok(())
//! }
//! ```

use crate::types::{Encoding, FoundString, StringSource, Tag};
Expand Down Expand Up @@ -188,8 +192,12 @@ fn extract_architecture_data<'a>(
let offset = arch.offset as usize;
let size = arch.size as usize;

if offset + size <= data.len() {
Ok(&data[offset..offset + size])
if let Some(end) = offset.checked_add(size) {
if end <= data.len() {
Ok(&data[offset..end])
} else {
Err(())
}
} else {
Err(())
}
Expand Down
5 changes: 4 additions & 1 deletion tests/fixtures/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ This directory contains pre-compiled binary test fixtures used for snapshot test
## Fixtures

- `test_binary_elf` - x86-64 ELF binary
- `test_binary_macho` - ARM64 Mach-O binary (contains typical load commands including LC_LOAD_DYLIB for system library dependencies like libSystem.B.dylib, potentially LC_RPATH commands, and framework dependencies if any frameworks are linked)
- `test_binary_macho` - ARM64 Mach-O binary with standard load commands:
- LC_LOAD_DYLIB for system library dependencies (e.g., libSystem.B.dylib)
- May include LC_RPATH commands
- May include framework dependencies
- `test_binary_pe.exe` - x86-64 PE binary
- `test_binary_with_resources.exe` - x86-64 PE binary with VERSIONINFO and STRINGTABLE resources

Expand Down
28 changes: 14 additions & 14 deletions tests/integration_macho.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,11 +267,12 @@ fn test_macho_load_command_extraction_snapshot() {
for (i, string) in dylib_paths.iter().take(20).enumerate() {
let is_framework = string.text.contains(".framework");
output.push_str(&format!(
"Dylib Path {}: {} {}\n",
"Dylib Path {}: {}{}",
i + 1,
string.text,
if is_framework { "(Framework)" } else { "" }
if is_framework { " (Framework)" } else { "" }
));
output.push('\n');
}
if dylib_paths.len() > 20 {
output.push_str(&format!("... and {} more\n", dylib_paths.len() - 20));
Expand All @@ -285,15 +286,16 @@ fn test_macho_load_command_extraction_snapshot() {
for (i, string) in rpaths.iter().take(20).enumerate() {
let has_variable = has_rpath_variable(&string.text);
output.push_str(&format!(
"Rpath {}: {} {}\n",
"Rpath {}: {}{}",
i + 1,
string.text,
if has_variable {
"(Contains @-variable)"
" (Contains @-variable)"
} else {
""
}
));
output.push('\n');
}
if rpaths.len() > 20 {
output.push_str(&format!("... and {} more\n", rpaths.len() - 20));
Expand Down Expand Up @@ -489,16 +491,14 @@ fn test_macho_rpath_variable_detection() {

for rpath_var in &rpaths_with_vars {
let mut variables_found = Vec::new();
if has_rpath_variable(&rpath_var.text) {
if rpath_var.text.contains("@rpath") {
variables_found.push("@rpath");
}
if rpath_var.text.contains("@executable_path") {
variables_found.push("@executable_path");
}
if rpath_var.text.contains("@loader_path") {
variables_found.push("@loader_path");
}
if rpath_var.text.contains("@rpath") {
variables_found.push("@rpath");
}
if rpath_var.text.contains("@executable_path") {
variables_found.push("@executable_path");
}
if rpath_var.text.contains("@loader_path") {
variables_found.push("@loader_path");
}
println!(
"Rpath variable found: {} (variables: {:?})",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
---
source: tests/integration_macho.rs
assertion_line: 314
expression: output
---
=== DYLIB PATHS ===
Total: 2

Dylib Path 1: /usr/lib/libSystem.B.dylib
Dylib Path 2: self
Dylib Path 1: /usr/lib/libSystem.B.dylib
Dylib Path 2: self

=== RPATHS ===
Total: 0
Expand Down