LZSS Payload Decompression
What It Does
LZSS (Lempel-Ziv-Storer-Szymanski) is a sliding-window dictionary compressor used by the SilverFox/ValleyRAT cluster to hide its second-stage payload inside the PE. At runtime, a small decompressor stub extracts the payload into newly allocated executable memory before injecting it into a suspended child process.
Detection / Fingerprint
- Embedded payload compressed with a 4096-byte window (12-bit offset mask
0xfff). - Decompressor stub contains
and r8d, 0xffffollowed byshr eax, 0xc(or equivalent) to split control tokens into offset and length fields. - Decompressed stage is immediately followed by process-injection API calls:
NtAllocateVirtualMemory,NtWriteVirtualMemory. - Compressed entropy is typically 5.5–6.5; decompressed stage is a valid PE/DLL with entropy ~6.0–7.0.
Implementation Patterns
- Control word format: 16-bit token where the low 12 bits are the back-reference offset and the high 4 bits encode match length (bias +3).
- If the match-length bit is zero, a literal byte is copied directly.
- Large copies are accelerated with SSE
xmmwordmoves via a helper likefcn.140006300(16/32/64-byte alignment branches).
Reproduce on Your Own VMs
- Compress a second-stage PE with any LZSS encoder using a 4096-byte window.
- Embed the raw compressed bytes as a
.rdataor.rsrcbyte array. - Implement a decoder loop:
uint16_t token = *(uint16_t *)src; uint16_t offset = token & 0xfff; uint8_t len = (token >> 12) + 3; if (len == 3) { *dst++ = *src++; } else { memcpy(dst, dst - offset, len); dst += len; } - Allocate executable memory (
VirtualAlloc/NtAllocateVirtualMemory) and copy the decompressed stage. - Inject into a suspended child via
CreateProcessW+NtWriteVirtualMemory.
Defensive Countermeasures
- Memory scanners should flag
and [reg], 0xfffpatterns near allocation APIs. - Behavioral detection: large
NtWriteVirtualMemoryto a recently created suspended process.
Related
- Observed in: silverfox
- Related technique: rc4-in-place-section-decryption