
sgn v1.0.0-rs
攻撃的セキュリティペイロード用のポリモーフィックバイナリエンコーダ。LFSRベースのフィードバックループ、ガベージ命令注入、複数回の難読化によりシェルコードをエンコードし、静的検出を回避します。
SGNは、静的に検出不可能なバイナリペイロードを生成するなど、攻撃セキュリティ目的のためのポリモーフィックなバイナリエンコーダです。これは、LFSRと同様の加法的フィードバックループを使用して、与えられたバイナリ命令をエンコードします。このプロジェクトは、オリジナルのShikata ga naiをgolangで再実装したものに、多くの改良を加えたものです。
[!WARNING]
このプロジェクトは最近Rustに移植されました。この移植は元の設計と動作を維持していますが、keystoneテキストアセンブラを純Rustのiced-x86アセンブラに置き換えているため、ネイティブライブラリへの依存はありません — 単純なcargo buildでビルドできます。レガシーなGoバージョンについては、sgn-goブランチを参照してください。
なぜ?
攻撃セキュリティコミュニティにとって、shikata ga naiエンコーダのオリジナル実装は、最高のシェルコードエンコーダ(現在に至るまで)と見なされています。しかし、長年にわたり、セキュリティ研究者はデコーダスタブを静的に検出するためのいくつかの落とし穴を発見しました(関連研究:FireEyeの記事)。このプロジェクトの主な動機は、与えられたバイナリを完全にランダムなデータと区別がつかないようにエンコードし、デコーダの存在を検出不可能にする、より優れたエンコーダを作成することでした。
- 64ビットサポート。
ついに正しくエンコードされたx64シェルコードが実現! - 新しい小型デコーダスタブ。
LFSRキーを1バイトに削減 - 疑似ランダムスキーマでエンコードされたスタブ。
デコーダスタブ自体も疑似ランダムスキーマでエンコード - 可視的なループ条件なし
スタブはループ条件を一切使わずに自己デコード!! - デコーダスタブの難読化。
キーストーンを使用したランダムガベージ命令ジェネレータを追加 - セーフレジスタオプション。
どのレジスタも破壊されません(オプションのプリアンブル、ポリモーフィズムを低下させる可能性があります)
仕組み
各エンコードパス:
- (オプション)レジスタ復元サフィックスを追加(セーフモード);
- 先頭にランダムで値を保持するガベージ命令を追加;
- ペイロードをADFL(加法的フィードバックループ)暗号で暗号化し、ループなしのデコーダスタブを前置して実行時に復号;
--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ビットツールチェーンがない場合は自動的にスキップされます)。両方のアーキテクチャが、プレーン、スキーマ、マルチレイヤー、セーフレジスタモードにわたって、ランダム化ストレスループを含めてテストされます。
移植に関する注記
- 命令生成は、keystoneアセンブリテキストではなく、
iced-x86の型付きアセンブラAPIを使用します。デコーダスタブは、RIP相対アドレッシング(x64)およびcall/pop2パス方式(x86)を中心に再構築されました。 - スキーマ暗号は、CPUのネイティブリトルエンディアンDWORDビューで直接表現されており、これはオリジナルのビッグ/リトルエンディアン混在算術と同等ですが、より明確です。
- オリジナルからのデッドコード(使用されていない約3k行の命令セットテーブルと、呼び出されなかった"unsafe garbage"ジェネレータ)は削除されました。
- 軽微な修正:
random_byteはフル範囲0..=255をカバーするようになり、ガベージサイズの予算(--max)はブロックごとの上限として一貫して適用されます。