Skip to content

Commit

Permalink
Expose write() operation in Rust
Browse files Browse the repository at this point in the history
  • Loading branch information
romainthomas committed Dec 9, 2024
1 parent f7171b6 commit a11b1b7
Show file tree
Hide file tree
Showing 18 changed files with 321 additions and 4 deletions.
4 changes: 4 additions & 0 deletions api/python/lief/MachO/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -401,8 +401,12 @@ class Binary(lief.Binary):

def is_valid_addr(self, address: int) -> bool: ...

@overload
def write(self, output: str) -> None: ...

@overload
def write(self, output: str, config: Builder.config_t) -> None: ...

@overload
def add(self, dylib_command: DylibCommand) -> LoadCommand: ...

Expand Down
11 changes: 10 additions & 1 deletion api/python/src/MachO/objects/pyBinary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -499,10 +499,19 @@ void create<Binary>(nb::module_& m) {

.def("write",
nb::overload_cast<const std::string&>(&Binary::write),
"Rebuild the binary and write and write its content if the file given in parameter"_doc,
"Rebuild the binary and write its content in the file given in the first parameter"_doc,
"output"_a,
nb::rv_policy::reference_internal)

.def("write",
nb::overload_cast<const std::string&, Builder::config_t>(&Binary::write),
R"doc(
Rebuild the binary and write its content in the file given in the first parameter.
The ``config`` parameter can be used to tweak the building process.
)doc"_doc,
"output"_a, "config"_a,
nb::rv_policy::reference_internal)

