Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
SILVERPICK — Windows ユーザーモード シェルコード開発フレームワーク (WUMSDF) | Kitploit
ツール/GitHubGitHub/winterknife/silverpick
エクスプロイトシェルコードレッドチーミングシェルコード生成ペイロード開発
GitHubwinterknife/silverpick

SILVERPICK

Windows ユーザーモード シェルコード開発フレームワーク (WUMSDF)

リポジトリを見る
1581751ヶ月前Kitploit レビュー済み

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

SILVERPICK

バージョン

  • v1.1

概要

プロジェクト SILVERPICK は、Windows ユーザーモードシェルコード開発フレームワーク (WUMSDF) であり、その唯一の目的は、ケイパビリティ開発者が C/C++ を使用して Windows x64 向けの Position Independent Code (PIC) ブロブを容易に構築できるようにし、そのような取り組みの開発コストを削減することです。

これはプロジェクト WILDBEAST から派生しており、以下のものを活用します:

  1. コードエディタとして Visual Studio Code
  2. コンパイラツールチェーンとして MinGW-w64 ツールチェーン
  3. ビルドシステムとして GNU Make

セットアップ

セットアップ手順はこちらから確認できます:GCC-Clang-Setup-Windows

このプロジェクトは MSYS2 を使用していることに注意してください。

特徴

高水準プログラミング言語でシェルコードを書くことは目新しいものではなく、2010年以降、数え切れないほどのブログ記事や研究論文が公開されてきました。では、SILVERPICK の新しさは何でしょうか?

それは良い質問ですね。

SILVERPICK には、袖に隠した素敵なトリックの袋がありますが、何よりも、これは私なりのこのテーマへの取り組みです。

それでは、前置きはこれくらいにして、最初のトリックを紹介します。

トリック 01

Matt Graeber が C でシェルコードを書くことを広めて以来、多くの人々が彼の Assembly 言語で書かれた16バイトのスタックアライメントスタブ を使用してきました。

これは問題ではありませんが、私たちは IKEA ではないので、アセンブリは必要ないはずであり、実際に必要ありません。

スタックアライメントスタブを生成してくれる GCC 関数属性 が存在します。

それが、便利な ALIGN_STACK マクロという形の force_align_arg_pointer 関数属性です。これは以下のアセンブリを生成します:

root@kitploit:~
Disassembly of section .init:

<PicEntry>:
	push   rbp
	mov    rbp,rsp
	and    rsp,0xfffffffffffffff0
	sub    rsp,0x20
	call   <PicEntry+0x11>	IMAGE_REL_AMD64_REL32	.text$payload
	leave
	ret

.init セクションとは何かって? それは、私の2番目のトリックへの良い導入となります。

トリック 02

Matt Graeber がある時点で C によるシェルコード作成を広めたかもしれませんが、実際にこの黒魔術を復活させたのは、Stardust を生み出した Paul Ungur です。

さて、Stardust は Binutils リンカスクリプト を使用して、関数とデータを適切な PE セクションに正しい順序で配置します。この手法自体は Austin Hudson の作品に由来しており、多くの人々が彼のリンカスクリプトの変種を使用しています。

リンカスクリプトはリンカのセクション順序付けには最適ですが、特定の関数をコードセクションの先頭に配置するだけであれば、それらは不要です。

ここで、.init という特別なセクション名を持つ section 関数属性の出番です。これは、その関数に main() 実行前のランタイム初期化コードが含まれており、リンク順序で 最初 でなければならないことをリンカに示します。

このために、CODE_BEGIN マクロが作成されました。

トリック 03

3番目のトリックとして、STACK_STRING マクロを紹介します。

C では、文字列リテラルを ANSI 文字の配列として宣言することで、スタック文字列(スタック上に動的に構築される文字列)を作成できます:

root@kitploit:~
char charrHelloKitty[] = { 'H', 'e', 'l', 'l', 'o', 'K', 'i', 't', 't', 'y', '\0' };

