
sgn v1.0.0-rs
Polymorpher Binärcodierer für offensive Security-Payloads. Kodiert Shellcode mit LFSR-basierter Rückkopplungsschleife, Einschleusung nutzloser Anweisungen und Verschleierung über mehrere Iterationen, um statische Erkennung zu umgehen.
SGN ist ein polymorpher Binärcode-Encoder für offensive Sicherheitszwecke, etwa um statisch nicht erkennbare Binär-Payloads zu erzeugen. Er verwendet eine additive Rückkopplungsschleife, um gegebene Binärbefehle ähnlich wie LFSR zu kodieren. Dieses Projekt ist die Neuimplementierung des ursprünglichen Shikata ga nai in Go mit vielen Verbesserungen.
[!WARNING]
Das Projekt wurde kürzlich nach Rust portiert. Dieser Port behält das ursprüngliche Design und Verhalten bei, ersetzt jedoch den Keystone-Textassembler durch den reinen Rust-iced-x86-Assembler, sodass keine nativen Bibliotheksabhängigkeiten bestehen — er lässt sich mit einem einfachencargo builderstellen. Im sgn-go-Zweig finden Sie die alte Go-Version.
Warum?
Für die Offensive-Security-Community gilt die ursprüngliche Implementierung des Shikata-ga-nai-Encoders als bester Shellcode-Encoder (bisher). Im Laufe der Jahre fanden Sicherheitsforscher jedoch mehrere Fallstricke beim statischen Erkennen des Decoder-Stubs (verwandte Arbeit: FireEye-Artikel). Das Hauptmotiv für dieses Projekt war es, einen besseren Encoder zu schaffen, der die übergebenen Binärdaten so weit kodiert, dass sie mit völlig zufälligen Daten identisch sind und das Vorhandensein eines Decoders nicht erkannt werden kann.
- 64-Bit-Unterstützung.
Finally properly encoded x64 shellcodes ! - Neuer kleinerer Decoder-Stub.
LFSR key reduced to 1 byte - Kodierter Stub mit pseudozufälligem Schema.
Decoder stub is also encoded with a psudo random schema - Keine sichtbare Schleifenbedingung
Stub decodes itself WITHOUT using any loop conditions !! - Verschleierung des Decoder-Stubs.
Random garbage instruction generator added with keystone - Option für sichere Register.
Non of the registers are clobbered (optional preable, may reduce polimorphism)
So funktioniert es
Jeder Kodierungsdurchlauf:
- (optional) fügt ein Register-Wiederherstellungs-Suffix an (sicherer Modus);
- stellt zufällige, werterhaltende Garbage-Anweisungen voran;
- verschlüsselt den Payload mit der ADFL-Chiffre (additive Rückkopplungsschleife) und stellt einen schleifenfreien Decoder-Stub voran, der dies zur Laufzeit rückgängig macht;
- sofern nicht
--plainangegeben ist, verschlüsselt es den Stub selbst mit einer zufälligen, pro Lauf erzeugten Schema- Chiffre (XOR/ADD/SUB/ROL/ROR/NOTüber DWORDs) und stellt einen selbstlokalisierenden Schema-Decoder voran, sodass sogar der Decoder wie Zufallsdaten aussieht; - wiederholt optional
--enc-Mal mit neuen Seeds; - (optional) stellt ein Register-Sicherungs-Präfix voran (sicherer Modus).
Installation
cargo install sgn
Sie können die vorkompilierten Binärdateien auch HIER erhalten.
Verwendung
-h ist ziemlich selbsterklärend; verwenden Sie -v, wenn Sie sehen möchten, was hinter den Kulissen passiert ( ͡° ͜ʖ ͡°)_/¯
__ _ __ __ _
___ / / (_) /_____ _/ /____ _ ___ ____ _ ___ ___ _(_)
(_-</ _ \/ / '_/ _ `/ __/ _ `/ / _ `/ _ `/ / _ \/ _ `/ /
/___/_//_/_/_/\_\\_,_/\__/\_,_/ \_, /\_,_/ /_//_/\_,_/_/
========[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
Beispiel:
sgn -i shellcode.bin -o encoded.bin -a 64 --badchars '\x00\x0a\x0d'
Ausführungsablauf
Das folgende Bild ist ein grundlegendes Ablaufdiagramm für den Encoder. Beachten Sie jedoch, dass sich Größen, Positionen und Reihenfolgen der Garbage-Anweisungen, Decoder und Schema-Decoder bei jeder Iteration ändern.
Das LFSR selbst ist im Hinblick auf den Wahrscheinlichkeitsraum ziemlich leistungsfähig. Für noch mehr Polymorphismus werden am Anfang des unkodierten Roh-Payloads Garbage-Anweisungen angehängt. Das folgende Bild zeigt die Begleitmatrix des charakteristischen Polynoms des LFSR und, wenn der Seed als Spaltenvektor angegeben wird, den Zustand des Registers in der Fibonacci-Konfiguration nach k Schritten.
Verwendung als Bibliothek
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());
Siehe examples/encode_binary.rs.
Testen
cargo test
Die Suite enthält Unit-Tests für den Chiffre-Roundtrip sowie echte Ausführungstests: Kodierter x64-Shellcode wird als ausführbar gemappt und prozessintern ausgeführt, und x86-Shellcode wird über eine cc -m32-Hilfsharness ausgeführt (wird automatisch übersprungen, wenn keine 32-Bit-Toolchain vorhanden ist). Beide Architekturen werden in den Modi Plain, Schema, mehrschichtig und Safe-Register getestet, einschließlich einer randomisierten Stress-Schleife.
Anmerkungen zum Port
- Die Anweisungserzeugung verwendet die typisierte Assembler-API von
iced-x86anstelle von Keystone-Assemblytext; die Decoder-Stubs wurden um RIP-relative Adressierung (x64) und eincall/pop-Zweipass-Schema (x86) neu aufgebaut. - Die Schema-Chiffre wird direkt in der nativen Little-Endian-DWORD-Sicht der CPU ausgedrückt, was äquivalent, aber klarer ist als die gemischte Big-/Little-Endian-Arithmetik des Originals.
- Nicht mehr verwendeter Code aus dem Original (die ungenutzte, etwa 3000 Zeilen umfassende Befehlssatztabelle und der „unsafe garbage“-Generator, der von nichts aufgerufen wurde) wurde entfernt.
- Kleinere Korrekturen:
random_byteumfasst jetzt den vollständigen Bereich0..=255, und das Garbage-Größenbudget (--max) wird konsistent als Obergrenze pro Block angewendet.