.-----.
.' - - '.
/ .-. .-. \
| | | | | |
\ \o/ \o/ /
_/ ^ \_
| \ '---' / | ▗▄▄▖▗▖ ▗▖ ▗▄▖ ▗▄▄▖▗▄▄▄▖▗▖ ▗▖
/ /`--. .--`\ \ ▐▌ ▐▌ ▐▌▐▌ ▐▌▐▌ █ ▝▚▞▘
/ /'---` `---'\ \ ▐▌▝▜▌▐▛▀▜▌▐▌ ▐▌ ▝▀▚▖ █ ▐▌
'.__. .__.' ▝▚▄▞▘▐▌ ▐▌▝▚▄▞▘▗▄▄▞▘ █ ▐▌
`| |`
| \
\ '--.
'. `\
`'---. |
,__) /
`..'
$ git clone https://github.com/aniko33/GhostyEncryptor
$ cd src
$ make ghostyencryptor
Now the executable ghostyencryptor is the project root
Usage: ./ghostyencryptor <shellcode.bin> [-key 0xFF] [-out output.bin] [-verify]
$ ./ghostyencryptor shellcode.bin
[i] KEY = 0xBC <--- GENERATED KEY!
[i] Size of shellcode 201798
[i] Original Entropy 6.046684
[+] Encryption...
[+] Compression...
[+] Nibble encoding...
[+] YEnc Encoding...
[+] Entropy 3.848014
[i] Size of shellcode 791272
[i] Shellcode output shellcode.out
$ ./ghostyencryptor shellcode.bin -key 0xAA
[i] KEY = 0xAA
[i] Size of shellcode 201798
[i] Original Entropy 6.046684
[+] Encryption...
[+] Compression...
[+] Nibble encoding...
[+] YEnc Encoding...
[+] Entropy 3.843809
[i] Size of shellcode 792132
[i] Shellcode output shellcode.out
$ ./ghostyencryptor shellcode.bin -key 0xFF -verify -out test.bin
[i] KEY = 0xFF
[i] Size of shellcode 201798
[i] Original Entropy 6.046684
[+] Encryption...
[+] Compression...
[+] Nibble encoding...
[+] YEnc Encoding...
[+] Verifying if the shellcode is valid...
[+] Entropy 3.841705
[i] Size of shellcode 798764
[i] Shellcode output test.bin
Into decryptor/ there are a fully function example of decryptor written in C and can be ported in every programming language.
$ mkdir -p decryptor/build
$ make decryptor.exe
Note
To change compiler: set environment key CC
$ CC=customCompiler make decryptor.exe
$ decryptor.exe <shellcode.bin> <key>
The decryptor will save the shellcode output to test.out
The decryptor needs to perform the following steps:
shellcodeStep1 = YEncDecode(shellcodeEncrypted)
shellcodeStep2 = NibbleDecode(shellcodeStep1)
shellcodeStep3 = RLEDecompress(shellcodeStep2)
decrypted = XorEncryptDecrypt(shellcodeStep3, key)yEnc is a simple binary-to-text encoding used for Usenet/text-only transports. It maps raw bytes to mostly printable characters with low overhead and a small escape mechanism.
- Take a byte, e.g.
0xF0. - Compute:
enc = (b + 42) % 256. - If
encis one of the reserved bytes{ 0x00, 0x0A, 0x0D, 0x3D }then:- Output the escape byte
'='with(enc + 64) % 256.
- Output the escape byte
- Otherwise output
encas a single byte
- Read bytes left-to-right.
- If byte is
'='(0x3D):- Read next byte
enc = (t - 64 + 256) % 256- If no next byte throw an error: truncated escape sequence.
- Else: recover original so
b = (byte - 42 + 256) % 256 - Output the decoded byte
- Escape byte:
=(0x3D) - Bytes that must be escaped (after adding 42):
0x00,0x0A(LF),0x0D(CR),0x3D(=) - Escaped transmitted value:
(enc + 64) % 256 - Decoder reverses by subtracting 64 (mod 256)
Nibble encoding is a method to encode the data in simple way with overhead of 1 byte to 2 bytes
- Take a byte like:
11110000b(1are first 4 bits and0are the last 4 bit) - split it in H (high) and L (low).
-
H = 1111 L = 0000
-
- Increase H by
0x40so1001111b - Increase L by
0x50so1010000b - Return the value as 2 bytes separated:
[H, L]so[1001111b, 1010000b]
- Take bytes like:
[1001111b, 1010000b]- The first one is the high, and the second is the low - Decrease H by
0x40so1111b - Decrease L by
0x50so0000b - Return the recomposed byte:
((high & 0xF) << 4) | (low & 0xF)so11110000b
Simple RLE encodes runs of repeated bytes as pairs (count, byte). Overhead is 1 extra byte per run (count) — encoded stream is: [count, value, count, value, ...]. Counts are single bytes (0–255), so maximum run length is 255.
- Start with an input byte buffer.
- Track the current run value (
prev) and a run lengthcount(byte). - Iterate input bytes:
- If the next byte equals
prevandcount < 255, incrementcount. - Otherwise, write the run as two bytes:
[count, prev], then setprevto the new byte andcount = 1.
- If the next byte equals
- After the loop, write the final run
[count, prev]. - Return the concatenated output bytes.
Note
- The first input byte initializes
prevandcount = 1. - A run of a single byte becomes
[1, value]. - Large runs are split into multiple runs when longer than 255.
- Read the compressed buffer two bytes at a time: first byte is
count, second isvalue. - For each pair, append
countcopies ofvalueto the output. - Stop when you've consumed all pairs. If the compressed buffer length is odd, it's malformed.
Input: [0xAA, 0xAA, 0xAA, 0xBB]
Encoded: [3, 0xAA, 1, 0xBB]
Decoded: [0xAA, 0xAA, 0xAA, 0xBB]
XOR stream here means each byte is XORed with a single-byte key that increments after every byte. The operation is symmetric: the same function encrypts and decrypts.
- Take input bytes and an initial single-byte key (0–255).
- For each input byte
b:- Compute out =
b XOR keysob ^ key. - Append out to output.
- Increment key:
key = (key + 1) & 0xFF(wraps at 255→0).
- Compute out =
- Return the output bytes.
Input: [0x10, 0x20, 0x30], key = 0x01
Keystream: [0x01, 0x02, 0x03]
Encrypted: [0x11, 0x22, 0x33]
Go to BENCHMARK.md
Important
I'm very lazy when it comes to writing good documentation, so "How to: X" may be documented incorrectly because I used AI (but i review it first).