Binkit is a Rust command-line toolbox for inspecting, disassembling, and modifying ELF64 binaries. It can display ELF metadata, disassemble x86-64 code, calculate an injection plan, append a payload, and update the executable entry point.
Use Binkit only on binaries you own or are authorized to modify. You are responsible for complying with applicable laws, licenses, and policies.
- Display complete ELF64, program-header, and section-header information.
- Disassemble ELF sections or raw x86-64 machine code using Intel syntax.
- Calculate aligned payload addresses and signed
rel32return offsets. - Append a payload by repurposing a compatible section and program header.
- Update the ELF entry point.
- Protect existing output files unless
--forceis explicitly provided. - Write files atomically while preserving the source permissions.
- Reject malformed or unsupported ELF structures with descriptive errors.
See ELF compatibility for the exact supported formats and current limitations.
cargo install --locked binkitgit clone https://github.com/matheus-git/binkit.git
cd binkit
cargo build --release --locked
./target/release/binkit --helpPrebuilt binaries may also be available on the GitHub Releases page.
Run binkit --help or binkit <COMMAND> --help for the complete CLI reference.
The info command displays the complete ELF header and its program or section tables. Options
can be combined:
binkit info ./program --header
binkit info ./program --programs
binkit info ./program --sections
binkit info ./program --header --programs --sectionsThe header output includes identification fields, byte order, ABI, file type, architecture, entry point, flags, table offsets, entry sizes, counts, and the section-name table index.
Disassemble .text or another section from a little-endian x86-64 ELF file:
binkit disasm ./program
binkit disasm ./program --section .initDisassemble a file containing raw x86-64 machine code:
binkit disasm ./payload.bin --binCalculate the aligned injection address and the signed rel32 displacement back to the current
entry point:
binkit check-inject ./program
binkit check-inject ./program --return-address 0x401000This command only reports values; it does not modify or create a file.
Append a payload and write the modified ELF to a new file:
binkit inject ./program \
--inject ./payload.bin \
--output ./program.injectedBy default, Binkit repurposes .note.gnu.property, renames it to .injected, and assigns an
aligned virtual address. Select another compatible section or address when needed:
binkit inject ./program \
--inject ./payload.bin \
--section .custom-note \
--address 0x405000 \
--return-address 0x401000 \
--output ./program.injectedInjection requires the selected section to have a matching program header and enough space in
the section-name string table for .injected. The command fails without creating the output if
these requirements are not met.
Existing destinations are protected. Use --force only when replacement is intentional:
binkit inject ./program -i ./payload.bin -o ./program.injected --forceThe payload is appended as provided. Binkit reports the injection address and return displacement but does not generate a jump, trampoline, or architecture-specific payload instructions.
Write a new ELF entry point to a separate output file:
binkit update ./program --entry 0x405000 --output ./program.updatedOmitting --output updates the input path atomically. Replacing a different existing destination
requires --force.
The ELF64 parser and core calculations are available as a Rust library:
use binkit::elf64::{Elf64Binary, calculate_rel32};
let bytes = std::fs::read("program")?;
let binary = Elf64Binary::new(&bytes)?;
println!("Entry point: 0x{:X}", binary.entry());
println!("rel32: {}", calculate_rel32(0x405000, binary.entry())?);
# Ok::<(), anyhow::Error>(())The project toolchain is pinned in rust-toolchain.toml and is installed automatically by
rustup. Run the same quality checks used by CI:
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-targets --all-features
cargo build --release --lockedThe integration tests also use GNU binutils, GCC, Clang, and lld. They compile several ELF64 variants, execute an injected x86-64 payload, and verify that another payload can restore the initial process state and return to the original entry point. On Debian or Ubuntu:
sudo apt-get update
sudo apt-get install binutils build-essential clang lldThe fuzz target requires nightly Rust and cargo-fuzz:
cargo install cargo-fuzz --locked
cargo +nightly fuzz run elf64-roundtripGenerated fuzz corpora, artifacts, and build output are ignored by Git.
Contributions should include tests for behavior changes and pass the formatting, lint, test, and release-build commands above. Useful areas include additional ELF validation, executable injection fixtures, architecture support, structured output, and other binary formats.
Licensed under the MIT License.