Skip to content
KitploitKITPLOIT
ツールエクスプロイトブログ
Log in
提出
ツールエクスプロイトブログ
提出

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
UnhookMe — 動的なWindows APIリゾルバ兼アンフックツール。フックされた関数(IAT、EAT、インラインパッチ)を検出して復元し、Red Teamマルウェアから監視されていないシステムコールを呼び出します。 | Kitploit
ツール/GitHubGitHub/mgeeky/unhookme
防御ツールレッドチーミングペイロード開発
GitHubmgeeky/unhookme

UnhookMe

動的なWindows APIリゾルバ兼アンフックツール。フックされた関数(IAT、EAT、インラインパッチ)を検出して復元し、Red Teamマルウェアから監視されていないシステムコールを呼び出します。

リポジトリを見る
34848164年前Kitploit レビュー済み

人気

すべて見る →

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

すべてのツールを探索

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

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

UnhookMe - 動的にフックを解除するインポートリゾルバ

侵入的なAVやEDRが、強化された可視性要件のために実行中のプロセスにホットパッチを導入する時代において、現代の攻撃者はこれらの監視をすり抜けるための堅牢なツールを必要としています。使用中の関数をその場でフック解除できる動的インポートリゾルバの提案実装は、攻撃者のレジリエンス強化に向けたさらなる一歩です。

ここで提案するソリューションは、リンカ解決型のWinAPIインポート(コンパイルされた実行可能ファイルのPEヘッダ、特にImport Address Tableに可視なまま)から、完全に動的なアプローチに切り替え、インポートを動的にのみ解決することに重点を置くことです。このような動的リゾルバには、オペレータ側からの指示なしにバックグラウンドで実行されるフック解除ロジックを組み込むことができます。


最も簡単な使用例

次のようにして、MessageBoxW をフックされず、監視されずに呼び出すことができます:

    RESOLVE(user32, MessageBoxW);
    _MessageBoxW(0, L"Look Ma! I'm unhooked!", L"Third - Unhooked", 0);

すべての魔法は RESOLVE マクロ定義内で発生し、_MessageBoxW という名前の ImportResolver<T> オブジェクトを構築します。


ショーケース

Unhookme showcase animation

UnhookMe の例の仕組みは次の通りです:

  1. 最初の MessageBoxW を表示します。これはフックの対象ではありません。
  2. 次に、MessageBoxW のプロローグを自分たちでフックし、メッセージを表示せずに常に0を返すようにします。
  3. 最後に、UnhookingImportResolver リゾルバを使用して MessageBoxW を動的に解決します。これにより、適用されたプロローグパッチを検出し、元のバイトを復元して、MessageBoxW の機能を効果的にフック解除します。

メッセージボックスが表示されている間に、次のログ行がコンソールのstdoutに出力されます:

