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

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

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

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

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
BYOVD-DriverKiller — 驱动程序逆向与利用 | Kitploit
ツール/GitHubGitHub/alex3o/byovd-driverkiller
エクスプロイトリバースエンジニアリングポストエクスプロイトバイナリ解析学習と教育レッドチーミング
GitHubalex3o/byovd-driverkiller

BYOVD-DriverKiller

驱动程序逆向与利用

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

人気

すべて見る →

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

すべてのツールを探索

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

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

BYOVD-DriverKiller

⚠️ 警告: このプロジェクトは厳密に教育的・デモンストレーション目的です。悪意のある目的で使用することを意図していません。目的は、リバースエンジニアリングの手法とWindowsドライバーのエクスプロイト手順を学ぶことです。


ここでは、d1rk(SaadAhla) https://github.com/SaadAhla が提供する演習を解くために私が取ったアプローチを説明します。この演習は、正規に署名され、ブロックリスト(HVCI、LOLBIN...)に存在しないドライバーに対してリバースエンジニアリングとエクスプロイトを行うというものです。 このカーネルモードドライバーを介してシステム上の任意のアクティブなプロセスを終了できるCプログラムも用意しています。その動作については、この後詳しく説明します。

POC-BYOD

📃 使用方法: DriverKiller.exe <プロセス名.exe> [-d]

オプション -d : エクスプロイト後にサービスとドライバーをシステムから削除します。

ドライバーの証明書が期限切れのため、ターゲットマシンでテスト署名モードを有効にする必要があります。


パート1 - リバースエンジニアリング:

演習では、SHA-256ハッシュを名前とする.sysファイルが提供されます。 最初のステップは、このファイルをIDAで開くことです。
IDAは無料で利用できます。Hex-Raysのサイトにアクセスしてライセンスを生成し、ソフトウェアをダウンロードするだけです。

まず、ドライバーのIAT(Import Address Table)を一覧表示し、目的のAPIへの呼び出しを探します: ZwTerminateProcess。

screen1-git

ZwTerminateProcess をダブルクリックすると、IDAはこの関数のコンパイル済みコードに移動します。エントリを選択してクロスリファレンスを表示すると、それを呼び出すドライバーの関数のリストが得られます。

screen2-git

ZwTerminateProcess を使用しているのは、オフセット 1CE の関数 sub_12EF4 であることがわかります。ダブルクリックすると、IDAはそのコンパイル済みコードを表示します。

screen11-git

逆コンパイルされたコードには、ZwOpenProcess(ターゲットプロセスへのハンドルを開く)と ZwTerminateProcess(そのハンドルを介してプロセスを終了する)への呼び出しが示されています。

