#executable #elf #mach-o #binary #pe #binary-format #run-time

bin+lib libsui

A injection tool for executable formats (ELF, PE, Mach-O) that allows you to embed files into existing binary and extract them at runtime

10 releases (5 breaking)

0.5.0 Nov 5, 2024
0.4.0 Sep 30, 2024
0.3.1 Sep 20, 2024
0.3.0 Aug 14, 2024
0.0.1 May 26, 2024

#209 in Parser implementations

Download history 760/week @ 2024-08-21 699/week @ 2024-08-28 1127/week @ 2024-09-04 909/week @ 2024-09-11 1119/week @ 2024-09-18 1048/week @ 2024-09-25 1056/week @ 2024-10-02 1698/week @ 2024-10-09 1466/week @ 2024-10-16 1456/week @ 2024-10-23 2195/week @ 2024-10-30 2347/week @ 2024-11-06 2167/week @ 2024-11-13 901/week @ 2024-11-20 1046/week @ 2024-11-27 945/week @ 2024-12-04

5,391 downloads per month
Used in 9 crates (6 directly)

MIT license

775KB
959 lines

Contains (ELF exe/lib, 410KB) tests/exec_elf64, (Mach-o exe, 400KB) tests/exec_mach64, (DOS exe, 145KB) tests/exec_pe64

libsui

Crates.io

Sui (सुई) is a injection tool for executable formats (ELF, PE, Mach-O) that allows you to embed files into existing binary and extract them at runtime.

It produces valid executables that can be code signed on macOS and Windows.

Documentation | Usage

Usage

cargo add libsui

Embedding data into binaries:

use libsui::{Macho, PortableExecutable};

let exe = std::fs::read("tests/exec_mach64")?;
let mut out = std::fs::File::create("out")?;

Macho::from(exe)?
    .write_section("__hello", b"Hello, World!".to_vec())?
    .build(&mut out)?;

let exe = std::fs::read("tests/exec_pe64")?;
let mut out = std::fs::File::create("out.exe")?;

PortableExecutable::from(exe)?
    .write_resource("hello.txt", b"Hello, World!".to_vec())?
    .build(&mut out)?;

Extracting from self:

use libsui::find_section;

let data = find_section("hello.txt")?;

Design

Mach-O

Resource is added as section in a new segment, load commands are updated and offsets are adjusted. __LINKEDIT is kept at the end of the file.

It is similar to linker's -sectcreate,__FOO,__foo,hello.txt option.

Note that Macho::build will invalidate existing code signature. on Apple sillicon, kernel refuses to run executables with bad signatures.

Use Macho::build_and_sign to re-sign the binary with ad-hoc signature. See apple_codesign.rs for details. This is similar to codesign -s - ./out command.

Macho::from(exe)?
    .write_section("__sect", data)?
    .build_and_sign(&mut out)?;
$ codesign -d -vvv ./out

Executable=/Users/divy/gh/sui/out
Identifier=a.out
Format=Mach-O thin (arm64)
CodeDirectory v=20400 size=10238 flags=0x20002(adhoc,linker-signed) hashes=317+0 location=embedded
Hash type=sha256 size=32
CandidateCDHash sha256=6b1abb20f2291dd9b0dbcd0659a918cb2d0e6b18
CandidateCDHashFull sha256=6b1abb20f2291dd9b0dbcd0659a918cb2d0e6b1876153efa17f90dc8b3a8f177
Hash choices=sha256
CMSDigest=6b1abb20f2291dd9b0dbcd0659a918cb2d0e6b1876153efa17f90dc8b3a8f177
CMSDigestType=2
CDHash=6b1abb20f2291dd9b0dbcd0659a918cb2d0e6b18
Signature=adhoc
Info.plist=not bound
TeamIdentifier=not set
Sealed Resources=none
Internal requirements=none

PE

Resource is added into a new PE resource directory as RT_RCDATA type and extracted using FindResource and LoadResource at run-time.

ELF

Data is simply appended to the end of the file and extracted from current_exe() at run-time.

This is subject to change and may use ELF linker notes (PT_NOTE) in the future.

Testing

This crate is fuzzed with LLVM's libFuzzer. See fuzz/.

exec_* executables in tests/ are compiled from tests/exec.rs:

rustc exec.rs -o exec_elf64 --target x86_64-unknown-linux-gnu

License

MIT

Dependencies

~2–14MB
~122K SLoC