July 30, 2026
Crystal Palace The Linker: Changing How You Build Loaders
There’s a moment every offensive developer hits where writing position-independent code stops being interesting and starts being a tax. You…

By S12 - 0x12Dark Development
4 min read
There's a moment every offensive developer hits where writing position-independent code stops being interesting and starts being a tax. You know exactly what your loader needs to do. You understand the logic. But before you can write a single line of actual capability, you're fighting your own toolchain, stripping strings character by character, banishing global variables, replacing every Win32 call with a PEB walk, and praying the compiler doesn't decide to generate a jump table somewhere that will break everything at runtime. And then you do it again for the next technique. And the one after that
Crystal Palace exists because that tax is a distraction. It's a linker and linker script language built specifically for offensive development, written by Raphael Mudge, the same person who built Cobalt Strike, and its core premise is simple: you should be spending your time building capability, not fighting relocations
This post isn't a tutorial. It's an explanation of what Crystal Palace actually is, how it thinks about the problem, and why it matters. The next ones in this Crystal Palace list will be directly building some payloads with it
https://medium.com/@s12deff/list/crystal-palace-78fc7f8f4c2d
Want to go deeper into Windows offensive development?
Video-based courses from beginner to advanced, and text-based modules (mini courses) with new releases constantly. Plus a technique database with 100+ real techniques updated weekly, and custom C2 agents and consulting for teams.
0x12 Dark Development Skip to content Join our offensive development courses and modules, and explore the techniques database with 100+ real…
The Problem with Position Independent Code
Before talking about what Crystal Palace does, it helps to be honest about why PIC development is painful in the first place.
When you compile a normal Windows program, the operating system's loader does a tremendous amount of invisible work on your behalf. It reads your PE headers, maps your sections into memory, resolves your imports by walking the export address tables of every DLL you depend on, patches your relocations, and then hands execution to your entry point. All of that happens before your first line of code runs
Position independent code throws all of that away. There's no PE header. There's no loader. There's no IAT. You're a raw blob of bytes that someone drops into memory and jumps to. When that blob tries to reference a string constant it put in .rdata, the address it expects no longer exists. When it tries to call VirtualAlloc through an import table entry, that table doesn't exist either. Every assumption the compiler made about how your program would be set up has been violated
The traditional response is to rewrite everything that creates those assumptions. Strings become character arrays built on the stack, byte by byte. Global variables get eliminated or replaced with specific tricks. Every Win32 API call becomes a manual PEB walk that finds the module, hashes the export names, and returns a function pointer. Switch statements get replaced with chains of if else because switches compile to jump tables, and jump tables are relocations
This works. It produces code that runs as a raw blob. But it's also genuinely hostile to write and maintain
What Crystal Palace Is
Crystal Palace is a post compilation linker. It doesn't compile anything. You write your C code normally, compile it to a COFF object file with MinGW (or other, is compiler agnostic), and then hand it to Crystal Palace, which transforms it into a working PIC blob
This distinction (linker, not compiler) matters more than it might seem. Because Crystal Palace operates on already compiled object files, it can work with code that was written without any knowledge of Crystal Palace at all. A function from a third party library, a technique module someone else built, a component you wrote six months ago, all of it becomes a candidate for inclusion in your PIC output as long as it compiles to a valid COFF.
The transformation Crystal Palace applies to those COFF files is what makes the magic happen. It takes the .text and .rdata sections and flattens them into a single contiguous region. It patches every relocation it can resolve statically But Crystal Palace goes further than just resolving relocations. It handles the two other major problems: API resolution and global variables
DFR
The way Crystal Palace handles Win32 API calls is through a system called Dynamic Function Resolution, or DFR. Instead of writing your own PEB walk for every loader you build, you declare your API calls using a MODULE$Function naming convention and let Crystal Palace handle the rest
When Crystal Palace processes your object file and encounters a reference to KERNEL32$VirtualAlloc, it calculates the ROR13 hash of the module name and the function name, and inserts a small stub that, at runtime, calls your resolver function with those two hashes as arguments. Your resolver (which can be as simple as a PEB walk that compares hashes against the export tables of loaded modules) returns the actual function pointer, and execution continues
Making Every Build Different
Even a technically sound loader fails eventually if it produces the same bytes every time. Static signatures are the lowest effort detection mechanism available to defenders and they scale, a signature written against one sample works against every sample you produce, forever.
Crystal Palace has a builtin answer to this: link time binary transformations that ensure every build is structurally unique.
+mutate rewrites instruction sequences with equivalent alternatives, +regdance shuffles register assignments, +blockparty randomizes basic block order within functions, and +disco randomizes function order in the output.
The magic command extends this to constants (memory protection flags, allocation sizes, anything that could anchor a signature) substituting them with random values from a pool you define. None of this changes what the program does. The bytes that represent it are different every single time
Crystal Palace can also generate a YARA rule from its own output and immediately check whether that output matches it. If a stable pattern survived the mutations, the build fails. You fix it and rebuild. You never ship something that would trigger a signature you could have caught yourself at compile time
Installation
Now its time to install the tool before we start with the practical posts:
Basically, runs in Linux or WSL. Here you can download the tool:
https://tradecraftgarden.org/crystalpalace.html
And here the documentation to install and use it:
https://tradecraftgarden.org/docs.html
Conclusions
Crystal Palace shifts the complexity of PIC development from the developer to the linker. Instead of rewriting code around position independent constraints, you can focus on building capabilities. In the next posts, we'll move from theory to practice by building real loaders with it
📌 Follow me: 🐦 X | 💬 Discord Server | 📸 Instagram | Newsletter | YouTube
S12.