ZwOpenProcess のドキュメント(https://learn.microsoft.com/fr-fr/windows-hardware/drivers/ddi/ntddk/nf-ntddk-zwopenprocess)を参照すると、ClientID パラメータが対象プロセスのPIDを示すポインタであることがわかります。

その上の行では、ClientId.UniqueProcess が変数 v22 で初期化されています。これはその直前に定義されています:

root@kitploit:~
v22 = (void )((_QWORD *)i + 10);

この代入を理解するには、変数 i と +10 フィールドを特定する必要があります。

screen3-git

この関数のさらに上では、SYSTEM_PROCESS_INFORMATION パラメータを指定した ZwQuerySystemInformation への呼び出しがあります。また、i が変数 v6 とともにこの構造体のエントリを反復するイテレータであることもわかります。

ZwQuerySystemInformation のドキュメント(https://learn.microsoft.com/en-us/windows/win32/sysinfo/zwquerysysteminformation)によると、この関数はシステム上のアクティブなプロセスごとに1エントリを含む配列を返します。

SYSTEM_PROCESS_INFORMATION 構造体は、https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation で説明されています。

root@kitploit:~
typedef struct _SYSTEM_PROCESS_INFORMATION {
    ULONG NextEntryOffset;
    ULONG NumberOfThreads;
    BYTE Reserved1[48];
    UNICODE_STRING ImageName;
    KPRIORITY BasePriority;
    HANDLE UniqueProcessId;
    PVOID Reserved2;
    ULONG HandleCount;
    ULONG SessionId;
    PVOID Reserved3;
    SIZE_T PeakVirtualSize;
    SIZE_T VirtualSize;
    ULONG Reserved4;
    SIZE_T PeakWorkingSetSize;
    SIZE_T WorkingSetSize;
    PVOID Reserved5;
    SIZE_T QuotaPagedPoolUsage;
    PVOID Reserved6;
    SIZE_T QuotaNonPagedPoolUsage;
    SIZE_T PagefileUsage;
    SIZE_T PeakPagefileUsage;
    SIZE_T PrivatePageCount;
    LARGE_INTEGER Reserved7[6];
} SYSTEM_PROCESS_INFORMATION;

参考: Windows x64 におけるいくつかの型のサイズ

  • ULONG = 4オクテット
  • USHORT = 2オクテット
  • HANDLE = 8オクテット
  • PWSTR = 8オクテット
  • KPRIORITY (LONGのtypedef) = 4オクテット
  • UNICODE_STRING = 16オクテット(構造体は以下のとおり):
root@kitploit:~
  typedef struct _UNICODE_STRING {
    USHORT Length;        -> 2      
    USHORT MaximumLength; -> + 2 = 4
    PWSTR  Buffer;        -> + 8 = 12 (12 n'est pas un multiple de 8 donc padding de 4 ajouté en amont de Buffer) = 16
} UNICODE_STRING;

UniqueProcessId のオフセットの計算:

root@kitploit:~
    ULONG NextEntryOffset;        -> 4
    ULONG NumberOfThreads;        -> + 4 = 8
    BYTE Reserved1[48];           -> + 48 = 56
    UNICODE_STRING ImageName;     -> + 16 = 72
    KPRIORITY BasePriority;       -> + 4 = 76 (76 n'est pas un multiple de 8 donc padding de 4 ajouté) = 80
    HANDLE UniqueProcessId;       -> + 8 = 88

したがって、UniqueProcessId メンバーはオフセット 0x50(10進数の80)にあります。

変数 v22 の代入を見ると、i が QWORD(8オクテット)ポインタにキャストされていることがわかります:

root@kitploit:~
v22 = (void )((_QWORD *)i + 10);
つまり、v22 は i + 10 * 8 = 80オクテットのアドレスに対応します。したがって、この変数には SYSTEM_PROCESS_INFORMATION 構造体から取得したPIDが含まれています。

どのPIDが ZwTerminateProcess に渡されるかを知るには、この代入を取り巻く条件を分析する必要があります。

screen4-git

最初にプロセスイメージ名が取得されていることがわかります:

root@kitploit:~
v9 = (wchar_t )((_QWORD *)i + 8);
v9 = i + 8 × 8 = 64オクテットのアドレスだからです。これは、ImageName メンバーの Buffer に対応します。このメンバーはオフセット 56 + 2 (USHORT) + 2 (USHORT) + 4 (padding) = 64 にあるためです。

以下の操作とループを考慮すると、引数として渡されたプロセス名(a2)とシステム上のアクティブなプロセス v9/String の間で比較が行われているという仮説を立てることができます。

root@kitploit:~
sub_1C078(String, v9, (int)v13);
v17 = strupr(a2);
v18 = strupr(String);

つまり、ZwTerminateProcess で終了するプロセス名を保持することになっているのはパラメータ a2 です。 a2 は関数 sub_12EF4 のパラメータであることに注目してください。さらに進めるには、この関数の参照を調べる必要があります(読みやすくするために ZwTerminateProcessCaller と改名しました)。

screen5-git

ZwTerminateProcessCaller はオフセット 61A の関数 sub_13624 によって呼び出されていることがわかります。

screen6-git

この逆コンパイル済みコードを分析する前に、関数 sub_13624(ZwTerminateProcessCallerCaller と改名)の参照を調べます。このコードがUserModeからの DeviceIoControl API呼び出しの後に実際に使用されていることを確認するためです。

screen§-git

ZwTerminateProcessCallerCaller は関数 sub_14130(ZwTerminateProcessCallerCallerCaller と改名... 幸いなことに、これはエントリポイントの前の最後の関数です 😅)によって呼び出されていることがわかります。

screen7-git

ZwTerminateProcessCallerCallerCaller はオフセット 306 の関数 sub_1A4A8 によって呼び出されていることがわかります。

screen8-git

ZwTerminateProcessCallerCallerCaller の代入が見つかります:

root@kitploit:~
memset64(DriverObject->MajorFunction, (unsigned __int64)ZwTerminateProcessCallerCallerCaller, 0x1Cu);
これは、この関数が MajorFunction テーブルのすべてのエントリ(0x1B = 27、および28個の主要IRPが存在)に割り当てられていることを意味します。

screen9-git

関数 sub_13624(別名 ZwTerminateProcessCallerCaller)に戻る前に、Symbolic Name と Device Name(ここでは同一)を取得します: Viragtlt。

screen12-git

ZwTerminateProcessCallerCaller に戻ると、その2番目のパラメータ(つまり a2)が MasterIrp->AssociatedIrp.SystemBuffer に対応していることがわかります。

screen13-git

ZwTerminateProcessCaller への呼び出しのすぐ上に、IOCTL コード -2106392528(16進数: 0x82730030)があります。

これらの情報から、このドライバーを悪用するには、終了するプロセス名を SystemBuffer に入れて DeviceIoControl API呼び出しをドライバーに送信する必要があると推測できます。


🔷 リバースエンジニアリングで得られた情報:

  • IOCTLCode : 0x82730030
  • Device Name : Viragtlt
  • Symbolic Name : Viragtlt
  • SystemBuffer にはターゲットプロセス名を含める必要があります

パート2 - エクスプロイト

このドライバーを悪用するには(ターゲットマシンにインストールされアクティブな場合)、まずドライバーへのハンドルを開き、終了したいプロセス名を含むバッファを指定して DeviceIoControl API呼び出しを行う必要があります。
この演習では、Cプロジェクトを開発しました。その機能は次のとおりです:

  • ドライバーがシステム上に存在しアクティブかどうかを確認します(特定のサービス名を使用):
    • 存在してアクティブな場合、プログラムは DeviceIoControl API呼び出しでドライバーを悪用します。
    • 存在しない場合、プログラムはリソースからドライバーを抽出し、ユーザーのデスクトップに展開して、アクティブなサービスを作成し、DeviceIoControl API呼び出しでドライバーを悪用します。(サービス作成を行うため、管理者権限が必要です。)
  • ドライバーがシステム上に存在するがサービスが開始されていない場合、プログラムはサービスを開始してから、DeviceIoControl API呼び出しで悪用します。

また、エクスプロイト後にサービスとドライバーをシステムから削除できる -d オプションも追加しました。

実行サイクル全体におけるCプログラムの動作は次のとおりです:

git

AV/EDR回避

この場合、DriverKiller.exe は Microsoft Defender によって静的にも動的にも検出されません。 ここでの回避はあまり意味がありません。悪用されるドライバーは期限切れの証明書を持っているため、実際の環境での使用は考えにくいからです。 ただし、よりステルス性を高めるために、次のものを実装することもできました:

  • GetProcAddress と GetModuleHandle のカスタム実装による IAT テーブルの特定のAPI呼び出しのマスキング
  • API呼び出し実行のためのカーネルへの接近(Direct/Indirect Syscalls)
  • Anti-VM / Anti-Debug テクニック

2025年8月29日時点のドライバー検出(既存の結果であり、明白な理由からVirusTotalには何も提出していません):

image

⚠️ このプロジェクトは学習目的で作成されています。不正確な点やエラーが含まれる可能性があります。提案、修正、議論はいつでも歓迎します! 😃 d1rk(SaadAhla) に感謝します: https://github.com/SaadAhla !

ツールをダウンロード