$npx -y skills add meltedinhex/analyst-ai-pack --skill analyzing-elf-binaries-on-linuxStatically analyzes Linux ELF malware: ELF header and sections, dynamic symbols
| 1 | # Analyzing ELF Binaries on Linux |
| 2 | |
| 3 | ## When to Use |
| 4 | |
| 5 | - You have a Linux executable or shared object and need to assess it statically. |
| 6 | - You want to read the ELF header, segments, dynamic symbols, and strings to infer behavior. |
| 7 | - You are checking for static linking, stripped symbols, or packing. |
| 8 | |
| 9 | **Do not use** symbol absence as proof of nothing — stripped or statically linked Go/Rust |
| 10 | binaries hide structure; switch to disassembly when static metadata is thin. |
| 11 | |
| 12 | ## Prerequisites |
| 13 | |
| 14 | - `readelf`/`nm`/`strings` (binutils) or `pyelftools` (`pip install pyelftools`). |
| 15 | - The sample in neutralized form inside the lab. |
| 16 | |
| 17 | ## Safety & Handling |
| 18 | |
| 19 | - Static only: parse the file; do not set it executable or run it. |
| 20 | |
| 21 | ## Workflow |
| 22 | |
| 23 | ### Step 1: Read the ELF header |
| 24 | |
| 25 | ```bash |
| 26 | python scripts/analyst.py analyze sample.elf |
| 27 | ``` |
| 28 | |
| 29 | Note class (ELF32/64), endianness, type (EXEC/DYN/REL), machine (x86-64, ARM, MIPS), and |
| 30 | whether it is stripped. |
| 31 | |
| 32 | ### Step 2: Examine segments and section permissions |
| 33 | |
| 34 | Writable+executable segments, or a single large segment, suggest packing or self-modifying |
| 35 | code. Compare `PT_LOAD` permissions against expectations. |
| 36 | |
| 37 | ### Step 3: Inspect dynamic symbols and needed libraries |
| 38 | |
| 39 | Imported functions hint at capability: `socket`/`connect` (network), `ptrace` (anti-debug or |
| 40 | injection), `fork`/`execve` (process control), `crypt`/`EVP_*` (encryption). |
| 41 | |
| 42 | ### Step 4: Detect static linking and packing |
| 43 | |
| 44 | Static binaries lack a dynamic symbol table and `NEEDED` entries. High whole-file entropy and |
| 45 | a tiny section table suggest a packer (e.g. UPX leaves `UPX!` markers). |
| 46 | |
| 47 | ### Step 5: Skim strings and constructors |
| 48 | |
| 49 | Check `.init_array`/constructors (code before `main`), and strings for paths, URLs, and shell |
| 50 | commands. |
| 51 | |
| 52 | ## Validation |
| 53 | |
| 54 | - Header `type` and segment permissions are consistent with the inferred behavior. |
| 55 | - Imported symbols correspond to plausible capabilities. |
| 56 | - Packing call (entropy + missing sections) matches the strings observed. |
| 57 | |
| 58 | ## Pitfalls |
| 59 | |
| 60 | - Assuming dynamic symbols are complete — they only cover imported/exported names, not |
| 61 | internal functions. |
| 62 | - Treating a stripped Go binary as "empty"; its structure lives in runtime metadata, not the |
| 63 | symbol table. |
| 64 | - Ignoring constructors/`.init_array`, which run before `main`. |
| 65 | |
| 66 | ## References |
| 67 | |
| 68 | - See [`references/api-reference.md`](references/api-reference.md) for the ELF analyzer. |
| 69 | - ELF/System V ABI spec and pyelftools (linked in frontmatter). |