
ネイティブAPIを介したntdll .textセクションの適切なアンフッキング。他のアンフッカーとは異なり、ロードされたntdllが2つになることはありません。x86/x64/wow64対応。
ネイティブAPIによるntdll .textセクションの適切なアンフック。x86/x64/wow64対応。
プログラムはPEBを走査してntdll.dllのベースアドレスを特定し、Import Address Tableに触れることなくPEエクスポートテーブルを手動で解析してNT API関数を解決します。次にNtOpenFileを使用してディスクからクリーンなntdll.dllを開き、NtCreateSectionでセクションオブジェクトを作成し、NtMapViewOfSectionでプロセスにマッピングして、LoadLibraryによる2つ目のDLLの実際の読み込みなしでアンフック元を取得します。フックされた.textセクションはNtProtectVirtualMemory経由でPAGE_EXECUTE_READWRITEに変更され、クリーンな.textがカスタムのmemcpyでフックされたセクションに上書きされ、その後プロテクションは元のフラグに復元されます。アンフックが成功したことをバイト単位で検証した後、クリーンなコピーはNtUnmapViewOfSectionで適切にマップ解除され、メモリ内に2つ目のntdllが残らないようにします。
公開されているアンフックコードのほとんどは、文字通り同じゴミソース(ired.teamの例や、github上のほぼすべてのオープンソースアンフックツールなど)からコピペされたものであり、実際のEDRに対して役に立たない大きな問題を抱えています。ネイティブAPIの代わりにVirtualProtectを使うため、フックされた関数を呼び出してアンフックするという本来の目的が完全に無意味になります。また、.textセクションにRWX権限を設定しますが、これはEDRが即座に検知する巨大なIOCです。さらに、セクションマッピングに対するCloseHandleではメモリが解放されないため、クリーンなコピーを実際にはマップ解除していません。UnmapViewOfFileまたはNtUnmapViewOfSectionが必要なのに、誰もがこの部分を忘れるため、プロセス内にntdllのコピーが2つロードされたままになり、これは基本的に「私はマルウェアです」と書かれた巨大なネオンサインのようなものです。また、メインのntdllに対してFreeLibraryを使おうとしますが、これは機能しない上にハンドルリークを引き起こします。さらに、適切に復元すれば1回で済むのに、不必要に2回RWXにプロテクションを変更します。
この実装は、全体でネイティブAPI(NtOpenFile、NtCreateSection、NtMapViewOfSection、NtProtectVirtualMemory)を使用し、NtUnmapViewOfSectionでクリーンなコピーを適切にマップ解除してntdllのコピーが2つロードされたままになるのを防ぎ、メインのntdllにFreeLibraryを使わず、メモリ比較で成功を検証することで、公開アンフックコードによくあるバグを修正しています。ただし、最新のEDRが検知する根本的なIOCを回避しているわけではありません。C:\Windows\System32\ntdll.dllに対してNtOpenFileを使用することはログに残るIOCであり、ntdll.dllを指すSEC_IMAGE付きのNtCreateSectionはETW経由で追跡され、ntdllの.textセクションのメモリプロテクションを変更することはネイティブAPIを使っても大きなレッドフラグであり、.textへの書き込みはメモリ書き込みコールバックで検出可能です。この手法は広く知られており、CrowdStrikeやSentinelOneなどの最新EDRはこのパターン全体に対するシグネチャを持っています。Microsoft Defender for EndpointやElasticのような先進的なEDRは、カーネルコールバックとETWテレメトリに依存しているため、もはやユーザーモードフックすら使用しておらず、アンフックはそれらに対して文字通り何の効果もありません。これはインラインフックのみを使用する基本的なEDRや古いセキュリティ製品に対しては有効ですが、カーネルモードコンポーネントや行動分析を備えたものには通用しません。より良い代替案としては、そもそもフックされた関数を一切呼ばない直接システムコール、wow64境界を越えるためのheaven's gate、実行時にntdll .textから手動でシステムコールを抽出する方法、または疑わしいAPIを完全に避けることなどがあります。2024/2025年において、実際のエンタープライズEDRに対してアンフックは一般的に死んだテクニックだからです。
x64ネイティブプロセス、x86ネイティブプロセス、wow64プロセス(x64 Windows上のx86)で動作します。wow64を自動検出し、正しいシステムディレクトリ(System32とSysWOW64)を使用するため、意識する必要はありません。
ntdll.dllの.textセクションのみが変更されます。なぜなら、そこに実際の関数コードがすべて存在し、EDRフックがインライン関数フック(関数プロローグへのjmp命令)として配置される場所だからです。.dataや.rdataなどの他のセクションには理由がない限り触れません。触れると利益もなくIOCが増えるだけだからです。
cl /EHsc /std:c++17 main.cpp /Fe:unhook.exe
とか何でもいいですが、最近のC++コンパイラなら動きます。windows.hとwinternl.hが必要です。
コンピュータシステムへの不正アクセスは違法です。自分が所有するシステム、またはテストの許可を得たシステムでのみ使用してください。連邦刑務所は現実に存在し、容赦ありません。
このコードはCONTAINING_RECORDマクロを使用してLDRリストを適切に走査し、セグメントレジスタ(x64ではgs、x86ではfs)経由でPEBにアクセスし、名前比較によるハードコードされた.textセクション検索を行います(もっとエレガントにできるかもしれませんが、とにかく動作します)。エラー処理はNTSTATUSコードとNT_SUCCESSマクロを使用し、メモリ操作は安全性のためSEH try/exceptでラップしています。C++が読めず、PE形式の内部構造を理解していないのであれば、そもそもこれを使うべきではないでしょう。