Binary modification utilities built on goblin.
This crate provides programmatic access to binary modification workflows typically done via command-line tools:
- Mach-O binaries (macOS/iOS): Functionality similar to Apple's
install_name_tool - ELF binaries (Linux/BSD): Functionality similar to
patchelf
- Modify dylib install names and dependencies (Mach-O)
- Add, remove, and modify runtime search paths (rpath)
- Change SONAME entries (ELF)
- Convert between RPATH and RUNPATH (ELF)
- Ad-hoc code signing support (Mach-O, with
codesignfeature) - Support for both 32-bit and 64-bit binaries
- Support for FAT/universal binaries (Mach-O)
- Smart relocation strategies to handle growing sections
no_stdcompatible (withalloc)
Add this to your Cargo.toml:
[dependencies]
goblin-ext = "0.1"| Feature | Default | Description |
|---|---|---|
std |
Yes | Standard library support |
mach |
Yes | Mach-O binary support |
elf |
Yes | ELF binary support |
codesign |
No | Ad-hoc code signing for Mach-O binaries |
use goblin_ext::MachOWriter;
let data = std::fs::read("libfoo.dylib")?;
let mut writer = MachOWriter::new(data)?;
// Change the install name
writer.change_id("@rpath/libfoo.dylib")?;
// Modify a dependency path
writer.change_dylib("/usr/lib/libold.dylib", "/usr/local/lib/libnew.dylib")?;
// Add an rpath
writer.add_rpath("@loader_path/../lib")?;
// Build the modified binary
let output = writer.build()?;
std::fs::write("libfoo_modified.dylib", output)?;use goblin::elf::Elf;
use goblin_ext::ElfWriter;
let data = std::fs::read("binary")?;
let elf = Elf::parse(&data)?;
let mut writer = ElfWriter::new(&data, &elf)?;
// Set the RUNPATH
writer.set_rpath("/usr/local/lib")?;
// Or set multiple paths
writer.set_rpath("/usr/local/lib:/opt/lib")?;
// Write the modified binary
let output = writer.write()?;
std::fs::write("binary_modified", output)?;use goblin_ext::modify_fat_binary;
let data = std::fs::read("universal.dylib")?;
let output = modify_fat_binary(&data, |writer| {
writer.change_id("@rpath/universal.dylib")?;
writer.add_rpath("@loader_path/../lib")?;
Ok(())
})?;
std::fs::write("universal_modified.dylib", output)?;| Method | Description |
|---|---|
get_id() |
Get the binary's install name |
change_id(name) |
Change the dylib install name |
get_dylibs() |
List all dylib dependencies |
change_dylib(old, new) |
Modify a dependency path |
delete_dylib(name) |
Remove a dependency |
add_dylib(name, kind) |
Add a new dependency |
get_rpaths() |
List all runtime search paths |
add_rpath(path) |
Add an rpath |
delete_rpath(path) |
Remove an rpath |
change_rpath(old, new) |
Modify an rpath |
build() |
Serialize the modified binary |
| Method | Description |
|---|---|
set_rpath(path) |
Set DT_RUNPATH (or DT_RPATH) |
set_rpath_forced(path) |
Force DT_RPATH instead of DT_RUNPATH |
set_soname(name) |
Set DT_SONAME |
remove_rpath() |
Remove DT_RPATH |
remove_runpath() |
Remove DT_RUNPATH |
rpath_to_runpath() |
Convert DT_RPATH to DT_RUNPATH |
runpath_to_rpath() |
Convert DT_RUNPATH to DT_RPATH |
write() |
Write the modified binary |
The crate includes two example CLI tools:
A Rust implementation of Apple's install_name_tool:
cargo run --example install_name_tool --features codesign -- \
-id @rpath/libfoo.dylib \
-add_rpath @loader_path/../lib \
-change /usr/lib/libold.dylib /usr/local/lib/libnew.dylib \
libfoo.dylib -o libfoo_modified.dylibA Rust implementation of patchelf:
cargo run --example patchelf -- set-rpath /usr/local/lib binary -o binary_modified
cargo run --example patchelf -- print-rpath binary
cargo run --example patchelf -- rpath-to-runpath binary -o binary_modified- CI/CD pipelines: Automate binary patching as part of build processes
- Cross-compilation: Fix library paths for different deployment environments
- Package management: Relocate binaries to new install prefixes
- Development: Test binaries with different library versions
This crate requires Rust 1.90.0 or later.
Licensed under the MIT License. See LICENSE for details.
Contributions are welcome! Please feel free to submit a Pull Request.