Module 10: Full Chain & Extending Stardust
Putting it all together, and building on top of the template.
The Big Picture
You've now studied every major subsystem of Stardust individually. This final module connects them into a complete execution chain, shows you how to extend the template with new capabilities, and provides a comprehensive comparison with AceLdr.
Complete Execution Chain
From source code to running implant, Stardust's lifecycle has four phases:
Stardust: 4-Phase Execution Chain
Phase 1: Build
(.text$A, $B, .rdata*, $C)
Phase 2: Injection (Loader-Side)
DONT_RESOLVE_DLL_REFERENCES
(Module stomping shown here; any injection technique works)
Phase 3: Initialization (Inside Stardust)
(.text$A, byte 0)
resolve::module()
ntdll, kernel32, ...
Phase 4: Implant Logic
How to Extend Stardust
Stardust is designed as a template, not a finished product. Here's how to add new capabilities.
Adding New API Declarations
To call a new Windows API, you need two things in common.h:
C++// Step 1: Add a D_API declaration to your API struct
// D_API defines the function pointer type and its DJB2 hash
// Example: adding WSAStartup from ws2_32.dll
// In the ws2_32 API struct:
struct ws2_32_apis {
D_API( void*, base ); // Index 0: module base
D_API( int, WSAStartup ); // Index 1: function pointer
D_API( SOCKET, WSASocketW ); // Index 2: function pointer
D_API( int, connect ); // Index 3: function pointer
};
// Step 2: Add the RESOLVE_TYPE for the module hash
// This associates the struct with the DJB2 hash of "ws2_32.dll"
RESOLVE_TYPE( ws2_32_apis, H_MODULE_WS2_32 );
Using New APIs in start()
Once declared, resolve and call the APIs in the start() function:
C++// In start() - resolve all ws2_32 APIs in one call
ws2_32_apis ws2;
RESOLVE_IMPORT( ws2, H_MODULE_WS2_32 );
// Now call them like normal function pointers
WSADATA wsaData;
ws2.WSAStartup( MAKEWORD(2, 2), &wsaData );
SOCKET sock = ws2.WSASocketW(
AF_INET, SOCK_STREAM, IPPROTO_TCP,
NULL, 0, 0
);
// Use symbol<T> for any string data you need
auto target = G_SYM( target_host ); // position-independent string access
Adding a New Module (DLL)
To resolve APIs from a DLL that Stardust doesn't already use (e.g., ws2_32.dll for networking):
- Add the module hash: Define
H_MODULE_WS2_32as the DJB2 hash of the string "ws2_32.dll" in your hash constants. - Create the API struct: Define a struct with
D_APIentries for each function you need (as shown above). - Add RESOLVE_TYPE: Associate the struct with the module hash.
- Resolve in start(): Call
RESOLVE_IMPORTwith your struct and module hash.
Remember the Rules
Every string you use must go through symbol<T> or G_SYM for position-independent access. Every API call must go through the resolution system. No direct string literals, no import table — these are the constraints of PIC shellcode.
AceLdr vs Stardust: Final Comparison
| Feature | AceLdr | Stardust |
|---|---|---|
| Purpose | Cobalt Strike UDRL (loads Beacon DLL reflectively) | Standalone implant template (shellcode framework) |
| Language | C with assembly | Modern C++ with assembly |
| Compiler | MinGW toolchain | MinGW toolchain |
| Hash Algorithm | DJB2 | DJB2 |
| PE in Memory | Yes (loads Beacon DLL) | No (pure shellcode, no PE) |
| Sleep Evasion | Yes (FOLIAGE sleep mask) | No (template only, no sleep loop) |
| Return Address Spoofing | Yes (JMP RBX gadget) | No |
| Heap Redirection | Yes (private heap + hooks) | No |
| x86 Support | No (x64 only) | No (x64 only) |
| Test Harness | Cobalt Strike integration | stomper.cc (module stomping demo) |
| Base Size (x64) | ~8–12 KB (loader + hooks + sleep chain) | ~2–4 KB (minimal template) |
The Key Difference
AceLdr is a complete loader with built-in evasion (sleep masking, heap redirection, return address spoofing). Stardust is a minimal template — it provides the scaffolding (PIC, API resolution, section layout) and expects you to build your implant logic on top. Stardust doesn't include sleep evasion, heap redirection, or return address spoofing because those are features you would add yourself based on your operational needs.
References & Further Study
Project Links
- Stardust Repository — The source code and build system for the Stardust implant template
- Stardust Blog Post — The author's walkthrough explaining design decisions and implementation details
Related Projects
- AceLdr — Cobalt Strike UDRL with FOLIAGE sleep mask (covered in the companion course)
- TitanLdr — Another reflective loader with similar evasion capabilities
- Havoc Framework — C2 framework that implements concepts similar to Stardust's shellcode approach
- ShellcodeTemplate — Alternative shellcode templates for comparison
Topics for Further Study
- Sleep evasion techniques — FOLIAGE, Ekko, Zilean patterns for encrypting shellcode during sleep
- Syscall stubs — Direct and indirect syscalls to bypass userland hooks (SysWhispers, HellsGate)
- ETW patching — Disabling Event Tracing for Windows to reduce telemetry
- AMSI bypass — Preventing the Antimalware Scan Interface from inspecting in-memory content
- Custom C2 protocols — Building communication channels with DNS, HTTP/S, or named pipes
- Process injection techniques — Beyond module stomping: process hollowing, thread hijacking, APC injection
Final Knowledge Check
Q1: What is the correct initialization order inside Stardust after RipStart executes?
Q2: To add a new API from a new DLL, which files/locations need changes?
Q3: Which of the following does Stardust NOT include, compared to AceLdr?
Q4: Approximately how large is the base Stardust x64 shellcode (before adding custom logic)?
Course Complete!
You've completed all 10 modules of the Stardust Deep Dive.
You now understand: position-independent code, compile-time hashing with DJB2, PEB walking and API resolution, the symbol<T> template for string access, linker scripts and section layout, module stomping as an injection technique, and how to extend the template with new capabilities.
Go build something.