Miscellaneous Security Concepts
What You Will Learn
- How GCC constructors run before
main() - How the C runtime initialization chain works
- What the
__attribute__((packed))directive does - How these concepts relate to exploit development
What Is It?
This topic covers low-level C and linker concepts that are important for malware analysis, binary exploitation, and reverse engineering.
Why It Matters
Understanding how programs initialize before main() is critical for:
- Reverse engineering obfuscated binaries that hide logic in constructors
- Writing shellcode that hooks into the initialization chain
- Understanding how shared library hijacking works (DLL/SO injection)
GCC Constructor Attribute
The __attribute__((constructor)) directive marks a function to run before main(). The linker places it in the .init_array section.
void __attribute__((constructor)) run_before_main() {
write(1, "hello", 6);
}
When this program runs, "hello" is printed before anything in main() executes. This is used by:
- Shared library initialization code
- Malware that hides in
.init_array - Sanitizers (ASAN, UBSAN) that need early initialization
C Runtime Initialization Chain
When a Linux ELF binary starts, execution flows:
_start
└── __libc_start_main
└── __libc_csu_init
└── iterate .init_array ← runs all constructors here
└── main()
__libc_csu_init iterates through the .init_array section, calling each function pointer. This is why constructor functions run before main().
In Reverse Engineering
When analyzing a binary, always check:
# List .init_array entries
readelf -S binary | grep init_array
objdump -d -j .init_array binary
# List all function pointers in .init_array
objdump --section=.init_array -s binary
Malware often places its real entry point in .init_array to run before any debugger breakpoints set on main.
Packed Structures
The __attribute__((packed)) directive tells GCC to use the exact size of the struct with no padding bytes between members:
struct normal {
char a; // 1 byte + 3 bytes padding
int b; // 4 bytes
}; // sizeof = 8
struct __attribute__((packed)) packed {
char a; // 1 byte (no padding)
int b; // 4 bytes
}; // sizeof = 5
This is used in:
- Network protocol parsing (packets have exact formats)
- File format parsing
- Binary protocol implementations
Unintended use of packed structs (vs. non-packed) is a source of memory corruption bugs — if you copy a packed struct’s address into a function expecting aligned access, you get an alignment fault.
Other GCC Attributes Used in Security
// Mark a function as never returning (like exit())
void __attribute__((noreturn)) fatal_error(void);
// Mark a function as deprecated
void __attribute__((deprecated)) old_func(void);
// Declare a function with specific visibility
void __attribute__((visibility("hidden"))) internal_func(void);
// Enforce a specific section placement
void __attribute__((section(".text.hot"))) hot_path(void);
// Prevent inlining (useful for stack frame analysis)
void __attribute__((noinline)) do_something(void);
Sections in ELF/PE
| Section | Contents |
|---|---|
.text | Executable code |
.data | Initialized global variables |
.bss | Uninitialized global variables |
.rodata | Read-only data (string literals) |
.init_array | Function pointers called before main |
.fini_array | Function pointers called after main |
.plt | Procedure Linkage Table (dynamic symbol stubs) |
.got | Global Offset Table (dynamic symbol addresses) |