
SGNは、静的に検出不可能なバイナリペイロードを生成するなど、攻撃セキュリティ目的のためのポリモーフィックなバイナリエンコーダです。これは、LFSRと同様の加法的フィードバックループを使用して、与えられたバイナリ命令をエンコードします。このプロジェクトは、オリジナルのShikata ga naiをgolangで再実装したものに、多くの改良を加えたものです。
[!WARNING]
このプロジェクトは最近Rustに移植されました。この移植は元の設計と動作を維持していますが、keystoneテキストアセンブラを純Rustのiced-x86アセンブラに置き換えているため、ネイティブライブラリへの依存はありません — 単純なcargo buildでビルドできます。レガシーなGoバージョンについては、sgn-goブランチを参照してください。
攻撃セキュリティコミュニティにとって、shikata ga naiエンコーダのオリジナル実装は、最高のシェルコードエンコーダ(現在に至るまで)と見なされています。しかし、長年にわたり、セキュリティ研究者はデコーダスタブを静的に検出するためのいくつかの落とし穴を発見しました(関連研究:FireEyeの記事)。このプロジェクトの主な動機は、与えられたバイナリを完全にランダムなデータと区別がつかないようにエンコードし、デコーダの存在を検出不可能にする、より優れたエンコーダを作成することでした。
ついに正しくエンコードされたx64シェルコードが実現!LFSRキーを1バイトに削減デコーダスタブ自体も疑似ランダムスキーマでエンコードスタブはループ条件を一切使わずに自己デコード!!キーストーンを使用したランダムガベージ命令ジェネレータを追加どのレジスタも破壊されません(オプションのプリアンブル、ポリモーフィズムを低下させる可能性があります)各エンコードパス:
--plainが指定されていない限り、スタブ自体をランダムな実行ごとのスキーマ暗号(DWORDに対するXOR/ADD/SUB/ROL/ROR/NOT)で暗号化し、自己位置特定スキーマデコーダを前置することで、デコーダもランダムデータのように見えます;--enc回数だけ新しいシードで繰り返し;cargo install sgn
プリコンパイル済みバイナリはこちらから入手することもできます。
使用方法
-hはかなり自明です。-vを使うと舞台裏で何が起こっているか確認できます ( ͡° ͜ʖ ͡°)_/¯
__ _ __ __ _
___ / / (_) /_____ _/ /____ _ ___ ____ _ ___ ___ _(_)
(_-</ _ \/ / '_/ _ `/ __/ _ `/ / _ `/ _ `/ / _ \/ _ `/ /
/___/_//_/_/_/\_\\_,_/\__/\_,_/ \_, /\_,_/ /_//_/\_,_/_/
========[Author:-Ege-Balcı-]====/___/=======v2.0.2=========
┻━┻ ︵ヽ(`Д´)ノ︵ ┻━┻ (ノ ゜Д゜)ノ ︵ 仕方がない
sgn [OPTIONS]
Options:
-i, --input <INPUT> 入力バイナリパス
-o, --out <OUT> エンコードされた出力バイナリ名 (デフォルト: <input>.sgn)
-a, --arch <ARCH> バイナリアーキテクチャ (32/64) [default: 64]
-c, --enc <ENC> バイナリをエンコードする回数 [default: 1]
-M, --max <MAX> ガベージブロックあたりの最大バイト数 [default: 50]
--plain デコーダスタブをエンコードしない
--ascii 完全にASCII印字可能なペイロードを生成(低速)
-S, --safe すべてのレジスタ値を保持(破壊しない)
--badchars <BADCHARS> これらのバイトを回避、16進形式 (例: \x00\x0a)
-v, --verbose 冗長モード
-h, --help ヘルプを表示
-V, --version バージョンを表示
例:
sgn -i shellcode.bin -o encoded.bin -a 64 --badchars '\x00\x0a\x0d'
以下の画像は、エンコーダの基本的なワークフロー図です。ただし、ガベージ命令、デコーダ、スキーマデコーダのサイズ、位置、順序は、反復ごとに変更されることに注意してください。
LFSR自体は、確率空間の点で非常に強力です。さらにポリモーフィズムを高めるために、エンコードされていない生のペイロードの先頭にガベージ命令が追加されます。以下の画像は、LFSRの特性多項式の同伴行列と、シードを列ベクトルとして表したもの、およびフィボナッチ構成におけるレジスタのkステップ後の状態を示しています。
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());
examples/encode_binary.rs を参照してください。
cargo test
スイートには、暗号ラウンドトリップのユニットテストに加えて、実際の実行テストが含まれています:
エンコードされたx64シェルコードは実行可能メモリにマッピングされ、プロセス内で実行されます。x86シェルコードはcc -m32ヘルパーハーネスを介して実行されます(32ビットツールチェーンがない場合は自動的にスキップされます)。両方のアーキテクチャが、プレーン、スキーマ、マルチレイヤー、セーフレジスタモードにわたって、ランダム化ストレスループを含めてテストされます。
iced-x86の型付きアセンブラAPIを使用します。デコーダスタブは、RIP相対アドレッシング(x64)およびcall/pop 2パス方式(x86)を中心に再構築されました。random_byteはフル範囲0..=255をカバーするようになり、ガベージサイズの予算(--max)はブロックごとの上限として一貫して適用されます。