.def("add",
nb::overload_cast<const DylibCommand&>(&Binary::add),
"Add a new " RST_CLASS_REF(lief.MachO.DylibCommand) ""_doc,
Expand Down
10 changes: 9 additions & 1 deletion api/rust/autocxx_ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ include_cpp! {
// ELF
// -------------------------------------------------------------------------
generate!("ELF_Binary")
block_constructors!("ELF_Binary")

generate_pod!("ELF_Binary_write_config_t")
block_constructors!("ELF_Binary_write_config_t")

block_constructors!("Span")
generate!("ELF_Binary_it_segments")
block_constructors!("ELF_Binary_it_segments")
generate!("ELF_Binary_it_sections")
Expand Down Expand Up @@ -313,6 +317,10 @@ include_cpp! {
// -------------------------------------------------------------------------
generate!("MachO_Binary")
block_constructors!("MachO_Binary")

generate_pod!("MachO_Binary_write_config_t")
block_constructors!("MachO_Binary_write_config_t")

generate!("MachO_Binary_it_stubs")
block_constructors!("MachO_Binary_it_stubs")
generate!("MachO_Binary_it_symbols")
Expand Down
3 changes: 2 additions & 1 deletion api/rust/cargo/lief/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ bitflags = "2.4"
num-traits = "0.2"
num-derive = "0.4"
num-bigint = "0.4"
tempfile = "3.14.0"
lief-ffi = { version = "0.16.0", path = "../lief-ffi" }

[features]
default = ["rustls-tls"]
rustls-tls = ["lief-ffi/rustls-tls"]
rustls-tls = ["lief-ffi/rustls-tls"]
1 change: 1 addition & 0 deletions api/rust/cargo/lief/src/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//! ```
pub mod binary;
pub mod builder;
pub mod dynamic;
pub mod hash;
pub mod header;
Expand Down
13 changes: 13 additions & 0 deletions api/rust/cargo/lief/src/elf/binary.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use std::mem::size_of;
use std::pin::Pin;
use std::path::Path;

use num_traits::{Num, cast};

use lief_ffi as ffi;

use crate::Error;
use super::builder::Config;
use super::hash::{Sysv, Gnu};
use super::dynamic::{self, DynamicEntries};
use super::header::Header;
Expand Down Expand Up @@ -287,6 +289,17 @@ impl Binary {

Err(Error::NotSupported)
}

/// Write back the current ELF binary into the file specified in parameter
pub fn write(&mut self, output: &Path) {
self.ptr.as_mut().unwrap().write(output.to_str().unwrap());
}

/// Write back the current ELF binary into the file specified in parameter with the
/// configuration provided in the second parameter.
pub fn write_with_config(&mut self, output: &Path, config: Config) {
self.ptr.as_mut().unwrap().write_with_config(output.to_str().unwrap(), config.to_ffi());
}
}

impl generic::Binary for Binary {
Expand Down
122 changes: 122 additions & 0 deletions api/rust/cargo/lief/src/elf/builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
use lief_ffi as ffi;

/// Structure used to configure the [`crate::elf::Binary::write_with_config`] operation
#[derive(Debug)]
pub struct Config {
/// Rebuild `DT_HASH`
pub dt_hash: bool,

/// Rebuild `DT_STRTAB`
pub dyn_str: bool,

/// Rebuild `PT_DYNAMIC` segment
pub dynamic_section: bool,

/// Rebuild `DT_FINI_ARRAY`
pub fini_array: bool,

/// Rebuild `DT_GNU_HASH`
pub gnu_hash: bool,

/// Rebuild `DT_INIT_ARRAY`
pub init_array: bool,

/// Rebuild `PT_INTERPRETER`
pub interpreter: bool,

/// Rebuild `DT_JMPREL`
pub jmprel: bool,

/// Rebuild notes sections
pub notes: bool,

/// Rebuild `DT_PREINIT_ARRAY`
pub preinit_array: bool,

/// Rebuild `DT_RELR`
pub relr: bool,

/// Rebuild `DT_ANDROID_REL[A]`
pub android_rela: bool,

/// Rebuild `DT_REL[A]`
pub rela: bool,

/// Rebuild `.symtab`
pub static_symtab: bool,

/// Rebuild `DT_VERDEF`
pub sym_verdef: bool,

/// Rebuild `DT_VERNEED`
pub sym_verneed: bool,

/// Rebuild `DT_VERSYM`
pub sym_versym: bool,

/// Rebuild `DT_SYMTAB`
pub symtab: bool,

/// Rebuild the Coredump notes
pub coredump_notes: bool,

/// Force to relocating all the ELF structures that are supported by LIEF (mostly for testing)
pub force_relocate: bool,
}

impl Default for Config {
fn default() -> Config {
Config {
dt_hash: true,
dyn_str: true,
dynamic_section: true,
fini_array: true,
gnu_hash: true,
init_array: true,
interpreter: true,
jmprel: true,
notes: false,
preinit_array: true,
relr: true,
android_rela: true,
rela: true,
static_symtab: true,
sym_verdef: true,
sym_verneed: true,
sym_versym: true,
symtab: true,
coredump_notes: true,
force_relocate: false,
}
}
}

impl Config {
#[doc(hidden)]
pub fn to_ffi(&self) -> ffi::ELF_Binary_write_config_t {
ffi::ELF_Binary_write_config_t {
dt_hash: self.dt_hash,
dyn_str: self.dyn_str,
dynamic_section: self.dynamic_section,
fini_array: self.fini_array,
gnu_hash: self.gnu_hash,
init_array: self.init_array,
interpreter: self.interpreter,
jmprel: self.jmprel,
notes: self.notes,
preinit_array: self.preinit_array,
relr: self.relr,
android_rela: self.android_rela,
rela: self.rela,
static_symtab: self.static_symtab,
sym_verdef: self.sym_verdef,
sym_verneed: self.sym_verneed,
sym_versym: self.sym_versym,
symtab: self.symtab,
coredump_notes: self.coredump_notes,
force_relocate: self.force_relocate,
}
}
}


1 change: 1 addition & 0 deletions api/rust/cargo/lief/src/macho.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub mod section;
pub mod symbol;
pub mod header;
pub mod stub;
pub mod builder;

#[doc(inline)]
pub use binary::Binary;
Expand Down
13 changes: 13 additions & 0 deletions api/rust/cargo/lief/src/macho/binary.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use std::mem::size_of;
use std::pin::Pin;
use std::path::Path;
use num_traits::{Num, cast};

use crate::Error;
use super::builder::Config;
use super::commands::build_version::{BuildVersion, Platform};
use super::commands::code_signature::CodeSignature;
use super::commands::code_signature_dir::CodeSignatureDir;
Expand Down Expand Up @@ -305,6 +307,17 @@ impl Binary {

Err(Error::NotSupported)
}

/// Write back the current MachO binary into the file specified in parameter
pub fn write(&mut self, output: &Path) {
self.ptr.as_mut().unwrap().write(output.to_str().unwrap());
}

/// Write back the current MachO binary into the file specified in parameter with the
/// configuration provided in the second parameter.
pub fn write_with_config(&mut self, output: &Path, config: Config) {
self.ptr.as_mut().unwrap().write_with_config(output.to_str().unwrap(), config.to_ffi());
}
}

impl generic::Binary for Binary {
Expand Down
25 changes: 25 additions & 0 deletions api/rust/cargo/lief/src/macho/builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use lief_ffi as ffi;

/// Structure used to configure the [`crate::macho::Binary::write_with_config`] operation
#[derive(Debug)]
pub struct Config {
/// Rebuild the `__LINKEDIT` segment
pub linkedit: bool,
}

impl Default for Config {
fn default() -> Config {
Config {
linkedit: true,
}
}
}

impl Config {
#[doc(hidden)]
pub fn to_ffi(&self) -> ffi::MachO_Binary_write_config_t {
ffi::MachO_Binary_write_config_t {
linkedit: self.linkedit,
}
}
}
6 changes: 6 additions & 0 deletions api/rust/cargo/lief/src/pe/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use lief_ffi as ffi;
use num_traits::{cast, Num};
use std::mem::size_of;
use std::pin::Pin;
use std::path::Path;

use super::data_directory::{DataDirectories, DataDirectory};
use super::debug;
Expand Down Expand Up @@ -307,6 +308,11 @@ impl Binary {

Err(Error::NotSupported)
}

/// Write back the current PE binary into the file specified in parameter
pub fn write(&mut self, output: &Path) {
self.ptr.as_mut().unwrap().write(output.to_str().unwrap());
}
}

impl std::fmt::Debug for Binary {
Expand Down
14 changes: 14 additions & 0 deletions api/rust/cargo/lief/tests/elf_tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod utils;
use std::env;
use lief::elf::builder::Config;
use lief::logging;
use lief::elf::dynamic;
use lief::elf::dynamic::DynamicEntry;
Expand Down Expand Up @@ -224,3 +225,16 @@ fn test_api() {
test_with("simple-gcc-c.bin");
}

#[test]
fn test_mut_api() {
let path = utils::get_elf_sample("elf_reader.mips.elf").unwrap();
let Binary::ELF(mut bin) = Binary::parse(path.to_str().unwrap()).unwrap() else { panic!("Expecting an ELF"); };
let tmpfile = tempfile::NamedTempFile::new().unwrap();
bin.write(tmpfile.path());

let path = utils::get_elf_sample("ELF_Core_issue_808.core").unwrap();
let Binary::ELF(mut bin) = Binary::parse(path.to_str().unwrap()).unwrap() else { panic!("Expecting an ELF"); };
let tmpfile = tempfile::NamedTempFile::new().unwrap();
bin.write_with_config(tmpfile.path(), Config::default());
}

20 changes: 19 additions & 1 deletion api/rust/cargo/lief/tests/macho_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod utils;
use std::path::Path;
use std::env;
use lief::logging;
use lief::macho::builder::Config;
use lief::macho::Relocation;
use lief::generic::Binary as GenericBinary;
use lief::macho::binding_info::{self, AsGeneric};
Expand Down Expand Up @@ -310,7 +311,6 @@ fn test_with_fullpath(name: &str, suffix: &str) {

#[test]
fn test_api() {

let mut dir = env::temp_dir();
dir.push("lief_macho_test.log");
logging::set_path(dir.as_path());
Expand All @@ -330,3 +330,21 @@ fn test_api() {
test_with("liblog_srp.dylib");
test_with_fullpath("CoreFoundation", "private/MachO/CoreFoundation");
}

#[test]
fn test_mut_api() {
let path = utils::get_macho_sample("FAT_MachO_x86_x86-64_library_libc++abi.dylib").unwrap();
let Binary::MachO(fat) = Binary::parse(path.to_str().unwrap()).unwrap() else { panic!("Expecting an ELF"); };
for mut bin in fat.iter() {
let tmpfile = tempfile::NamedTempFile::new().unwrap();
bin.write(tmpfile.path());
}

let path = utils::get_macho_sample("json_api.cpp_1.o").unwrap();
let Binary::MachO(fat) = Binary::parse(path.to_str().unwrap()).unwrap() else { panic!("Expecting an ELF"); };
for mut bin in fat.iter() {
let tmpfile = tempfile::NamedTempFile::new().unwrap();
bin.write_with_config(tmpfile.path(), Config::default());
}
}

Loading

0 comments on commit a11b1b7

Please sign in to comment.