
Codificador binário polimórfico para payloads de segurança ofensiva. Codifica shellcode com loop de feedback baseado em LFSR, injeção de instruções de lixo e ofuscação de múltiplas iterações para evadir a detecção estática.
<div align="center">
<img src="https://assets.kitploit.com/production/public/readmes/3551/71476533a52676b901aed0ae0ab78a9dd1cf687fd6360bdaad6e5998b944842f.png">
<br>
[![GitHub All Releases][release-img]][release]
[![Build][workflow-img]][workflow]
[![Issues][issues-img]][issues]
[![Crates][crates-img]][crates]
[![License: MIT][license-img]][license]
</div>
[crates]: https://crates.io/crates/sgn
[crates-img]: https://img.shields.io/crates/v/sgn
[release]: https://github.com/EgeBalci/sgn/releases
[release-img]: https://img.shields.io/github/v/release/EgeBalci/sgn
[downloads]: https://github.com/EgeBalci/sgn/releases
[downloads-img]: https://img.shields.io/github/downloads/EgeBalci/sgn/total?logo=github
[issues]: https://github.com/EgeBalci/sgn/issues
[issues-img]: https://img.shields.io/github/issues/EgeBalci/sgn?color=red
[license]: https://raw.githubusercontent.com/EgeBalci/sgn/master/LICENSE
[license-img]: https://img.shields.io/github/license/EgeBalci/sgn.svg
[google-cloud-shell]: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/EgeBalci/sgn&tutorial=README.md
[workflow-img]: https://github.com/EgeBalci/sgn/actions/workflows/main.yml/badge.svg
[workflow]: https://github.com/EgeBalci/sgn/actions/workflows/main.yml
[fe-article]: https://www.fireeye.com/blog/threat-research/2019/10/shikata-ga-nai-encoder-still-going-strong.html
[lfsr]: https://en.wikipedia.org/wiki/Linear-feedback_shift_register
SGN é um codificador binário polimórfico para fins de segurança ofensiva, como gerar payloads binários estaticamente indetectáveis. Ele usa um loop de realimentação aditiva para codificar determinadas instruções binárias, similar ao [LFSR][lfsr]. Este projeto é a reimplementação do [Shikata ga nai original](https://github.com/rapid7/metasploit-framework/blob/master/modules/encoders/x86/shikata_ga_nai.rb) em golang, com muitas melhorias.
> [!WARNING]
> O projeto foi recentemente migrado para Rust. Esta migração mantém o design e o comportamento originais, mas substitui o montador de texto [keystone](https://www.keystone-engine.org/) pelo montador puro-Rust [`iced-x86`](https://docs.rs/iced-x86), portanto **não há dependências nativas de bibliotecas** — a compilação é feita com um simples `cargo build`. Confira o branch [sgn-go](https://github.com/EgeBalci/amber/tree/sgn-go) para a versão legada em Go.
## Por quê?
Para a comunidade de segurança ofensiva, a implementação original do codificador shikata ga nai é considerada o melhor codificador de shellcode (até agora). Mas, ao longo dos anos, pesquisadores de segurança encontraram várias armadilhas na detecção estática do stub de decodificação (trabalho relacionado: [artigo da FireEye][fe-article]). A principal motivação deste projeto foi criar um codificador melhor, que codifique o binário fornecido a ponto de ser idêntico a dados totalmente aleatórios e impossível de detectar a presença de um decodificador.
- [x] Suporte a 64 bits. `Finally properly encoded x64 shellcodes !`
- [x] Novo stub de decodificação menor. `LFSR key reduced to 1 byte`
- [x] Stub codificado com esquema pseudoaleatório. `Decoder stub is also encoded with a psudo random schema`
- [x] Sem condição de loop visível. `Stub decodes itself WITHOUT using any loop conditions !!`
- [x] Ofuscação do stub de decodificação. `Random garbage instruction generator added with keystone`
- [x] Opção de registrador seguro. `Non of the registers are clobbered (optional preable, may reduce polimorphism)`
## Como funciona
Cada passagem de codificação:
1. (opcional) adiciona um sufixo de restauração de registradores (modo seguro);
2. prefixa instruções de lixo aleatórias que preservam valores;
3. cifra o payload com a cifra **ADFL** (loop de realimentação aditiva) e
prefixa um stub de decodificação sem loop que o reverte em tempo de execução;
4. a menos que `--plain` seja usado, cifra o próprio stub com uma **cifra
de esquema** aleatória por execução (`XOR/ADD/SUB/ROL/ROR/NOT` sobre DWORDs) e prefixa um
decodificador de esquema autolocalizável, para que até o decodificador pareça dados aleatórios;
5. opcionalmente, repete `--enc` vezes com novas sementes;
6. (opcional) adiciona um prefixo de salvamento de registradores (modo seguro).
## Instalação
```sh
cargo install sgn
```
Você também pode obter os binários pré-compilados [AQUI][release].
**Uso**
`-h` é bem autoexplicativo; use `-v` se quiser ver o que está acontecendo nos bastidores `( ͡° ͜ʖ ͡°)_/¯`
<p align="center">
<img src="https://assets.kitploit.com/production/public/readmes/3551/d7536cd852e99bfd9dfcfb21e7d050a763a678d5bb65a6db80e89d4c4f5a3a8b.gif">
</p>
```
__ _ __ __ _
___ / / (_) /_____ _/ /____ _ ___ ____ _ ___ ___ _(_)
(_-</ _ \/ / '_/ _ `/ __/ _ `/ / _ `/ _ `/ / _ \/ _ `/ /
/___/_//_/_/_/\_\\_,_/\__/\_,_/ \_, /\_,_/ /_//_/\_,_/_/
========[Author:-Ege-Balcı-]====/___/=======v2.0.2=========
┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ (ノ ゜Д゜)ノ ︵ 仕方がない
sgn [OPTIONS]
Options:
-i, --input <INPUT> Input binary path
-o, --out <OUT> Encoded output binary name (default: <input>.sgn)
-a, --arch <ARCH> Binary architecture (32/64) [default: 64]
-c, --enc <ENC> Number of times to encode the binary [default: 1]
-M, --max <MAX> Maximum bytes per garbage block [default: 50]
--plain Do not encode the decoder stub
--ascii Generate a fully ASCII-printable payload (slow)
-S, --safe Preserve all register values (no clobber)
--badchars <BADCHARS> Avoid these bytes, hex format (e.g. \x00\x0a)
-v, --verbose Verbose mode
-h, --help Print help
-V, --version Print version
```
Exemplo:
```sh
sgn -i shellcode.bin -o encoded.bin -a 64 --badchars '\x00\x0a\x0d'
```
## Fluxo de Execução
A imagem a seguir é um diagrama básico de fluxo de trabalho do codificador. Mas lembre-se de que os tamanhos, locais e ordens mudarão para instruções de lixo, decodificadores e decodificadores de esquema a cada iteração.
<p align="center">
<img src="https://assets.kitploit.com/production/public/readmes/3551/1db7423a884b71b9464011392860cb7f32e6f9e3652f5cd26ed443e5297f52fc.png">
</p>
O próprio LFSR é bastante poderoso em termos de espaço de probabilidade. Para ainda mais polimorfismo, instruções de lixo são adicionadas no início do payload bruto não codificado. A imagem abaixo mostra a matriz companheira do polinômio característico do LFSR e, representando a semente como um vetor coluna, o estado do registrador na configuração de Fibonacci após k passos.
<p align="center">
<img src="https://raw.githubusercontent.com/egebalci/sgn/HEAD/.github/matrices.svg">
</p>
## Usando como biblioteca
```rust
use sgn::Encoder;
let shellcode = std::fs::read("payload.bin")?;
let mut encoder = sgn::Encoder::new(64)?;
let encoded = encoder.encode(&shellcode)?;
println!("encoded {} bytes", encoded.len());
```
Veja `examples/encode_binary.rs`.
## Testes
```sh
cargo test
```
A suíte inclui testes unitários de cifragem/decifragem, além de **testes de execução reais**: shellcode x64 codificado é mapeado como executável e executado no processo, e shellcode x86 é executado por meio de um harness auxiliar `cc -m32` (ignorado automaticamente se não houver toolchain de 32 bits). Ambas as arquiteturas são exercitadas nos modos plain, schema, multicamadas e registrador seguro, incluindo um loop de estresse aleatorizado.
## Notas sobre a migração
* A geração de instruções usa a API de montador tipada do `iced-x86` em vez do texto de montagem do keystone; os stubs de decodificação foram reconstruídos em torno do endereçamento relativo a RIP (x64) e de um esquema de duas passagens `call/pop` (x86).
* A cifra de esquema é expressa diretamente na visão nativa de DWORD em little-endian da CPU, o que é equivalente, porém mais claro, à aritmética mista big/little-endian do original.
* O código morto do original (a tabela de conjunto de instruções não usada, de ~3 mil linhas, e o gerador de "lixo inseguro" que nada chamava) foi removido.
* Correções menores: `random_byte` agora cobre toda a faixa `0..=255`, e o orçamento de tamanho do lixo (`--max`) é aplicado consistentemente como um limite por bloco.