Voltar às atualizações
New releaseJul 29, 2026

sgn v1.0.0-rs

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.

Compartilhar

GitHub All Releases Build Issues Crates License: MIT

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. Este projeto é a reimplementação do Shikata ga nai original 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 pelo montador puro-Rust 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 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). 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.

  • Suporte a 64 bits. Finally properly encoded x64 shellcodes !
  • Novo stub de decodificação menor. LFSR key reduced to 1 byte
  • Stub codificado com esquema pseudoaleatório. Decoder stub is also encoded with a psudo random schema
  • Sem condição de loop visível. Stub decodes itself WITHOUT using any loop conditions !!
  • Ofuscação do stub de decodificação. Random garbage instruction generator added with keystone
  • 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

cargo install sgn

Você também pode obter os binários pré-compilados AQUI.

Uso

-h é bem autoexplicativo; use -v se quiser ver o que está acontecendo nos bastidores ( ͡° ͜ʖ ͡°)_/¯

       __   _ __        __                               _ 
  ___ / /  (_) /_____ _/ /____ _  ___ ____ _  ___  ___ _(_)
 (_-</ _ \/ /  '_/ _ `/ __/ _ `/ / _ `/ _ `/ / _ \/ _ `/ / 
/___/_//_/_/_/\_\\_,_/\__/\_,_/  \_, /\_,_/ /_//_/\_,_/_/  
========[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:

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.

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.

Usando como biblioteca

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

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.

Categorias