Skip to content
AZ Tools

ELF Binary Inspector

Reads an ELF binary the way readelf does, straight out of the bytes and entirely in your browser. The header gives the word size and byte order, the OS/ABI, the architecture, the entry point and whether the file is a relocatable object, a plain executable, a position-independent executable or a shared library — a distinction the header alone does not make, because a PIE and a .so are both DYN and only the interpreter or the DF_1_PIE flag tells them apart. The program headers list what the loader maps, and the dynamic array gives the interpreter path, every library in DT_NEEDED, the SONAME a library publishes itself under, and any RPATH or RUNPATH baked into the file — the last of these is worth checking on anything you did not build yourself, since it changes where the loader looks for libraries. The hardening row answers the questions checksec answers, from the same places: PIE from the type and DF_1_PIE, NX from whether PT_GNU_STACK is writable-executable, and RELRO as none, partial or full depending on whether PT_GNU_RELRO is present and BIND_NOW is set. Stripped means the file has no SHT_SYMTAB, which is what strip removes; the dynamic symbol table stays either way, so a stripped library still exports its names. Two things it does not do: it will not disassemble, and it will not tell you whether a stack-protector or FORTIFY_SOURCE was used, because both of those need the symbol table read for specific names rather than a header flag. Big-endian and 32-bit files are read correctly — the word size and byte order come out of the first six bytes and everything after is read through them — so an ARM, MIPS or PowerPC binary from a router or an embedded image opens as readily as an x86-64 one.

How to use

  1. Drop the binary onto the box — an executable with no extension, a .so, a .o or a core file all work.
  2. Read the header row for the architecture and type. PIE executable and shared object are both DYN; the interpreter line below tells you which one you have.
  3. Check the hardening chips: PIE, NX and full RELRO are what a distribution build normally has, and an amber chip is worth explaining before you ship the file.
  4. Look at Needs for the shared libraries the loader will search for, and at RUNPATH for any non-standard directory the binary adds to that search.
  5. Open the section list when you need sizes — .text for code, .rodata for constants, and .debug_* sections if debug information was left in.

Frequently asked questions

What is the difference between a PIE executable and a shared library? Both say DYN.
The ELF type really is the same: position-independent code that the loader can map at any address. What separates them is that an executable has a PT_INTERP program header naming the dynamic loader (usually /lib64/ld-linux-x86-64.so.2) so the kernel knows how to start it, while a library has none and is only ever loaded by something else. Modern toolchains also set DF_1_PIE in the dynamic flags of an executable, which is what readelf reports and what this tool uses first, falling back to the interpreter when an older linker left the flag out.
What do PIE, NX and RELRO actually protect against?
PIE lets the kernel load the binary at a random base address, so ASLR applies to the program's own code and not just the libraries — without it, gadget addresses are fixed and known. NX marks the stack non-executable, so injected shellcode cannot simply be jumped to. RELRO makes the relocation tables read-only after startup: partial protects the ones resolved before main, and full also resolves every function up front so the GOT can be made read-only, closing the classic GOT-overwrite technique. All three are link-time properties, which is why they can be read from the file without running it.
Why does it say the binary is stripped when I can still see function names?
There are two symbol tables. Stripped here means SHT_SYMTAB is gone, which is what strip removes and what a debugger needs. The dynamic symbol table, SHT_DYNSYM, has to stay in any file that exports or imports symbols, or dynamic linking could not work — so a stripped library still lists everything it exports, and a stripped executable still lists what it imports. That is why nm on a stripped file says no symbols while nm -D still prints a list.
Can it read a binary for another architecture, or a big-endian one?
Yes. The class byte and the data byte at the start of the header say whether the file is 32- or 64-bit and which byte order it uses, and every field after that is read through those two, so an AArch64, ARM, MIPS, RISC-V or big-endian PowerPC binary is read as accurately as an x86-64 one. The architecture is reported by name for the common machine types and as a raw code for anything else. What it cannot do is tell you whether the binary will run on your machine — that depends on the kernel, the ABI and the libraries, not only the header.
What is a Build ID for?
It is a hash the linker stores in a note section, identifying that exact build. Distributions use it to match a binary with its separately-shipped debug symbols: the debug file lands in /usr/lib/debug/.build-id/xx/yyyy.debug, and a debugger given a core dump can find the right symbols even when the binary itself has been stripped. It is also a reliable way to tell whether two files really are the same build, since the id changes with any change to the compiled output.
Does the binary get uploaded anywhere?
No. The file is read with the browser's File API and parsed by JavaScript in the page. Nothing is sent to a server and there is no server-side component to send it to, which matters here more than for most tools: a binary you are inspecting may well be something you are not free to upload. You can disconnect from the network after the page loads and everything still works.

Related tools