Avatar

LIEF Rust bindings updates

ionicons-v5-k Romain Thomas June 16, 2024
Wave

The rust bindings for LIEF are getting more and more production-ready for the next official release of LIEF (v0.15.0). This blog post exposes the recent updates on these bindings and some use cases.

Documentation

The Rust documentation for the current bindings is now almost complete such as most of the functions and structures are documented:

LIEF Rust Documentation

One can access the nightly doc at this address: https://lief-rs.s3.fr-par.scw.cloud/doc/latest/lief/index.html

New Architectures Supported

As mentioned in the previous blog post, the Rust bindings work with a “pre-compilation” step. Since the previous blog post, I added the support of iOS (i.e. aarch64-apple-ios) and for Linux ARM64 (i.e. aarch64-unknown-linux-gnu) which gives us this support in LIEF compared to the Rust Platform Support

Rust Tier 1 Support

TripletSupportComment
aarch64-unknown-linux-gnu
i686-pc-windows-gnu
i686-pc-windows-msvc🤷Could be supported if needed
i686-unknown-linux-gnu🤷Could be supported if needed
x86_64-apple-darwin
x86_64-pc-windows-gnu
x86_64-pc-windows-msvc
x86_64-unknown-linux-gnu

Rust Tier 2 Support

TripletSupportComment
aarch64-apple-ios
aarch64-apple-ios-sim🤷Could be supported if needed
aarch64-linux-android⏱️Planned
aarch64-apple-darwin
x86_64-unknown-linux-musl⏱️Planned

The support for some triplets like i686-pc-windows-msvc will be done on an as-needed basis so feel free to reach out or to open an issue/discussion on GitHub if you need this support.

Uses Cases

 1// This code checks the PE Authenticode
 2
 3let path = std::env::args().last().unwrap();
 4let mut file = std::fs::File::open(path).expect("Can't open the file");
 5
 6if let Some(lief::Binary::PE(pe)) = lief::Binary::from(&mut file) {
 7    let result = pe.verify_signature(pe::signature::VerificationChecks::DEFAULT);
 8    if result.is_ok() {
 9        println!("Valid signature!");
10    } else {
11        println!("Signature not valid: {}", result);
12    }
13    return ExitCode::SUCCESS;
14}
15ExitCode::FAILURE

 1// This code list all the libraries needed by an ELF binary as well as
 2// the versioning of the symbols.
 3// Example of output:
 4// Dependencies:
 5//   - libclang-cpp.so.17
 6//   - libLLVM-17.so
 7//   - libstdc++.so.6
 8//   - libc.so.6
 9// Versions:
10//   From libc.so.6
11//     - GLIBC_ABI_DT_RELR
12//     - GLIBC_2.14
13//     - GLIBC_2.34
14//     - GLIBC_2.32
15//   From libstdc++.so.6
16//     - GLIBCXX_3.4.29
17//     - GLIBCXX_3.4.30
18//   From libLLVM-17.so
19//     - LLVM_17
20
21let mut args = std::env::args();
22if args.len() != 2 {
23    println!("Usage: {} <binary>", args.next().unwrap());
24    return ExitCode::FAILURE;
25}
26
27let path = std::env::args().last().unwrap();
28let mut file = std::fs::File::open(&path).expect("Can't open the file");
29if let Some(lief::Binary::ELF(elf)) = lief::Binary::from(&mut file) {
30    println!("Dependencies:");
31    for entry in elf.dynamic_entries() {
32        if let dynamic::Entries::Library(lib) = entry {
33            println!("  - {}", lib.name());
34        }
35    }
36    println!("Versions:");
37    for version in elf.symbols_version_requirement() {
38        println!("  From {}", version.name());
39        for aux in version.auxiliary_symbols() {
40            println!("    - {}", aux.name());
41        }
42    }
43
44    return ExitCode::SUCCESS;
45}
46println!("Can't process {}", path);
47ExitCode::FAILURE

 1// Inspecting the PE rich header
 2
 3let path = std::env::args().last().unwrap();
 4let mut file = std::fs::File::open(&path).expect("Can't open the file");
 5
 6if let Some(lief::Binary::PE(pe)) = lief::Binary::from(&mut file) {
 7    let rich_header = pe.rich_header().unwrap_or_else(|| {
 8        println!("Rich header not found!");
 9        process::exit(0);
10    });
11
12    println!("Rich header key: 0x{:x}", rich_header.key());
13    for entry in rich_header.entries() {
14        println!("id: 0x{:04x} build_id: 0x{:04x} count: #{}",
15                 entry.id(), entry.build_id(), entry.count());
16    }
17
18    return ExitCode::SUCCESS;
19}
20println!("Can't process {}", path);
21ExitCode::FAILURE

 1// Dumping which section of an iOS app is encrypted
 2
 3let path = std::env::args().last().unwrap();
 4let mut file = std::fs::File::open(&path).expect("Can't open the file");
 5
 6if let Some(lief::Binary::MachO(fat)) = lief::Binary::from(&mut file) {
 7    for macho in fat.iter() {
 8        for cmd in macho.commands() {
 9            if let lief::macho::Commands::EncryptionInfo(info) = cmd {
10                println!("Encrypted area: 0x{:08x} - 0x{:08x} (id: {})",
11                    info.crypt_offset(), info.crypt_offset() + info.crypt_size(),
12                    info.crypt_id()
13                )
14            }
15        }
16    }
17    return ExitCode::SUCCESS;
18}
Avatar
Romain Thomas Posted on June 16, 2024