Safe Penetration Testing Labs · intermediate · ~15 min
Walk an ELF64 symbol table and count the entries with global binding.
Iterate the buffer 24 bytes at a time, read st_info at offset 4, count entries where (st_info >> 4) == 1.
Symbol counts are the first signal you get from a stripped vs. un-stripped binary.
Every reverse-engineering tool — nm, objdump, readelf, Ghidra,
radare2 — starts by reading the symbol table out of an ELF binary.
The on-disk layout is fixed: 24-byte entries, the binding lives in
the top nibble of st_info.
We don't need a full ELF reader to make use of .symtab — we just
need to count entries with a property.
offset size field
0 4 st_name
4 1 st_info <- top 4 bits = binding, low 4 bits = type
5 1 st_other
6 2 st_shndx
8 8 st_value
16 8 st_size
Bindings:
0 LOCAL1 GLOBAL ← we count these2 WEAKSo binding = st_info >> 4.
Implement int count_global_symbols(const uint8_t *buf, size_t n)
where buf is the raw .symtab bytes and n is its length. Return
the number of GLOBAL-binding entries, or -1 if n is not a
multiple of 24 (an incomplete entry is a corrupt symtab).
NULL buf with n == 0 → return 0 (empty is fine).
NULL buf with n > 0 → return -1.
n must be a multiple of 24.struct * pointer cast — alignment-unsafe on some
hosts. Just index buf[i*24 + 4]..strtab here..rela.dyn is a separate module.24-byte stride. High nibble of byte 4. Count when it equals 1.