C++ では、char 配列を constexpr とマークするだけでスタック文字列を作成できます:

root@kitploit:~
constexpr char charrHelloKitty[]{ "HelloKitty" };

しかし、これらの手法はどちらも、文字列リテラルが十分に大きい場合、コンパイラ最適化の前では無力になります。それに対して私たちのソリューションは、Can Bölük による巧妙な C++ テンプレートメタプログラミングハックのおかげで、文字列の長さやコンパイラ最適化のレベルに関係なく機能します。

このマクロの使用は非常に簡単です:

root@kitploit:~
STACK_STRING(sstrText, "an extra long hello world!");
STACK_STRING(sstrCaption, "Demo");

MessageBoxA(nullptr, sstrText.data(), sstrCaption.data(), MB_OK);

これにより、次のアセンブリが生成されます:

root@kitploit:~
mov     [rsp+58h+var_23], 61h ; 'a'
mov     [rsp+58h+var_22], 6Eh ; 'n'
mov     [rsp+58h+var_21], 20h ; ' '
mov     [rsp+58h+var_20], 65h ; 'e'
mov     [rsp+58h+var_1F], 78h ; 'x'
mov     [rsp+58h+var_1E], 74h ; 't'
mov     [rsp+58h+var_1D], 72h ; 'r'
mov     [rsp+58h+var_1C], 61h ; 'a'
mov     [rsp+58h+var_1B], 20h ; ' '
mov     [rsp+58h+var_1A], 6Ch ; 'l'
mov     [rsp+58h+var_19], 6Fh ; 'o'
mov     [rsp+58h+var_18], 6Eh ; 'n'
mov     [rsp+58h+var_17], 67h ; 'g'
mov     [rsp+58h+var_16], 20h ; ' '
mov     [rsp+58h+var_15], 68h ; 'h'
mov     [rsp+58h+var_14], 65h ; 'e'
mov     [rsp+58h+var_13], 6Ch ; 'l'
mov     [rsp+58h+var_12], 6Ch ; 'l'
mov     [rsp+58h+var_11], 6Fh ; 'o'
mov     [rsp+58h+var_10], 20h ; ' '
mov     [rsp+58h+var_2F], 0
mov     [rsp+58h+var_F], 77h ; 'w'
mov     [rsp+58h+var_E], 6Fh ; 'o'
mov     [rsp+58h+var_D], 72h ; 'r'
mov     [rsp+58h+var_C], 6Ch ; 'l'
mov     [rsp+58h+var_B], 64h ; 'd'
mov     [rsp+58h+var_A], 21h ; '!'
mov     [rsp+58h+var_33], 44h ; 'D'
mov     [rsp+58h+var_32], 65h ; 'e'
mov     [rsp+58h+var_31], 6Dh ; 'm'
mov     [rsp+58h+var_30], 6Fh ; 'o'

トリック 04

C++ と言えば、4番目のトリックはコンパイル時文字列ハッシュです。

これは新しい概念ではありませんが、SILVERPICK は既存の公開実装に対していくつかの改良を提供します。

まず、ハッシュ衝突攻撃が成功する確率を減らすために、一般的な非暗号化ハッシュ関数 FNV-1a の64ビット版を使用します。

次に、HashDB などの事前計算されたハッシュテーブルルックアップ に対抗するために、ハッシュ関数に修正されたパラメータを使用します。重要なのは、これによってハッシュ関数の特性は 変わらない ことです。

実行時に短い文字列をハッシュするには、HASH_STRING_RUN_TIME マクロを使用するだけです。

コンパイル時に短い文字列リテラルをハッシュするには、HASH_STRING_COMPILE_TIME マクロを使用するだけです。コンパイル時のみの評価は consteval によって保証されます。

トリック 05

x86 文字列命令を使用して、かなりの数の C ランタイムライブラリ (CRT) 関数を実装できることがわかりました。そこで当然、私はコンパイラ組み込み関数とインラインアセンブリを組み合わせてそれらを実装することにしました。

