cybersecurity · intermediate · ~15 min · safe pentest lab

Count global symbols in an ELF .symtab buffer

Strided binary walk with a bitwise nibble extraction.

Challenge

Your job

Implement:

#include <stdint.h>
#include <stddef.h>
int count_global_symbols(const uint8_t *buf, size_t n);

Each Elf64_Sym is 24 bytes. The binding lives in the top 4 bits of st_info, which is at offset 4 inside each entry. Binding 1 = GLOBAL.

Return:

  • the count of entries with (st_info >> 4) == 1 on success
  • 0 if buf == NULL && n == 0 (empty)
  • -1 if buf == NULL && n > 0 (corrupt)
  • -1 if n % 24 != 0 (corrupt)

Hints

  1. (concept) No struct cast. Read buf[i*24 + 4] directly.
  2. (common bug) Confusing the binding (top nibble) with the type (low nibble).
  3. (direction) Loop for (i = 0; i < n / 24; ++i).

Why this matters

The symbol table is the first place a reverse-engineer looks. A counter of global symbols is a one-glance signal of how stripped a binary is.

Input format

A const byte buffer + its length in bytes.

Output format

Non-negative count, or -1 on corruption / invalid input.

Constraints

No alignment-unsafe casts. n must be a multiple of 24.

Starter code

#include <stdint.h>
#include <stddef.h>
int count_global_symbols(const uint8_t *buf, size_t n) {
    /* TODO */
    (void)buf; (void)n;
    return -1;
}

Common mistakes

Confusing binding and type. Forgetting the n % 24 check. Casting (Elf64_Sym *)buf and tripping on alignment.

Edge cases to handle

Empty input. Single entry. All entries WEAK.

Complexity

O(n) per byte; O(n/24) per entry.

Background lessons

Up next

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.