$ cat eba_ELF_Binaries_Analyzer_2.txt
eba — ELF Binaries Analyzer
Part 2: DT_NEEDED, .dynsym and the Dynamic Linker
Introduction
In Part 1, we looked at what eba does and why it exists.
In this article, we go deeper and answer the more interesting question:
How does eba extract dynamic linking information from an ELF binary?
We will dissect:
- the dynamic segment (PT_DYNAMIC)
- DT_NEEDED entries
- the dynamic symbol table (.dynsym)
- the role of PLT and GOT
All examples are based on real code used inside eba.
The Dynamic Linker in a Nutshell
When you execute a dynamically linked ELF binary:
- the kernel maps the ELF into memory
- control is transferred to the dynamic linker (ld-linux)
- the linker:
- loads shared libraries
- resolves symbols
- patches the GOT
- only then does execution reach main()
Everything the linker needs lives in the PT_DYNAMIC segment.
PT_DYNAMIC — The Heart of Runtime Metadata
The dynamic segment is referenced via the program header table.
eba locates it by scanning all program headers:
for (int i = 0; i < ehdr.e_phnum; i++) {
if (phdrs[i].p_type == PT_DYNAMIC) {
dyn_offset = phdrs[i].p_offset;
dyn_size = phdrs[i].p_filesz;
break;
}
}
This segment contains an array of Elf64_Dyn entries:
typedef struct {
Elf64_Sxword d_tag;
union {
Elf64_Xword d_val;
Elf64_Addr d_ptr;
} d_un;
} Elf64_Dyn;
Each entry answers a question the linker might ask.
DT_NEEDED — Which Libraries Are Required?
DT_NEEDED entries specify shared library dependencies.
Example:
- DT_NEEDED → libc.so.6
- DT_NEEDED → libcrypto.so.3
eba extracts them by:
- locating DT_STRTAB
- mapping virtual addresses to file offsets
- reading the string table
- resolving offsets
if (d->d_tag == DT_NEEDED) {
printf(" %s\n", &strtab[d->d_un.d_val]);
}
Why This Matters
- unexpected libraries → suspicious
- minimal imports → shellcode-like behavior
- crypto libraries → encryption, TLS, ransomware potential
Virtual Addresses vs File Offsets
A common pitfall when parsing ELF:
DT_STRTAB does not give a file offset.
It gives a virtual address.
eba solves this by walking PT_LOAD segments:
Elf64_Off vaddr_to_offset(Elf64_Addr vaddr) {
return p_offset + (vaddr - p_vaddr);
}
This mapping step is essential for any dynamic ELF analysis.
.dynsym — The Dynamic Symbol Table
.dynsym contains symbols visible to the dynamic linker.
These include:
- imported functions
- exported APIs
- global variables
eba locates it via:
- DT_SYMTAB -> virtual address
- DT_SYMENT -> size of Elf64_Sym
Each symbol looks like this:
typedef struct {
Elf64_Word st_name;
unsigned char st_info;
Elf64_Addr st_value;
Elf64_Xword st_size;
} Elf64_Sym;
Import vs Export Detection
eba distinguishes imports from exports using:
if (sym->st_value == 0)
printf("IMPORT\n");
else
printf("EXPORT\n");
Why it works:
- imported symbols have no address yet
- exported symbols already have one
This allows instant classification without relocations.
Symbol Binding & Type
Using macros:
- ELF64_ST_BIND(st_info)
- ELF64_ST_TYPE(st_info)
eba can tell:
- GLOBAL vs LOCAL
- FUNC vs OBJECT
Example output:
printf FUNC GLOBAL IMPORT
my_api FUNC GLOBAL EXPORT
PLT — Procedure Linkage Table
The PLT is a trampoline layer.
Imported functions do not jump directly to libc.
Instead:
call printf@plt
First call:
- jumps into the dynamic linker
- resolves the symbol
- patches the GOT
Later calls:
- jump directly to the resolved address
eba does not resolve PLT stubs yet — but it detects their presence
indirectly via .dynsym imports.
GOT — Global Offset Table
The GOT holds addresses of resolved symbols.
Key properties:
- writable at runtime
- frequently targeted by exploits
- critical for understanding control flow hijacking
Future versions of eba may:
- detect GOT overwrite potential
- inspect RELRO status
Why This Matters for Security
Malware Analysis
- shellcode-style malware → no DT_NEEDED
- packers → high entropy + few imports
- stealers → libc + networking libraries
Binary Hardening
- full RELRO?
- PIE enabled?
- stripped symbols?
Dynamic metadata tells the full story.
Practical Example
$ ./eba /bin/ls
You immediately learn:
- which libraries are loaded
- which symbols are imported
- whether the binary is stripped
- how complex runtime linking is
All before opening a GUI tool.
Limitations
eba currently:
- assumes ELF64
- assumes valid layouts
- does not resolve relocations
- does not follow PLT chains
Conclusion
Understanding DT_NEEDED and .dynsym means understanding how Linux binaries actually run.
eba doesn’t hide this complexity — it exposes it.
If you understand the loader, you understand the binary.
$
cd /home/user/blog