コード内で msvcrt!memset 関数を使用したいですか? 代わりに ZERO_MEMORY マクロを使用してください。これはコンパイラ組み込み関数を介して生成された rep stosb 命令を使用します。

msvcrt!memcpy 関数や msvcrt!memmove 関数はどうかって? 代わりとなる COPY_MEMORY マクロを紹介します。これはコンパイラ組み込み関数を介して生成された rep movsb 命令を使用します。

では、msvcrt!memcmp 関数の代替はどうでしょうか? repe cmpsb 命令を生成するためのコンパイラ組み込み関数は正確には存在しないことがわかります。そこで、代わりにインラインアセンブリを使用した compare_memory 関数を記述します。

最後に、msvcrt!memchr 関数の置き換えをお探しなら、scan_memory 関数を紹介します。これもまた、repne scasb 命令を生成するコンパイラ組み込み関数がないため、インラインアセンブリを使用します。

ああ、それから、scan_memory ルーチンを使って、より安全な独自の msvcrt!strlen 関数を次のように書けることも言い忘れていました:

root@kitploit:~
DWORD_PTR dwptrExportNameLength = std::min(BIT_CAST(DWORD_PTR, scan_memory(strExportName, 0x00, MAX_EXPORTED_SYMBOL_NAME_LEN)) - BIT_CAST(DWORD_PTR, strExportName), MAX_EXPORTED_SYMBOL_NAME_LEN);

これらの実装は、対象とする CPU マイクロアーキテクチャによっては、最も高性能なコードを生成しない可能性があることに注意してください。ただし、目的の処理を確実に実行することは保証されます。

トリック 06

もっとトリックに興味がありますか?

Common.h には、コンパイラを調整する際の複雑さを抽象化するための、他にもたくさんの小さなマクロがあります。

GetModuleHandle 関数の依存関係のない実装が UserModuleBase.cpp で提供されています。使いやすさを簡素化するために、GET_USER_MODULE_BASE という名前の便利なマクロが作成されました。

同様に、GetProcAddress 関数の依存関係のない実装が PEParse.cpp で提供されており、それは GET_EXPORTED_SYMBOL_ADDRESS という適切な名前の便利なマクロにラップされています。さらに、実行時動的リンクを支援するための2つのマクロが用意されています - 関数ポインタを0に宣言して初期化する INITIALIZE_FUNCTION_POINTER と、その関数ポインタを解決する RESOLVE_FUNCTION_POINTER です。

Visual Studio Code 統合 がプロジェクトに組み込まれているため、開発者は Ctrl+Shift+B キーボードショートカットを使用して、手間のかからないビルドプロセスを実行できます。

GitHub Actions 統合 もプロジェクトに組み込まれており、CI ビルドを可能にします。

このプロジェクトは、よく整理された構造と、徹底的にコメントされ、比較的クリーンなコードにいくらかの誇りを持っています。

最後に、プロジェクトの Makefile をひと目見てください。そこには、小型で安全かつ OPSEC フレンドリーなコードを生成する、厳選されたコンパイラフラグとリンカフラグが含まれています。その一方で、冗長なログと生成されたリンカマップファイルは、ビルドプロセスへの可視性を提供し、ツールチェーンのより深い理解を促進します。さらに、各翻訳単位は逆アセンブルファイルも生成します。これを調べると、しばしば「コンパイラは今何をしたんだ?」といった感想を抱くことでしょう。

使用方法

このフレームワークに魅力を感じたら、このセクションではその使用方法を説明します。

以下は PicMain.cpp からの抜粋です:

