mirror of
https://github.com/licitrasimone/CrystalSliver
synced 2026-06-21 13:55:58 +00:00
docs: update for Initialize export, evasion fixes, and in-memory loading model
- TOOLCHAIN.md §3c: crystal-loader now ~42 KB, exports Initialize, RW→RX, -s + --gc-sections flags, no identifying strings - TOOLCHAIN.md §3d: crystal-exec now ~75 KB, gen_pico_header.py replaces xxd, XOR-encrypted embedded PICO, same evasion properties as §3c - RUNBOOK.md §1.1: correct DLL sizes (42/75 KB) - RUNBOOK.md §3: add Defender surface note — DLLs load in-memory via Sliver, PICO file from upload IS on disk and visible to scanner - RUNBOOK.md §4: note crystal-exec DLL is in-memory, PICO XOR-encrypted at build - README.md: fix RWX→RW+RX description, update verified table sizes/export, fix default-jdk → openjdk-17-jdk in quick build Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -64,7 +64,7 @@ Pass runtime args without a rebuild by appending them after `|`:
|
||||
sliver > crystal --payload C:/path/file.pico.bin|args here
|
||||
```
|
||||
|
||||
The `crystal-loader.x64.dll` is a Sliver DLL Extension that allocates RWX memory, loads the PICO blob, and jumps to the Crystal Palace entrypoint. Paths use forward slashes. Arg format is `type:string` (not BOF binary).
|
||||
The `crystal-loader.x64.dll` is a Sliver DLL Extension that reads the PICO blob from disk into a `VirtualAlloc(RW)` region, flips it to RX with `VirtualProtect`, and jumps to the Crystal Palace entrypoint. No `PAGE_EXECUTE_READWRITE` mapping is ever held. Paths use forward slashes. Arg format is `type:string` (not BOF binary). The DLL is loaded in-memory by Sliver — it is not written as a file to the target disk.
|
||||
|
||||
### C — Built-in shell execution via Crystal Palace
|
||||
|
||||
@@ -108,7 +108,7 @@ docs/
|
||||
|
||||
```bash
|
||||
# 1. Toolchain
|
||||
sudo apt install -y mingw-w64 nasm default-jdk make zip git curl
|
||||
sudo apt install -y mingw-w64 nasm openjdk-17-jdk make zip git curl
|
||||
|
||||
# 2. Crystal Palace dist (BSD-3-Clause, Raphael Mudge)
|
||||
mkdir -p external/crystalpalace
|
||||
@@ -154,7 +154,7 @@ See `docs/RUNBOOK.md` for the full operator procedure (Sliver install, listener
|
||||
| Crystal Palace CLI verified | OK | `./link <spec> <dll> <out.bin> [%KEY=value]` — positional, documented in `dist/README` |
|
||||
| End-to-end PICO build (Use case A) | OK | 117 KB PICO produced from test DLL |
|
||||
| End-to-end PICO build (Use case B) | OK | 111 KB PICO produced via `postex-loader/loader.spec` |
|
||||
| Sliver Extension wrapper DLL builds | OK | `crystal-loader.x64.dll` ~232 KB, `crystal-exec.x64.dll` ~328 KB — both PE32+ exporting `go` symbol |
|
||||
| Sliver Extension wrapper DLL builds | OK | `crystal-loader.x64.dll` ~42 KB, `crystal-exec.x64.dll` ~75 KB — both PE32+ exporting `Initialize` symbol; no RWX; stripped |
|
||||
| Extension tarball packs correctly | OK | 37 KB tarball validated with `tar -tzf` |
|
||||
| Custom stager build (two-file delivery) | OK | `bundle-stager.sh` → `csvchelper.exe` (17 KB, entropy 4.784) + `payload.dat` (AES-256-CBC) |
|
||||
| Runtime execution on Windows (Use case A) | OK | Sliver session established on Windows 10 x64 FLARE-VM; stager passes Defender (Wacatac.B!ml + ZomBytes.B) |
|
||||
|
||||
+8
-2
@@ -115,8 +115,8 @@ ls -la build/
|
||||
|
||||
Expected files after the above:
|
||||
|
||||
- `crystal-loader.x64.dll` (~232 KB, in `sliver-glue/` parent)
|
||||
- `crystal-exec.x64.dll` (~328 KB, in `sliver-glue/` parent)
|
||||
- `crystal-loader.x64.dll` (~42 KB, in `sliver-glue/` parent)
|
||||
- `crystal-exec.x64.dll` (~75 KB, in `sliver-glue/` parent)
|
||||
- `build/smoketest.bin` (3 bytes: `31 c0 c3` = `xor eax,eax; ret`)
|
||||
- `build/crystal-loader-0.1.0.tar.gz` (~37 KB)
|
||||
|
||||
@@ -295,6 +295,10 @@ The extension tarball `crystal-kit-sliver/sliver-glue/build/crystal-loader-0.1.0
|
||||
- `crystal-loader.x64.dll` — provides the `crystal` command
|
||||
- `crystal-exec.x64.dll` — provides the `crystal-exec` command (see Phase 4)
|
||||
|
||||
> **Defender surface:** the extension DLLs (`crystal-loader.x64.dll`, `crystal-exec.x64.dll`) are loaded **in-memory** by Sliver's extension system — they are sent over the C2 channel and mapped directly into the implant process. They are never written as files to the target disk and are not visible to Defender's on-access file scanner.
|
||||
>
|
||||
> The **PICO file** you upload in step 3.4 (`upload ... C:/Windows/Temp/mytool.bin`) **does** land on disk and will be scanned by Defender on write. Keep PICO files small, avoid common shellcode patterns at offset 0 (Crystal Palace's XOR mask helps here), and delete the file after execution (step 5 cleanup).
|
||||
|
||||
### 3.1 Install the extension (one-time per session)
|
||||
|
||||
```
|
||||
@@ -357,6 +361,8 @@ If the DLL calls `BeaconPrintf` or `BeaconOutput`, the output is forwarded to th
|
||||
|
||||
The `crystal-exec` command runs an arbitrary shell command on the target through the Crystal Palace evasion stack. No file to upload — the executor PICO is embedded inside `crystal-exec.x64.dll` at build time. Output is returned to the Sliver console via an anonymous pipe; no disk artifact is created.
|
||||
|
||||
Like `crystal-loader.x64.dll`, the `crystal-exec.x64.dll` DLL is loaded **in-memory** by Sliver and never written to disk on the target. This means Defender's file scanner does not see it. The embedded PICO bytes are XOR-encrypted with a fresh 256-byte key at build time (`gen_pico_header.py`), so static patterns from Crystal Palace do not appear in the DLL's `.data` section.
|
||||
|
||||
### 4.1 Install the extension (same tarball as Phase 3)
|
||||
|
||||
If not already installed:
|
||||
|
||||
+17
-9
@@ -88,14 +88,20 @@ Example invocation:
|
||||
|
||||
```makefile
|
||||
CC_64 := x86_64-w64-mingw32-gcc
|
||||
CFLAGS := -Wall -Os -DBUILD_DLL
|
||||
LDFLAGS := -shared -Wl,--subsystem,windows
|
||||
CFLAGS := -Wall -Os -DBUILD_DLL -ffunction-sections -fdata-sections
|
||||
LDFLAGS := -shared -Wl,--subsystem,windows -s -Wl,--gc-sections
|
||||
|
||||
# Produces ../crystal-loader.x64.dll
|
||||
$(CC_64) $(CFLAGS) crystal-loader.c beacon_compatibility.c -o ../crystal-loader.x64.dll $(LDFLAGS)
|
||||
```
|
||||
|
||||
**Verified output:** ~232 KB, PE32+ x86-64, exports symbol `go`.
|
||||
Key evasion properties:
|
||||
- Exports `Initialize` (not `go` — the `go` export name is the primary `Win64/MeterBof.A` static signature)
|
||||
- No `[crystal-loader]` / `PICO` / tool-identifying strings in `.rdata`
|
||||
- `VirtualAlloc(RW)` + `VirtualProtect(RX)` — no `PAGE_EXECUTE_READWRITE` mapping ever held
|
||||
- `-s` strips all symbol table entries; `--gc-sections` removes dead code
|
||||
|
||||
**Verified output:** ~42 KB, PE32+ x86-64, exports symbol `Initialize`.
|
||||
|
||||
A smoke test shellcode (`smoketest.asm`) builds in parallel:
|
||||
|
||||
@@ -119,13 +125,14 @@ Step 1: crystalexec.c → crystalexec.dll
|
||||
Step 2: crystalexec.dll → crystalexec.pico.bin (Crystal Palace wrap)
|
||||
../generate.sh crystalexec.dll "" crystalexec.pico.bin
|
||||
|
||||
Step 3: crystalexec.pico.bin → crystalexec_pico.h (embed as C byte array)
|
||||
xxd -i crystalexec.pico.bin | \
|
||||
sed 's/unsigned char .../unsigned char crystalexec_pico/; \
|
||||
s/unsigned int .../unsigned int crystalexec_pico_len/' > crystalexec_pico.h
|
||||
Step 3: crystalexec.pico.bin → crystalexec_pico.h (XOR-encrypt + embed as C array)
|
||||
python3 gen_pico_header.py crystalexec.pico.bin crystalexec_pico.h
|
||||
Fresh random 256-byte key every build — Crystal Palace byte patterns in .data
|
||||
are obfuscated; outputs crystalexec_pico[] + crystalexec_pico_key[] arrays.
|
||||
|
||||
Step 4: crystal-exec.c + crystalexec_pico.h → ../crystal-exec.x64.dll
|
||||
x86_64-w64-mingw32-gcc -Wall -Os -DBUILD_DLL -shared -Wl,--subsystem,windows \
|
||||
x86_64-w64-mingw32-gcc -Wall -Os -DBUILD_DLL -ffunction-sections -fdata-sections \
|
||||
-shared -Wl,--subsystem,windows -s -Wl,--gc-sections \
|
||||
-o ../crystal-exec.x64.dll crystal-exec.c
|
||||
```
|
||||
|
||||
@@ -134,8 +141,9 @@ Key design constraints:
|
||||
- Use custom string helpers (`hex_parse`, `str_append`) instead of `strtoull`, `strtol`, `snprintf`
|
||||
- `crystal-exec.c` (the Sliver extension itself) may use CRT normally — it runs in the normal process context, not inside the PICO loader
|
||||
- Single callback model: all output accumulates into a heap buffer; exactly ONE `callback(buf, len)` call at the very end. Sliver extension loaders only display the first callback invocation — any subsequent calls are silently dropped.
|
||||
- Exports `Initialize` (not `go`); no `[crystal-exec]` / `PICO` strings in binary; XOR-decrypt embedded PICO at runtime into `VirtualAlloc(RW)`, then `VirtualProtect(RX)` — no `PAGE_EXECUTE_READWRITE` ever held.
|
||||
|
||||
**Verified output:** `crystal-exec.x64.dll` — ~328 KB, PE32+ x86-64, exports symbol `go`.
|
||||
**Verified output:** `crystal-exec.x64.dll` — ~75 KB, PE32+ x86-64, exports symbol `Initialize`.
|
||||
|
||||
### 3e. Custom stager — two-file delivery (Use case A Defender bypass)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user