Difficulty: Beginner

Module 3: Project Anatomy

Every file, every folder, and why it exists.

Directory Structure

File TreeStardust/
├── Makefile              # Build system (MinGW cross-compilation)
├── CMakeLists.txt        # Alt build for development/debugging
├── README.md
├── bin/
│   └── obj/              # Compiled object files
├── include/
│   ├── common.h          # Master header, instance class, symbol<T>
│   ├── constexpr.h       # Compile-time DJB2 hashing
│   ├── macros.h          # D_API, G_SYM, RESOLVE_IMPORT macros
│   ├── memory.h          # zero(), copy(), compare()
│   ├── native.h          # Windows NT structures (22,000+ lines)
│   └── resolve.h         # API/module resolution declarations
├── scripts/
│   └── linker.ld         # Custom section ordering
├── src/
│   ├── main.cc           # Entry point + implant logic
│   ├── resolve.cc        # PEB walking + export table parsing
│   └── asm/
│       ├── entry.x64.asm # x64 entry point + RipStart
│       ├── entry.x86.asm # x86 entry point + RipStart
│       ├── utils.x64.asm # x64 RipData (data section locator)
│       └── utils.x86.asm # x86 RipData
├── test/
│   └── stomper.cc        # Module stomping injection tester
└── static/
    └── *.png             # Demo screenshots

File Dependency Graph

How Files Connect

main.cc — includes common.h, constexpr.h, resolve.h
↓ calls entry() from
entry.x64.asm / entry.x86.asm — stardust() entry, RipStart()
↓ main.cc uses APIs resolved by
resolve.cc — module() walks PEB, _api() walks exports
↓ string addresses found via
utils.x64.asm / utils.x86.asm — RipData()
↓ all section ordering controlled by
scripts/linker.ld — .text$A, .text$B, .rdata, .text$C

Build Pipeline

The Makefile orchestrates a four-step build process using a MinGW cross-compilation toolchain:

Makefile - Build Steps (Simplified)# 1. Assemble entry points and utilities for both architectures
#    (The assembler used depends on the toolchain - may be GAS or NASM)
assemble src/asm/entry.x64.asm -> bin/obj/entry.x64.obj
assemble src/asm/utils.x64.asm -> bin/obj/utils.x64.obj

# 2. Compile C++ sources with MinGW cross-compilation toolchain
compile src/main.cc    -> bin/obj/main.x64.obj    $CFLAGS
compile src/resolve.cc -> bin/obj/resolve.x64.obj $CFLAGS

# 3. Link everything with custom linker script
link bin/obj/*.x64.obj -> bin/stardust.x64.exe  -Tscripts/linker.ld

# 4. Extract .text section as raw shellcode
objcopy --dump-section .text=bin/stardust.x64.bin bin/stardust.x64.exe

# 5. Delete the intermediate PE (we only need the .bin)
rm bin/stardust.x64.exe

Key Compiler Flags

FlagPurpose
-target x86_64-w64-mingw32Cross-compile for Windows x64 via MinGW
-OsOptimize for size
-nostdlibNo C/C++ standard library
-fno-exceptionsDisable C++ exceptions
-fPICPosition-independent code
-masm=intelUse Intel assembly syntax
-mno-sseDisable SSE instructions for compatibility
-fms-extensionsMicrosoft extensions (SAL annotations, etc.)
-Wl,-Tscripts/linker.ldCustom linker script for section layout

MinGW Toolchain Note

Both Stardust and AceLdr use MinGW-based cross-compilation toolchains to produce Windows PE binaries from a Linux build environment. AceLdr uses x86_64-w64-mingw32-gcc (GCC-based). Stardust also targets x86_64-w64-mingw32 but the exact compiler frontend (Clang vs GCC) may vary by version or fork. The key difference is the linker script and objcopy extraction step that turns the PE into raw shellcode.

Pop Quiz: Project Structure

Q1: How is the final shellcode extracted from the compiled PE?

Stardust uses objcopy --dump-section .text=output.bin to extract just the .text section from the compiled PE. This is different from AceLdr which used a Python script with an "ACELDR" end marker. The objcopy approach is cleaner since the linker script already ensures everything needed is in .text.

Q2: How many C++ source files does Stardust have?

Stardust is remarkably minimal: just main.cc (entry point + implant logic) and resolve.cc (PEB walking + export parsing). Everything else is in headers or assembly files. This minimalism is key to the tiny binary size.