Difficulty: Beginner

Module 2: Modern C++ for Shellcode

How Stardust abuses modern C++ features for compile-time evasion.

Wait, C++ for Shellcode?

Most shellcode is written in C or pure assembly. Using C++ sounds insane — classes, templates, virtual tables, exceptions... all that overhead. But Stardust carefully uses only the zero-cost features of modern C++. The compiler does heavy lifting at build time so the runtime binary stays tiny.

The Three Modern C++ Features That Matter

1. constexpr / consteval — Forced Compile-Time Execution

constexpr (C++14+) tells the compiler a function may run at compile time. consteval (C++20) forces it — the result must be computed at compile time. Stardust uses these features so that strings like API names are hashed during compilation and never appear in the binary:

C++ - constexpr.hnamespace expr {
    template <typename T = char>
    constexpr auto hash_string(       // constexpr = CAN run at compile time
        const T* string               // consteval would FORCE compile time (C++20)
    ) -> uint32_t {
        uint32_t hash = 5381;         // DJB2 initial value
        uint8_t  byte = 0;

        while ( *string ) {
            byte = static_cast<uint8_t>( *string++ );
            if ( byte >= 'a' ) byte -= 0x20;  // Case-insensitive (uppercase)
            hash = ( ( hash << 5 ) + hash ) + byte;  // hash * 33 + byte
        }
        return hash;
    }
}

What Happens at Build Time

What you writeauto hash = expr::hash_string( "NtAllocateVirtualMemory" );
What the compiler produces (pseudocode)auto hash = 0x1A2B3C4D;  // Just a constant integer. No string. No function call.

The string "NtAllocateVirtualMemory" exists only in your source code. It never makes it into the binary. Defenders running strings on the shellcode see nothing.

constexpr vs consteval

constexpr functions can be evaluated at compile time but may also run at runtime if called with non-constant arguments. consteval (C++20) must be evaluated at compile time — the compiler errors if it cannot. When used with constant string literals, constexpr is typically sufficient since the compiler can and does resolve it at compile time. Whether Stardust uses constexpr or consteval may depend on the version or fork, but the effect is the same: hashes are baked into the binary as constants.

2. Templates — Type-Safe API Resolution

Stardust uses templates to make API resolution type-safe. Instead of casting void* everywhere:

C++ - resolve.hnamespace resolve {
    template <typename T>
    inline auto declfn api(
        _In_ const uintptr_t module_base,
        _In_ const uintptr_t symbol_hash
    ) -> T* {
        return reinterpret_cast<T*>( _api( module_base, symbol_hash ) );
    }
}

// Usage: compiler knows the exact function signature
decltype(MessageBoxA)* msgbox = RESOLVE_API(
    reinterpret_cast<uintptr_t>(user32), MessageBoxA
);

3. decltype — Automatic Type Deduction

C++ - macros.h#define D_API( x )  decltype( x ) * x;

// Inside the instance class:
struct {
    D_API( LoadLibraryA )    // expands to: decltype(LoadLibraryA)* LoadLibraryA;
    D_API( GetProcAddress )  // expands to: decltype(GetProcAddress)* GetProcAddress;
};

decltype(LoadLibraryA) gives the compiler the exact function signature of the real Windows API. Your function pointer is automatically the right type. No manual typedef needed.

What C++ Features Stardust AVOIDS

FeatureWhy It's Banned
Exceptions (try/catch)Requires runtime support tables, huge overhead
RTTI (dynamic_cast)Type info tables bloat the binary
STL containersDepend on the C++ standard library (heap, exceptions)
Virtual functionsvtable pointers aren't position-independent
Global constructorsRequire CRT initialization that doesn't exist
SSE instructionsDisabled via -mno-sse for compatibility

The -nostdlib Flag

Stardust compiles with -nostdlib, meaning there is no C runtime, no C++ standard library. No printf, no malloc, no std::string, no new/delete. Every memory operation is done manually via memory::copy(), memory::zero(), or Windows API calls.

Pop Quiz: Modern C++ Features

Q1: What is the difference between constexpr and consteval?

constexpr functions CAN be evaluated at compile time but may also run at runtime if called with non-constant arguments. consteval functions MUST be evaluated at compile time — the compiler errors if it can't. When used with constant string literals in this context, both achieve the same goal: the string never appears in the binary.

Q2: Why does Stardust use decltype(LoadLibraryA)* LoadLibraryA;?

decltype(LoadLibraryA) resolves to the exact function signature: HMODULE(LPCSTR). The * makes it a function pointer. This means you can call it with the same parameters as the real API and the compiler will type-check everything for you. No error-prone manual typedefs.