Description
This document describes inner workings of sui, an injection tool for embedding arbitrary data into precompiled executables (ELF, PE and Mach-O).
It is cross-platform and supports cross-“patching” for all formats. Under the hood sui uses format-specific features described in Supported formats.
It produces valid executables that can be code-signed and distributed.
Emebedded data can be accessed by the executable at runtime using libsui library. Using sui
It is available as a Rust crate and a command-line tool.
cargo add libsui
Run-time
Find and extract the embedded data from the executable:
use libsui::find_section;if let Some(data) = find_section("mydata") {
// found
}
Name of the section is the same as the one used during injection. It refers to the section name in Mach-O, resource name in PE and tag in ELF.
Injecting
Build and sign a new Mach-O executable:
use sui::Macho;Macho::from(input)? // load an existing executable
.write_section("mydata", data)? // write a new section with auxiliary data
.build_and_sign(output)?; // build and sign the executable
Build a new Portable Executable:
use sui::PortableExecutable;PortableExecutable::from(input)? // load an existing executable
.write_resource("mydata", data)? // inject a new resource (RCDATA) with auxiliary data
.build(output)?; // build and sign the executable
Build a new ELF executable:
use sui::Elf;Elf::from(input)? // load an existing executable
.append("mydata", data)? // tag and append auxiliary data
.build(output)?; // build
Build a new PE with icon:
use sui::PortableExecutable;PortableExecutable::from(input)? // load an existing executable
.write_resource("mydata", data)? // inject a new resource (RCDATA) with auxiliary data
.write_icon("icon.ico")? // inject an icon resource (RT_ICON)
.build(output)?; // build
Ad-hoc codesign a modified arm64 Mach-O executable:
use sui::apple_codesign::MachoSigner;MachoSigner::new(input)? // load an existing executable
.sign(output)?; // sign the executable with ad-hoc signature
Refer to the API documentation for more up-to-date documentation.
Supported formats
ELF, PE and Mach-O are supported.
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 ./outExecutable=/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
ELF
Data is simply appended to the end of the file with a tag and magic descriptor. Extracted from current_exe() at run-time.
This is subject to change and may use ELF linker notes (PT_NOTE) in the future.
PE
Resource is added into a new PE resource directory as RT_RCDATA type and extracted using FindResource and LoadResource at run-time.
Comparison with postject
Sui supports ad-hoc codesigning for Mach-O executables and Icon resources for PE executables which postject does not.
Sui is much faster and lightweight compared to postject which is built on top of LIEF, a heavy C++ dependency.
$ time sui ./node test.txt ./out
0m0.151s$ time postject ./node name test.txt
0m8.993s
Conclusion
sui is open-source on Github: https://github.com/denoland/sui and is the tech behind deno compile, converts JavaScript and TypeScript code into a single executable.