$npx -y skills add mohitmishra786/low-level-dev-skills --skill elf-inspectionELF binary inspection skill for Linux. Use when examining ELF executables or shared libraries with readelf, objdump, nm, or ldd to understand symbol visibility, section layout, dynamic dependencies, build IDs, or relocation entries. Activates on queries about ELF format, shared l
| 1 | # ELF Inspection |
| 2 | |
| 3 | ## Purpose |
| 4 | |
| 5 | Guide agents through inspecting Linux ELF binaries: symbol tables, section layout, dynamic linking, debug info, and diagnosing linker errors. |
| 6 | |
| 7 | ## Triggers |
| 8 | |
| 9 | - "What libraries does this binary depend on?" |
| 10 | - "Why is this binary so large?" |
| 11 | - "I have an `undefined reference` or symbol not found at runtime" |
| 12 | - "How do I check if debug info is in this binary?" |
| 13 | - "How do I find what symbols a library exports?" |
| 14 | - "How do I check if a binary is PIE / has RELRO?" |
| 15 | |
| 16 | ## Workflow |
| 17 | |
| 18 | ### 1. Quick overview: `file` and `size` |
| 19 | |
| 20 | ```bash |
| 21 | file prog # type, arch, linkage, stripped or not |
| 22 | size prog # section sizes: text, data, bss |
| 23 | size --format=sysv prog # detailed per-section breakdown |
| 24 | ``` |
| 25 | |
| 26 | ### 2. Dynamic dependencies: `ldd` |
| 27 | |
| 28 | ```bash |
| 29 | ldd ./prog # show all shared lib dependencies |
| 30 | ldd -v ./prog # verbose: include symbol versions |
| 31 | |
| 32 | # Check why a library is loaded |
| 33 | ldd ./prog | grep libssl |
| 34 | |
| 35 | # For a library (not an executable) |
| 36 | ldd ./libfoo.so |
| 37 | ``` |
| 38 | |
| 39 | If `ldd` shows `not found`, the shared library is missing from `LD_LIBRARY_PATH` or `/etc/ld.so.conf`. |
| 40 | |
| 41 | Fix: |
| 42 | |
| 43 | ```bash |
| 44 | export LD_LIBRARY_PATH=/path/to/libs:$LD_LIBRARY_PATH |
| 45 | # Or install the library and run ldconfig |
| 46 | sudo ldconfig |
| 47 | ``` |
| 48 | |
| 49 | ### 3. Symbols: `nm` |
| 50 | |
| 51 | ```bash |
| 52 | nm prog # all symbols (T=text, D=data, U=undefined, etc.) |
| 53 | nm -D ./libfoo.so # dynamic symbols only |
| 54 | nm -C prog # demangle C++ symbols |
| 55 | nm --defined-only prog # only defined symbols |
| 56 | nm -u prog # only undefined (needed) symbols |
| 57 | nm -S prog # include symbol size |
| 58 | |
| 59 | # Search for a symbol |
| 60 | nm -D /usr/lib/libssl.so | grep SSL_read |
| 61 | ``` |
| 62 | |
| 63 | Symbol type codes: |
| 64 | |
| 65 | - `T` / `t` — text (code): global / local |
| 66 | - `D` / `d` — data (initialised): global / local |
| 67 | - `B` / `b` — BSS (uninitialised): global / local |
| 68 | - `R` / `r` — read-only data: global / local |
| 69 | - `U` — undefined (needs to be provided at link time) |
| 70 | - `W` / `w` — weak symbol |
| 71 | |
| 72 | ### 4. Sections: `readelf` |
| 73 | |
| 74 | ```bash |
| 75 | readelf -h prog # ELF header (arch, type, entry point) |
| 76 | readelf -S prog # all sections |
| 77 | readelf -l prog # program headers (segments) |
| 78 | readelf -d prog # dynamic section (like ldd but raw) |
| 79 | readelf -s prog # symbol table |
| 80 | readelf -r prog # relocations |
| 81 | readelf -n prog # notes (build ID, ABI tag) |
| 82 | readelf --debug-dump=info prog | head -100 # DWARF info |
| 83 | readelf -a prog # all of the above |
| 84 | ``` |
| 85 | |
| 86 | ### 5. Disassembly and source: `objdump` |
| 87 | |
| 88 | ```bash |
| 89 | # Disassemble all code sections |
| 90 | objdump -d prog |
| 91 | objdump -d -M intel prog # Intel syntax |
| 92 | |
| 93 | # Disassemble + intermix source (needs -g at compile time) |
| 94 | objdump -d -S prog |
| 95 | |
| 96 | # Disassemble specific symbol |
| 97 | objdump -d prog | awk '/^[0-9a-f]+ <main>:/,/^$/' |
| 98 | |
| 99 | # All sections (including data) |
| 100 | objdump -D prog |
| 101 | |
| 102 | # Header info |
| 103 | objdump -f prog |
| 104 | objdump -p prog # private headers (including needed libs) |
| 105 | ``` |
| 106 | |
| 107 | ### 6. Binary hardening check |
| 108 | |
| 109 | ```bash |
| 110 | # Check for PIE, RELRO, stack canary, NX |
| 111 | # Use checksec (install separately) |
| 112 | checksec --file=prog |
| 113 | |
| 114 | # Manual checks: |
| 115 | readelf -h prog | grep Type # ET_DYN = PIE, ET_EXEC = non-PIE |
| 116 | readelf -d prog | grep GNU_RELRO # RELRO present |
| 117 | readelf -d prog | grep BIND_NOW # full RELRO |
| 118 | readelf -s prog | grep __stack_chk # stack protector |
| 119 | readelf -l prog | grep GNU_STACK # NX bit (RW = no exec, RWE = exec stack) |
| 120 | ``` |
| 121 | |
| 122 | ### 7. Section size analysis (binary bloat) |
| 123 | |
| 124 | ```bash |
| 125 | # Detailed section sizes |
| 126 | size --format=sysv prog | sort -k2 -nr | head -20 |
| 127 | |
| 128 | # Per-object contribution (with -Wl,--print-map or bloaty) |
| 129 | # Bloaty (install separately): https://github.com/google/bloaty |
| 130 | bloaty prog |
| 131 | |
| 132 | # Check stripped vs not |
| 133 | file prog |
| 134 | strip --strip-all -o prog.stripped prog |
| 135 | ls -lh prog prog.stripped |
| 136 | ``` |
| 137 | |
| 138 | ### 8. Build ID |
| 139 | |
| 140 | Build IDs uniquely identify a binary/library build, enabling `debuginfod` lookups. |
| 141 | |
| 142 | ```bash |
| 143 | readelf -n prog | grep 'Build ID' |
| 144 | # or |
| 145 | file prog | grep BuildID |
| 146 | ``` |
| 147 | |
| 148 | ### 9. Common diagnosis flows |
| 149 | |
| 150 | **"undefined symbol at runtime"** |
| 151 | |
| 152 | ```bash |
| 153 | # Which library was expected to provide it? |
| 154 | nm -D libfoo.so | grep mysymbol |
| 155 | # Is the library in the runtime path? |
| 156 | ldd ./prog | grep libfoo |
| 157 | # Check LD_PRELOAD / LD_LIBRARY_PATH |
| 158 | ``` |
| 159 | |
| 160 | **"binary is too large"** |
| 161 | |
| 162 | ```bash |
| 163 | size --format=sysv prog | sort -k2 -nr | head |
| 164 | nm -S --defined-only prog | sort -k2 -nr | head -20 |
| 165 | objdump -d prog | awk '/^[0-9a-f]+ </{fn=$2} /^[0-9a-f]/{count[fn]++} END{for(f in count) print count[f], f}' | sort -nr | head -20 |
| 166 | ` |