root@kitploit:~
/// @brief PIC start function
/// @param None
/// @return None
EXTERN_C NO_INLINE VOID __stdcall payload(
    VOID
) {
    // Init local variables
    PVOID pKernel32 = nullptr;
    INITIALIZE_FUNCTION_POINTER(LoadLibraryA);
    HMODULE hUser32 = nullptr;
    STACK_STRING(sstrUser32, "user32.dll");
    INITIALIZE_FUNCTION_POINTER(MessageBoxA);
    STACK_STRING(sstrText, "an extra long hello world!");
    STACK_STRING(sstrCaption, "Demo");

    // Get the image base address of kernel32.dll
    pKernel32 = GET_USER_MODULE_BASE("kernel32.dll");
    if (pKernel32 == nullptr)
        goto cleanup;

    // Resolve kernel32!LoadLibraryA
    RESOLVE_FUNCTION_POINTER(pKernel32, LoadLibraryA);
    if (LoadLibraryA == nullptr)
        goto cleanup;

    // Load User32.dll into the process VAS
    hUser32 = LoadLibraryA(sstrUser32.data());
    if (hUser32 == nullptr)
        goto cleanup;

    // Resolve user32!MessageBoxA
    RESOLVE_FUNCTION_POINTER(hUser32, MessageBoxA);
    if (MessageBoxA == nullptr)
        goto cleanup;

    // Display a message box
    MessageBoxA(nullptr, sstrText.data(), sstrCaption.data(), MB_OK);

    // Cleanup
cleanup:
    return;
}

十分に簡単に見えますよね?

SILVERPICK フレームワークを使用して C/C++ で PIC を作成する際は、次のルールを考慮する必要があります:

  1. payload 関数を従来のプログラムの main 関数、つまり (擬似) エントリポイント として扱います。
  2. すべての文字列リテラルは スタック文字列 として宣言する必要があります。
  3. グローバル変数 はコード内のどこでも使用できません。
  4. Windows API または Native API 関数は、対応するヘッダファイルで関数プロトタイプが利用可能であることを確認した上で、実行時動的リンク を介してのみ使用できます。

将来の拡張機能

このセクションには、将来のプロジェクトに統合される予定の拡張機能の非網羅的なリストが含まれています。

  • Clang/LLVM ツールチェーンに切り替える。
  • 別のビルドシステムに切り替える。
  • スタック文字列と連携し、FLOSS に耐性のあるコンパイル時文字列難読化。
  • シード付き非暗号化カスタムハッシュ関数を使用したコンパイル時文字列ハッシュ。
  • GS セグメントベースアドレスを取得する代替方法。
  • Export Address Filtering (EAF) エクスプロイト緩和をバイパスする機能。

参考文献

以下は、私の調査中に非常に貴重であることが判明し、このプロジェクトのインスピレーションとして広く使用された、時系列順に並べた参考文献のリストです:

  1. Cコンパイラでシェルコードを書く 著: Nick Harbour (2010)

  2. Cコンパイラによるシェルコード 著: Didier Stevens (2010)

  3. Cで最適化されたWindowsシェルコードを書く 著: Matt Graeber (2013)

  4. より良いシェルコードの書き方、または単にコンパイラを使う方法 著: Justin Fisher (2016)

  5. ShellcodeStdio 著: Jack Ullrich (2016)

  6. シェルコード: RSA-2048鍵交換、AES-256、SHA-3を使用したWindows PIC 著: Odzhan (2016)

  7. 最適化されたWindowsシェルコードを書く 著: Dimitri Fourny (2017)

  8. Cでのシェルコードの作成とコンパイル 著: Aleksandra Doniec と Mantvydas Baranauskas (2021)

  9. Visual StudioとC++を使用して任意のコードからシェルコードを作成する 著: Hamid Memar (2021)

  10. Cで最適化されたWindowsシェルコードを書く 著: Philip Woldhek (2021)

  11. Cからインラインアセンブリを経てシェルコードへ 著: Steve Salinas (2023)

  12. Visual Studioで独自のWindows x86/64シェルコードを作成する方法 著: Yazid Benjamaa (2023)

  13. モダンインプラント設計:位置独立型マルウェア開発 著: Paul Ungur (2024)

  14. Cからシェルコードへ(簡単な方法) 著: Print3M (2024)

  15. 著: Tijme Gommers (2025)

エラッタ

VirusTotal

私が奇妙に思ったのは、Microsoft Defender による VirTool:Win64/Silepesz.A という分類でした。