[~] Resolved symbol kernel32.dll!CreateFileA
[~] Resolved symbol kernel32.dll!ReadProcessMemory
[~] Resolved symbol kernel32.dll!MapViewOfFile
[~] Resolved symbol kernel32.dll!VirtualProtectEx
[#] Found trampoline hook in symbol: MessageBoxW . Restored original bytes from file.
[~] Resolved symbol user32.dll!MessageBoxW

使用方法

合計5つのC++ソースコード/ヘッダファイルをソリューションに含める必要があります。ただし、メインプログラムファイルは、以下に詳述する2つの必要なヘッダのみを含めればよいです。

  • resolver.h - UnhookingImportResolver の実装の大部分と便利なマクロ定義を含むヘッダ
  • resolver.cpp - グローバルオプションが定義されたソースコード
  • usings.h - 一般的に使用されるWinAPIのための数十の using 型定義を含む、大きくて厄介なヘッダファイル
  • PE.cpp - カスタムPEパーサのソースコードファイル
  • PE.h - カスタムPEパーサのヘッダファイル

必要なヘッダ

プログラムは次の2つのヘッダのみを含める必要があります:

#include "usings.h"
#include "resolver.h"

グローバルオプション

リゾルバの動作やアクティビティの報告方法に影響を与える、変更可能なグローバルオプションがいくつかあります。これらは resolver.cpp ファイルの先頭で定義されています:

リゾルバのグローバルオプション:

  • globalQuietOption - 出力を一切行いたくない場合は true に設定
  • globalVerboseOption - 詳細な冗長出力を行いたい場合は true に設定
  • globalAntiSplicingOption - 解決された関数がフックされている場合にフックを解除する
  • globalLogFilePath - 出力ログ行のリダイレクト先。空の場合はstdoutを使用
bool globalQuietOption = false;
bool globalVerboseOption = true;
bool globalAntiSplicingOption = true;

wchar_t globalLogFilePath[MAX_PATH] = L"";

カスタムAPI型の指定

リゾルバを使用するには、まず関数ポインタ型を厳密な形式の using 文で宣言する必要があります:

    using fn_FunctionName = ReturnType WINAPI (
        ParamType1 paramName1,
        ...,
        ParamTypeN paramNameN,
    );

このリポジトリには、数十の一般的なWindows API用の事前定義されたusing型を含む usings.h ヘッダファイルが付属しています。

FunctionName は、ImportResolver に解決させたい WinAPI に対応し、その関数ポインタは WINAPI 呼び出し規約(x86 では __stdcall、x64 では __fastcall)を持つものとしてマークされなければなりません。ReturnType は WINAPI 型修飾子の前に置く必要があります。

関数の解決と使用

上記のように関数ポインタ型を定義すると、次の方法で使用できるようになります:

    RESOLVE(libraryName, FunctionName);
    ReturnType output = _FunctionName(param1, ..., paramN);

マクロ RESOLVE は ImportResolver テンプレートオブジェクトのインスタンス化と指定されたライブラリ名の調整を行います。

リゾルバはさらにいくつかのマクロ定義を導入し、さまざまな状況でコンストラクタ呼び出しを簡単に使用できるようにします:

#define RESOLVE(mod, func)                    RESOLVE_PARAMETERIZED(mod, func, ::globalVerboseOption, ::globalAntiSplicingOption)
#define RESOLVE_NO_UNHOOK(mod, func)          RESOLVE_PARAMETERIZED(mod, func, ::globalVerboseOption, false)

#define RESOLVE_VERBOSE_UNHOOK(mod, func)     RESOLVE_PARAMETERIZED(mod, func, true, true)
#define RESOLVE_VERBOSE_NOUNHOOK(mod, func)   RESOLVE_PARAMETERIZED(mod, func, true, false)
#define RESOLVE_NOVERBOSE_UNHOOK(mod, func)   RESOLVE_PARAMETERIZED(mod, func, false, true)
#define RESOLVE_NOVERBOSE_NOUNHOOK(mod, func) RESOLVE_PARAMETERIZED(mod, func, false, false)

リゾルバのコンストラクタ:

    template<typename Ret, typename ...Args>
    ImportResolver<Ret WINAPI(Args...)>(
            std::string dllName,
            std::string funcName,
            bool _verbose = false,
            bool _unhook = false,
            bool *_wasItHooked = nullptr
        )

仕組み

このリゾルバは、カスタムPEヘッダパーサを活用し、参照されたすべてのDLLモジュールを処理してエクスポートをマッピングし、モジュールのPEヘッダの整合性と参照された関数のスタブバイトの整合性を検証します。

考え方は次の通りです:

  1. まず、GetModuleHandle でアクセスできない場合、ユーザーが指定したライブラリ(RESOLVE マクロの最初のパラメータとして指定されたもの)を LoadLibrary でロードします。

  2. 次に、ロード/参照されたライブラリのPEヘッダを処理し、エクスポートをマッピングし、エクスポートアドレスの配列を取得するとともに、クロス検証のためにこれらのアドレスを自分たちで計算します。

  3. DLLのExport Address Tableで定義されたルーチンのアドレスが期待と一致しない場合、そのエクスポートはEATフックされていると見なされます。同様に、その関数の実行可能ファイルのImport Address Table (IAT) エントリが変更され、DLLのコードセクション内の正しい場所を指していない場合、その関数はIATフックされていると見なされます。

  4. これまでのところフックが見つからなかった場合、関数のプロローグの最初のNバイトを取得し、ディスクに保存されているDLLファイル内のものと比較します。メモリから取得したバイトとファイルから取得したバイトの間に不一致がある場合、関数がインラインパッチ(ホットパッチ)されたと見なします。

  5. 関数がフックされていると見なされた場合、元のエクスポートアドレス(自分たちで計算したもの)を返し、エントリのフックを解除します。パッチバイトが存在する場合は、それらを復元します。

  6. 最後に、リゾルバのパフォーマンスへの影響を最適化するために、ロードされたすべてのモジュールのイメージベースと解決された関数アドレスをキャッシュし、以降のアクセス時にキャッシュ(std::map)から返します。

このような動的フック解除リゾルバが直面する問題の中には、転送されたAPIのトラバースに関するものがあります(DLLには、この関数はこのモジュールには実装されておらず、別のモジュールにあることを示すExport thunkが含まれている場合があります)。この実装はサポートしていますが、トラバースロジックが時々壊れることがあります。


☕ サポートを示す ☕

このプロジェクトや他のプロジェクトは、眠れない夜と たくさんの努力 の成果です。もし私の活動を気に入ってくださり、常にコミュニティに還元していることを評価していただけるなら、コーヒーを一杯ご馳走する ことを検討してください(できればビールの方がいいですが)感謝の気持ちとして! 💪


著者

   Mariusz Banach / mgeeky, 21
   <mb [at] binary-offensive.com>
   (https://github.com/mgeeky)
ツールをダウンロード