Home / Alt manpages / elfedit(1)

  • elfedit(1)
  • User command
  • linux

Edit ELF Header Fields Safely with elfedit

Sometimes a binary needs one header byte changed, such as its OSABI, and a hex editor is a very good way to ruin it. The command elfedit changes selected ELF header fields properly, and this guide shows how to verify with readelf and roll back, in about fifteen minutes.

The examples use GNU Binutils 2.42, the version installed here. You need elfedit, readelf, a shell, and an ELF file you are allowed to modify. The commands normally need no elevated privileges. Use sudo only when the file's ownership or permissions genuinely require it. Root access does not make an unsafe metadata change safe.

Warning

elfedit edits files in place. Work on a copy first, keep a backup until verification is complete, and do not experiment on a running system binary or a production service executable.

1. Check the installed command

Confirm which binary will run and record its version:

$ command -v elfedit
/usr/bin/elfedit
$ elfedit --version
GNU elfedit (GNU Binutils for Ubuntu) 2.42

The installed elfedit, aarch64-linux-gnu-elfedit and x86_64-linux-gnu-elfedit manpages describe the same Binutils 2.42 interface. The target-prefixed names do not mean every target-specific machine name is accepted. This build documents i386, IAMCU, L1OM, K1OM and x86-64 for machine matching and output.

Checkpoint

If elfedit --version reports a different release, read that installation's manual before copying the examples. Option names and supported values are version-specific.

2. Make a disposable working copy

Choose an ELF file and copy it to a temporary or working directory. This example uses the harmless system utility true; replace the source with your own file:

$ mkdir -p "$HOME/elfedit-work"
$ cp /usr/bin/true "$HOME/elfedit-work/true"
$ cp "$HOME/elfedit-work/true" "$HOME/elfedit-work/true.orig"
$ file "$HOME/elfedit-work/true"
/home/you/elfedit-work/true: ELF 64-bit LSB pie executable, ...

The second copy is the undo path. Keep it unchanged.

Tip

If you are editing an archive containing ELF files, make a separate archive backup as well. The manual says archives are supported, but an archive edit is still a write operation.

3. Inspect the original header

Use readelf before changing anything. The header fields relevant to this guide are class, file type, machine, OSABI and ABI version:

$ readelf -h "$HOME/elfedit-work/true" | grep -E 'Class:|OS/ABI:|Type:|Machine:|ABI Version:'
  Class:                             ELF64
  OS/ABI:                            UNIX - System V
  Type:                              DYN (Position-Independent Executable file)
  Machine:                           Advanced Micro Devices X86-64
  ABI Version:                       0

The exact machine description and spacing vary, so save the important values, not the presentation. The original file here is a 64-bit position-independent executable. Changing its file type or machine field would be far more consequential than changing a test OSABI value.

4. Change selected header fields

At least one output option is required. This example changes the copied file's OSABI to the installed command's Linux alias for GNU and sets the ELF ABI version to 7:

$ elfedit \
    --output-osabi=Linux \
    --output-abiversion=7 \
    "$HOME/elfedit-work/true"
$ readelf -h "$HOME/elfedit-work/true" | grep -E 'OS/ABI:|ABI Version:'
  OS/ABI:                            UNIX - GNU
  ABI Version:                       7

The other output options and their values:

  • --output-mach and --output-type. The supported file types in this installation are rel, exec and dyn.
  • OSABI values. They include none, GNU, Linux, FreeBSD and others listed by elfedit --help.
  • ABI versions. These must be integers from 0 through 255.

Safety boundary

Changing the machine or file type can make a file unusable, even if the command exits successfully. Do not use those options to force a loader or build tool to accept an incompatible file. Test the result with the real consumer, and keep the backup until that test has passed.

5. Add an input filter before a risky edit

Input options make the edit conditional. For example, this command changes only a relocatable object whose machine is x86-64:

$ elfedit \
    --input-mach=x86-64 \
    --input-type=rel \
    --output-osabi=GNU \
    path/to/object.o

If the file does not match, elfedit reports an unmatched field and returns a non-zero status. In a local test, applying --input-type=rel to an ordinary PIE produced Unmatched e_type, status 1, and left the OSABI unchanged. Treat a non-zero status as a failed edit and inspect the file again instead of carrying on automatically.

The other filters are --input-osabi and --input-abiversion. Omitting an input filter means that field matches any value. That is convenient for a controlled copy, but a poor guardrail for a script processing files from several build stages.

6. Use a response file for long commands

Options can be read from an @file. Put one or more whitespace-separated options in the file, quoting an option when its value needs whitespace:

$ printf '%s\n' '--output-osabi=NetBSD' > "$HOME/elfedit-work/options.txt"
$ cp "$HOME/elfedit-work/true.orig" "$HOME/elfedit-work/response-test"
$ elfedit "@$HOME/elfedit-work/options.txt" "$HOME/elfedit-work/response-test"
$ readelf -h "$HOME/elfedit-work/response-test" | grep 'OS/ABI:'
  OS/ABI:                            UNIX - NetBSD

Response files may include other response files recursively. A missing or unreadable file is treated literally, so check the exit status and inspect the result.

Warning

Do not build a response file from untrusted text without controlling its contents.

7. Verify, recover and automate

Verification is a separate step. Re-run readelf -h and compare every field you intended to change. For a script, capture the status immediately and stop on failure:

$ elfedit --output-osabi=Linux --output-abiversion=7 "$HOME/elfedit-work/true"
$ status=$?
$ if [ "$status" -ne 0 ]; then
>     printf 'elfedit failed with status %s\n' "$status" >&2
>     exit "$status"
> fi
$ readelf -h "$HOME/elfedit-work/true" | grep -E 'OS/ABI:|ABI Version:'

To undo the examples, replace the changed copy with the untouched backup:

$ cp "$HOME/elfedit-work/true.orig" "$HOME/elfedit-work/true"
$ readelf -h "$HOME/elfedit-work/true" | grep -E 'OS/ABI:|ABI Version:'
  OS/ABI:                            UNIX - System V
  ABI Version:                       0

Recovery

This works because the example preserved a byte-for-byte original. If you edited the only copy, recovery depends on your normal backup system. Do not assume that changing the header back will restore padding, archive metadata, or other bytes changed by a failed or interrupted operation.

Done means

  • Version confirmed. You checked the installed Binutils version and supported option values.
  • Backup kept. You copied the ELF file and retained an untouched original.
  • Header inspected first. You looked at the original header before editing it.
  • Precondition set. You used an input filter where the edit needed one.
  • Result verified. You checked the exit status and the changed fields with readelf.
  • Restore known. You know the restore command and have not modified a production executable by accident.