以下は、そのシグネチャが対象とするバイト列です:

root@kitploit:~
[+] Target file size: 2560 bytes
[+] Analyzing...
[!] Identified end of bad bytes at offset 0x4CB
000003CB   44 24 2F 32 C6 44 24 30  2E C6 44 24 31 64 C6 44   D$/2�D$0.�D$1d�D
000003DB   24 32 6C C6 44 24 33 6C  C6 44 24 35 61 C6 44 24   $2l�D$3l�D$5a�D$
000003EB   36 6E C6 44 24 37 20 C6  44 24 38 65 C6 44 24 39   6n�D$7 �D$8e�D$9
000003FB   78 C6 44 24 3A 74 C6 44  24 3B 72 C6 44 24 3C 61   x�D$:t�D$;r�D$<a
0000040B   C6 44 24 3D 20 C6 44 24  3E 6C C6 44 24 3F 6F C6   �D$= �D$>l�D$?o�
0000041B   44 24 40 6E C6 44 24 41  67 C6 44 24 42 20 C6 44   D$@n�D$Ag�D$B �D
0000042B   24 43 68 C6 44 24 44 65  C6 44 24 45 6C C6 44 24   $Ch�D$De�D$El�D$
0000043B   46 6C C6 44 24 47 6F C6  44 24 48 20 C6 44 24 29   Fl�D$Go�D$H �D$)
0000044B   00 C6 44 24 49 77 C6 44  24 4A 6F C6 44 24 4B 72   .�D$Iw�D$Jo�D$Kr
0000045B   C6 44 24 4C 6C C6 44 24  4D 64 C6 44 24 4E 21 C6   �D$Ll�D$Md�D$N!�
0000046B   44 24 25 44 C6 44 24 26  65 C6 44 24 27 6D C6 44   D$%D�D$&e�D$'m�D
0000047B   24 28 6F E8 55 00 00 00  48 85 C0 74 4B 48 BA 58   $(o�U...H.AtKH�X
0000048B   D0 CC C6 F8 E7 BF 0A 48  89 C1 E8 86 FD FF FF 48   DI�o��.H.A�.y��H
0000049B   85 C0 74 34 48 8D 4C 24  2A FF D0 48 85 C0 74 28   .At4H.L$*�DH.At(
000004AB   48 BA D9 92 FB 55 9A AC  70 E0 48 89 C1 E8 63 FD   H�U.�U.�p�H.A�cy
000004BB   FF FF 48 85 C0 74 11 48  8D 54 24 35 45 31 C9 4C   ��H.At.H.T$5E1�L

これは以下のソースに変換されます:

root@kitploit:~
pKernel32 = GET_USER_MODULE_BASE("kernel32.dll");
if (pKernel32 == nullptr)
    goto cleanup;

RESOLVE_FUNCTION_POINTER(pKernel32, LoadLibraryA); // mov rdx, 0x0ABFE7F8C6CCD058 (FNV-1a hash of "LoadLibraryA" with modified offset basis)
if (LoadLibraryA == nullptr)
    goto cleanup;

hUser32 = LoadLibraryA(sstrUser32.data());
if (hUser32 == nullptr)
    goto cleanup;

RESOLVE_FUNCTION_POINTER(hUser32, MessageBoxA); // mov rdx, 0xE070AC9A55FB92D9 (FNV-1a hash of "MessageBoxA" with modified offset basis)
if (MessageBoxA == nullptr)
    goto cleanup;

MessageBoxA(nullptr, sstrText.data(), sstrCaption.data(), MB_OK); // arg setup only

言うまでもなく、これは非常に脆い検出であり、例に示されている正確なサンプルコードのみを検出します。しかしながら、これはポリモーフィックな API ハッシュを使用することの重要性を浮き彫りにします。

ツールをダウンロード
relocatable
  • PIC開発クラッシュコース 著: Raphael Mudge (2025)

  • scfw 著: Petr Beneš (2026)