フィルタドライバ入門

127
フィルタドライバ入門 firewood@hatena hotpepsi@twitter

Upload: firewood

Post on 13-Jul-2015

2.202 views

Category:

Software


7 download

TRANSCRIPT

Page 1: フィルタドライバ入門

フィルタドライバ入門

firewood@hatenahotpepsi@twitter

Page 2: フィルタドライバ入門

自己紹介 生息地

組込日記 http://d.hatena.ne.jp/firewood/ よく使う環境

Windows 、 Linux 、 Flash 、 C/C++ 、 x86 、 ARM

趣味 エンバグ、デバッグ キーボード蒐集

Page 3: フィルタドライバ入門

はじめに 書籍、 WDK 、 web の情報を元に記述

していますが、間違いがあれば教えてください

Page 4: フィルタドライバ入門

目的 ユーザー空間からカーネル空間まで全

体的にざっと理解する 「 WDM ドライバ開発完全ガイド」を

何となく読めるようになる 自分の理解を深める

Page 5: フィルタドライバ入門

概要 Windows のデバイスドライバについて フィルタドライバの概要、種類、機能

、実装 インストール方法

Page 6: フィルタドライバ入門

デバイスドライバの概要 ←★ フィルタドライバの概要 ドライバとインスタンス IRP フィルタドライバの実装 フィルタドライバの登録 INF ファイル

Page 7: フィルタドライバ入門

デバイスドライバとは デバイスドライバの定義

あるハードウェアを OS から利用可能にするためのソフトウェア(狭義の定義)

デバイスドライバの目的 ハードウェアを抽象化すること

基本的には、それぞれのハードウェアに応じたデバイスドライバが必要となる

Page 8: フィルタドライバ入門

ユーザーランドとカーネル

ユーザー

ユーザーランド

カーネル

デバイス

ユー

ザー

空間

ーネ

ル空

操作

CUI や GUI、 ライブラリ、 アプリケーション

ハードウェア抽象化 ハードウェア毎の 違いを吸収

Page 9: フィルタドライバ入門

デバイスドライバの位置

ユーザー

ユーザーランドAPI kernel32.dll など

カーネルランド本体 ntoskrnl.exe など

デバイス

ユー

ザー

空間

ーネ

ル空

操作

アプリケーション

デバイスドライバ

Page 10: フィルタドライバ入門

実行形式の種類 NT ドライバ

Windows NT 3.1 ~ 4.0 用 Windows Driver Model ( WDM )

Windows 98 および 2000 以降のドライバ Windows 用のドライバの多くがこの形式

WDF Driver Model ユーザーモードのドライバも書ける新形式

Page 11: フィルタドライバ入門

WDM の特長 階層化 雛形を定義することによりデバイスド

ライバ開発を定型化 必要最小限の部分だけ実装することが

できる(ミニポートドライバ、フィルタドライバ)

Page 12: フィルタドライバ入門

WDM の階層例他にも クラスドライバ ミニクラスドライ

バ ポートドライバ ミニポートドライ

バなど色々ある

Lowe r フィルタドライバ

バスドライバ

Ha rdwa re Abs t ra c t ion Laye r(HAL)

ファンクションドライバ

uppe r フィルタドライバ

Page 13: フィルタドライバ入門

デバイスドライバの概要 フィルタドライバの概要 ←★ ドライバとインスタンス IRP フィルタドライバの実装 フィルタドライバの登録 INF ファイル

Page 14: フィルタドライバ入門

フィルタドライバの概要 機能追加のためのデバイスドライバ フル実装ではなく、部分実装

ほとんどの処理を既存のデバイスドライバに任せ、必要な処理だけ行う

デバイスドライバとデバイスドライバの間にはさまる、いわゆる「フック」を行う 加工したり横取りしたりできる

Page 15: フィルタドライバ入門

フックとは

デバイスドライバ A からは、フィルタドライバがデバイスドライバ B に見える

デバイスドライバ B からは、フィルタドライバがデバイスドライバ A に見える

デバイスドライバ A

デバイスドライバ B

デバイスドライバ A

フィルタドライバ

デバイスドライバ B

間にはさむ

Page 16: フィルタドライバ入門

フィルタドライバの例 アンチウィルスソフト

リアルタイムファイルシステム監視 VMware

ホスト OS のキーボード、マウス、ネットワークなど入出力を横取りし、ゲスト OSに流す

葉隠れの術 「 SONYが rootkit 」とネットで話題に

Page 17: フィルタドライバ入門

フィルタドライバの特長 階層化 雛形を定義することによりデバイスド

ライバ開発を定型化 必要最小限の部分だけ実装することが

できる

WDM の特長 ≒ フィルタドライバの特長

Page 18: フィルタドライバ入門

フィルタドライバの配置の種類 Upper と Lower の二種類ある Upper フィルタ

あるデバイスドライバの上位側を乗っ取る Lower フィルタ

あるデバイスドライバの下位側を乗っ取る

Page 19: フィルタドライバ入門

Upper フィルタ あるデバイスドライ

バの上位側に追加する

ユーザーランド側の入出力を乗っ取ることができる

手軽だが、低レベルの操作はできない

バスドライバ

ファンクションドライバ

Uppe r フィルタドライバ

Page 20: フィルタドライバ入門

Lower フィルタ あるデバイスドライ

バの下位側に追加する

低レベル入出力を乗っ取ることができる

細かい操作が可能だが煩雑

バスドライバ

ファンクションドライバ

Lowe r フィルタドライバ

Page 21: フィルタドライバ入門

フィルタドライバの範囲の種類 デバイスに対するフィルタドライバ

例: PS/2 キーボードに対するドライバ 同種のデバイスのみに適用される

例:USB キーボードには適用されない デバイスクラスに対するフィルタドラ

イバ 例:キーボードに対するドライバ そのクラスに属する全デバイスに適用され

る 例: PS/2・USB両方に適用される

Page 22: フィルタドライバ入門

デバイスドライバの概要 フィルタドライバの概要 ドライバとインスタンス ←★ IRP フィルタドライバの実装 フィルタドライバの登録 INF ファイル

Page 23: フィルタドライバ入門

ドライバとインスタンス デバイスドライバ

実行ファイル ドライバオブジェクト

デバイスドライバのインスタンス(通常一つ)

デバイスオブジェクト 個別のデバイスのインスタンス

Page 24: フィルタドライバ入門

ドライバオブジェクト デバイスドライバのインスタンス デバイスドライバが必要になると、

カーネルがロード&実行 システム起動時やデバイスを挿したとき

デバイスドライバのロード =ドライバオブジェクトの生成 DriverEntry 関数が呼び出される

引数はドライバオブジェクト

Page 25: フィルタドライバ入門

デバイスオブジェクト システム起動時やデバイスを挿したとき、デ

バイス毎に(バスドライバ等が)生成する 登録されているデバイスドライバそれぞれが

デバイスオブジェクトを生成する 総数=デバイス数 ×デバイスドライバ数

それぞれのデバイスドライバの AddDevice関数が呼び出される 引数はドライバオブジェクトと、下位のデバイスオブジェクト

Page 26: フィルタドライバ入門

デバイスマネージャで見てみる あるデバイスには複数のデバイスドラ

イバ(フィルタドライバ含む)が登録されている

Page 27: フィルタドライバ入門

レジストリで見てみる( 1 ) PS/2 キーボード

Page 28: フィルタドライバ入門

レジストリで見てみる( 2 ) キーボードクラス

Page 29: フィルタドライバ入門

ドライバ階層例 ドライバがディジーチェーン接続されている

kbdc la s s (クラスドライバ)

i8042prt(ポートドライバ)

Ha rdwa re Abs t ra c t ion Laye r(HAL)

vmkbd(フィルタドライバ)

Page 30: フィルタドライバ入門

インスタンスの生成順序

kbdc la s s の ドライバオブジェクト

i8042prt の ドライバオブジェクト

vmkbd の ドライバオブジェクト

デバイス オブジェクト

②通知

デバイス オブジェクト

③生成

④連結

デバイス オブジェクト

①生成

⑤通知

⑥生成

⑦連結

Page 31: フィルタドライバ入門

フィルタドライバの優先順位 Lower DO→FDO→Upper DO の順に生成 (対クラスよりも)デバイスに対する

フィルタドライバが先にインスタンス化される

同種では記述順にインスタンス化される

Page 32: フィルタドライバ入門

フィルタドライバのリンク 次のようなリンクを形成する(はず)

上位(ユーザー空間) → クラスの Upper B → クラスの Upper A → デバイスの Upper B → デバイスの Upper A → FDO → クラスの Lower B → クラスの Lower A → デバイスの Lower B → デバイスの Lower A → PDO → 下位( HAL )

生成は上記の逆順(デバイスの Lower から)

Page 33: フィルタドライバ入門

デバイスドライバの概要 フィルタドライバの概要 ドライバとインスタンス IRP ←★ フィルタドライバの実装 フィルタドライバの登録 INF ファイル

Page 34: フィルタドライバ入門

IRP の概要 IRP

I/O Request Packet 何らかのイベントが発生することによ

り生成され、デバイスオブジェクトに伝達される指示パケット

Read 、 Write 、 Plug&Play など、様々な内容のメッセージが定義されている

Page 35: フィルタドライバ入門

IRP の処理イメージ 上位のデバイス

オブジェクトが、下位のデバイスオブジェクトへ IRP を伝播させていく

デバイスオブジェクトA

IRP

イベント 発生 生成

IRP

デバイスオブジェクトB

Page 36: フィルタドライバ入門

IRP のスタック領域

IRP

デバイスオブジェクトY

デバイスオブジェクトZ

デバイスオブジェクトX

A 用のスタック領域

IRP 内の自分用の領域に アクセスし、次の階層へ 伝播させていく

B 用のスタック領域

C 用のスタック領域

ドライバオブジェクトA

ドライバオブジェクトB

ドライバオブジェクトC

Page 37: フィルタドライバ入門

概要編終了 すいませんがあと 90 枚あります

Page 38: フィルタドライバ入門

デバイスドライバの概要 フィルタドライバの概要 ドライバとインスタンス IRP フィルタドライバの実装 ←★ フィルタドライバの登録 INF ファイル

Page 39: フィルタドライバ入門

開発に必要な環境( 1 ) DDK

Windows 2000 で開発できる Vista 用のドライバが書けない

WDK Windows XP 以降で開発できる 2000/XP/Vista のドライバ開発が可能

WinDbg なくても開発は可能、あると便利

Page 40: フィルタドライバ入門

開発に必要な環境( 2 ) VMware ホスト+ VMware ゲスト

1 台の PC で開発とテスト実行が可能 named pipe 経由で WinDbg 接続 デバイスドライバの種類によっては開発不

能 二台の PC (開発機と実験機)

シリアルクロスケーブル経由で WinDbg 接続

最終的には実機での検証が必要

Page 41: フィルタドライバ入門

最小限の実装 単純なフィルタドライバは以下の処理

だけで OK 初期化( DriverEntry/DriverUnload ) デバイスの追加( AddDevice ) IRP ハンドラ

ファイルシステム等はもっと複雑

Page 42: フィルタドライバ入門

DriverEntry の概要 ドライバのロード完了時に呼び出され

る WinMain() や DllMain() に相当 この関数だけあればビルドはできる

引数はドライバオブジェクトとレジストリのパス

主な責務は、 AddDevice や IRP ハンドラ等関数ポインタをドライバオブジェクトに設定すること

Page 43: フィルタドライバ入門

余談 1 :エントリポイント PE ヘッダにアドレスが記録されている

手動リンクするならシンボルは何でもよい

Page 44: フィルタドライバ入門

余談 2 : GsDriverEntry /GS オプションありでビルドした場合

( WDK 以降のデフォルト)のエントリポイント /GS つきだとスタックチェックのコードが

生成 ドライバファイルのエントリポイントに

GsDriverEntry のアドレスが入る GsDriverEntry 内で DriverEntry へジャンプ

sources での設定で無効化できる BUFFER_OVERFLOW_CHECKS=0

詳しくは web で

Page 45: フィルタドライバ入門

DriverEntry の例 NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,

IN PUNICODE_STRING RegistryPath) {

int i; for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; ++i) {

DriverObject->MajorFunction[i] = OtherDispatch; } DriverObject->MajorFunction[IRP_MJ_POWER] = PowerDispatch; DriverObject->MajorFunction[IRP_MJ_PNP] = PnPDispatch; DriverObject->DriverStartIo = NULL; DriverObject->DriverUnload = DriverUnload; DriverObject->DriverExtension->AddDevice = AddDevice; return STATUS_SUCCESS;

}

Page 46: フィルタドライバ入門

DriverUnload 静的に確保しているものがなければ空

で OK 管理しているデバイスオブジェクトが

ゼロになると呼び出される デバイスオブジェクトを静的に確保してい

ると自動的にはアンロードされない static void DriverUnload(IN PDRIVER_OBJECT DriverObject) { }

Page 47: フィルタドライバ入門

AddDevice の概要 デバイスが接続された時に呼び出され

る 接続=デバイスオブジェクトの生成

引数はドライバオブジェクトと、自分の下位となるデバイスオブジェクト

下位のデバイスオブジェクト 通常はバスドライバ(のドライバオブジェ

クト)が生成したもの 通称 PDO ( Physical Device Object )

Page 48: フィルタドライバ入門

典型的な AddDevice の処理 新しいデバイスオブジェクト objを生成

する objのメンバーを初期化する

RemoveLock の初期化など objを PDO にアタッチする

アタッチすると、下位のデバイスオブジェクト(ポインタ)が得られる

Page 49: フィルタドライバ入門

アタッチ IoAttachDeviceToDeviceStack ()に

よってデバイスオブジェクトのチェーンに追加する IRP を受け取れるようになる

PDO

生成したデバイス オブジェクト

PDO

アタッチ

Page 50: フィルタドライバ入門

IRP ハンドラの概要 特定の種類の IRP を処理する関数 いずれかのパターン

IRP毎に関数を用意する 一つの関数で共通処理を行い、関数内で

IRP の種類で分岐する 電源管理と PnP ( Plug&Play )は他の

IRP と処理が異なるので、別の関数にすることが多い

Page 51: フィルタドライバ入門

上位と下位 自分の上位と下位がある 上位= I/Oマネージャや、自分へアタッ

チしたデバイスオブジェクト 上位から IRP が送られてくる

下位=自分がアタッチしたデバイスオブジェクト IRP を送信することができる

Page 52: フィルタドライバ入門

IRP ハンドラの責務 自分の上位( IRP の送信元)に対して

、処理結果をステータスとして返す 自前で IRP を処理するか、下位で処理

してもらうかを決める 自分で処理しない場合は、下位に IRP

を渡し、その処理結果を上位に返す

Page 53: フィルタドライバ入門

フィルタドライバの IRP 処理 基本は「何もしないフィルタドライ

バ」 ここでいう「何もしない」とは、上位

から受け取った IRP を、加工せずに下位に渡すこと いわゆるスルー出力

下位に対して、特定の IRP を渡さないことにより、機能を無効化できる(例:書込禁止)

Page 54: フィルタドライバ入門

IRP ハンドラの定石 いくつかの処理パターンがある

自分で処理する・しない 下位に渡す・渡さない 下位の処理が終わるのを待つ・待たない

Microsoft KB「 IRP のさまざまな処理方法」 http://support.microsoft.com/kb/320275/ja

Page 55: フィルタドライバ入門

シナリオ 1 :スルー出力 上位から受け取った IRP を下位に渡し

、下位の処理結果を上位に返す(丸投げ)

static NTSTATUS OtherDispatch(IN PDEVICE_OBJECT DeviceObject,

IN PIRP Irp) {

DEVICE_EXTENSION *Extension = (DEVICE_EXTENSION *)DeviceObject->DeviceExtension;

IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(Extension->NextLowerDriver, Irp);

}

Page 56: フィルタドライバ入門

シナリオ 1 の用途 「何もしない」=もらったものを中継

する 「何も足さない、何も引かない」

「どの IRP が」「いつ」あったかを監視できる デバッグ出力、ロギング

その IRP の処理結果(いつ完了し、どういう結果が得られたか)は、シナリオ 1 ではわからない

Page 57: フィルタドライバ入門

シナリオ 2 :同期して待つ IRP を下位に渡し、処理が終わるまで

待ち、結果を上位に返す(※ 下記は抜粋)

static NTSTATUS CompletionRoutine(DeviceObject, Irp, Event) {

KeSetEvent(Event, IO_NO_INCREMENT, FALSE); } NTSTATUS OtherDispatch(DeviceObject, Irp) {

KeInitializeEvent(&Event, NotificationEvent, FALSE); IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp, CompletionRoutine, &Event, …); status = IoCallDriver(Extension->NextLowerDriver, Irp); KeWaitForSingleObject(&Event, Executive, KernelMode); IoCompleteRequest (Irp, IO_NO_INCREMENT); return status;

}

Page 58: フィルタドライバ入門

シナリオ 2 の用途 処理の完了を待つものに使用する

典型的な使用例は、デバイスの使用開始待ち( IRP_MN_START_DEVICE )

完了するまで上位に制御を返さない KeWaitForSingleObject ()で待つと、他の IRP ディスパッチ処理も停止する(かも) そのため、下位の処理が短時間に終わらな

い IRP には適用すべきでない

Page 59: フィルタドライバ入門

シナリオ 3:処理完了時に通知 IRP を下位に渡し、完了時に通知して

もらう (通常、下位が非同期処理をするため)同

期的に待たない static NTSTATUS CompletionRoutine(DeviceObject, Irp, Event) {

if (Irp->PendingReturned) IoMarkIrpPending(Irp); return STATUS_CONTINUE_COMPLETION;

} NTSTATUS OtherDispatch(DeviceObject, Irp) {

IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp, CompletionRoutine, NULL, …); return IoCallDriver(Extension->NextLowerDriver, Irp);

}

Page 60: フィルタドライバ入門

シナリオ 3の用途 下位の処理結果( I/O読み込みの結果

等)を加工したい場合に使える シナリオ 2 は処理完了まで上位をブ

ロックするが、シナリオ 3だと下位が非同期処理をしていれば上位に制御が戻る

明示的に非同期処理をしたい場合はシナリオ 4にする

Page 61: フィルタドライバ入門

シナリオ 4: IRP をキューに入れる 上位に pending を通知し、後で処理す

る NTSTATUS CompletionRoutine(DeviceObject, Irp, Event) {

return STATUS_CONTINUE_COMPLETION; } NTSTATUS OtherDispatch(DeviceObject, Irp) {

NTSTATUS status; IoMarkIrpPending(Irp); IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp, CompletionRoutine, NULL, …); IoCallDriver(Extension->NextLowerDriver, Irp); return STATUS_PENDING;

}

Page 62: フィルタドライバ入門

シナリオ 4の用途 その IRP を別のスレッドで処理したい

場合に使用する 非同期処理を行う場合、他のスレッド

との競合を考慮したコードを書く必要がある スピンロックによる排他制御や、他のス

レッドによって IRP がキャンセルされたかどうかのチェック等

Page 63: フィルタドライバ入門

シナリオ 5:下位に渡さない IRP を処理完了に設定する

static NTSTATUS OtherDispatch(IN PDEVICE_OBJECT DeviceObject,

IN PIRP Irp) {

// なにがしかの処理

NTSTATUS status = …; ULONG_PTR info = …;

Irp->IoStatus.Status = status; Irp->IoStatus.Information = info; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status;

}

Page 64: フィルタドライバ入門

シナリオ 5の用途 フィルタドライバで追加実装した機能

など、自分で処理する必要がある IRPの場合 独自の DeviceIoControl など

特定の機能を上書きしたり禁止できる 例:ある条件下では書き込みを禁止する

Page 65: フィルタドライバ入門

BSoD BlueScreen of Death (死の青画面) デバイスドライバのバグやメモリエ

ラー等で発生 デバッガ接続している場合は BSoD は

表示されず、デバッガプロンプトになる

BSoD 発生時、クラッシュダンプに追加情報を格納することも可能

Page 66: フィルタドライバ入門

余談:色を変える BSOD Properties NT

Page 67: フィルタドライバ入門

実行レベル カーネル空間では、スレッドの実行レ

ベルが状況に応じて動的に変化する 割り込み処理などで一時的に高くなる

ユーザープロセスの優先度とはまた別 全ユーザープロセスよりもカーネルが優先

フィルタドライバで使う実行レベルは主に以下の 2 レベル 高= DISPATCH_LEVEL 低= PASSIVE_LEVEL

Page 68: フィルタドライバ入門

ページング ページング=ページを 1 単位としたメ

モリブロックを外部記憶装置( HDD )へ追い出す スワップ=プロセス単位( IT 用語辞典)

デバイスドライバのソースコードにおいて、ある関数または変数がページング可能かどうかを指定できる 指定方法はコードとデータで異なる 確保時に固定(動的に変化しない)

Page 69: フィルタドライバ入門

DISPATCH_LEVEL 実行優先度が高く、処理の自由度が低

い 応答性が必要な処理などで使用する

DPC ( Deferred Procedure Call )など ページングしない(できない)

ページアウトされた領域にアクセスするとBSoD

ページアウトを伴う可能性のある関数は呼び出せない

Page 70: フィルタドライバ入門

PASSIVE_LEVEL 実行優先度が低く、処理の自由度が高

い 応答性が不要の処理を記述する

IRP のディスパッチなど ページングする(できる)

ページアウトされた領域にアクセスするとページインする( BSoD にならない)

DISPATCH_LEVEL でないと呼び出せない関数は、一時的に実行レベルを上げて呼び出す

Page 71: フィルタドライバ入門

non-paged ページング不可、通称「非ページ」 メモリが不足してもページアウトされ

ない ページング指定がないものはページン

グ不可になる システム全体のパフォーマンスに影響

するので、必要最小限に抑える PASSIVE_LEVEL でも使える

Page 72: フィルタドライバ入門

paged ページング可、通称「ページ」 ページアウトされる可能性がある ユーザー空間のプログラムと同じレベ

ルのリソース DISPATCH_LEVEL では使えない

Page 73: フィルタドライバ入門

コードのページング指定 関数宣言のあとに pragma で指定

#pragma alloc_text(INIT, DriverEntry) #pragma alloc_text(PAGE, DriverUnload)

ページング可である関数に「 PAGE 」を指定する

初期化時しか使わないコード( DriverEntry )には INIT を指定する 初期化処理の完了後、解放される

Page 74: フィルタドライバ入門

PAGED_CODE () ページング可能な領域に配置された

コードであることを示すマクロ PASSIVE_LEVEL で実行されるべきという

印 実行時のチェック

PASSIVE_LEVEL よりも高い優先度で実行されると警告をデバッグ出力

Page 75: フィルタドライバ入門

データのページ指定 ページ可能ヒープから確保

ExAllocatePoolWithTag ( PagedPool ) 非ページヒープから確保

ExAllocatePoolWithTag ( NonPagedPool)

#pragma data_seg ()でデータをページング可能領域( PAGE セクション)に置けるが、データだけ別ファイルにする必要がある

Page 76: フィルタドライバ入門

ページング指定とセクション ページング不可のコードは .text セク

ションに入る ページング不可のデータは .data

や .rodata セクションに入る ページング可のデータは PAGE セク

ションに入る リスティングファイルや IDA Pro でわ

かる

Page 77: フィルタドライバ入門

豆知識: pageable ページ可能は「 pageable 」 でもなぜか DO_POWER_PAGABLE と

…いう定義が

Page 78: フィルタドライバ入門

デバイスドライバの概要 フィルタドライバの概要 ドライバとインスタンス IRP フィルタドライバの実装 フィルタドライバの登録 ←★ INFファイル

Page 79: フィルタドライバ入門

フィルタドライバの登録( 1 ) デバイスドライバとしてインストール

しておく Win32API の CreateService()

レジストリエントリに追加する Upper フィルタの場合:値 UpperFilters Lower フィルタの場合:値 LowerFilters 値はMULTI_SZ型 複数登録できる

Page 80: フィルタドライバ入門

フィルタドライバの登録( 2 ) デバイスに対するフィルタドライバの

追加 Win32API の

SetupDiSetDeviceRegistryProperty() を使用して登録する

レジストリエントリHKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum 以下に登録される(レジストリエディタでは読み取りのみ可能)

Page 81: フィルタドライバ入門

フィルタドライバの登録( 3) デバイスクラスに対するフィルタドラ

イバの追加 HKEY_LOCAL_MACHINE\SYSTEM\Curre

ntControlSet\Control\Class\{CLASS_GUID}以下を、レジストリ操作関数で設定する

RegOpenKeyEx() 、 RegSetValueEx()

Page 82: フィルタドライバ入門

フィルタドライバの削除 SetupDiGetDeviceRegistryProperty() または

RegQueryValueEx() により既存の値を読み取る

MULTI_SZ型の値から、対象文字列を削除する

SetupDiSetDeviceRegistryProperty() またはRegSetValueEx() により値を設定する

DeleteService() によりデバイスドライバの登録を削除する

Page 83: フィルタドライバ入門

GUI で設定 DevFilterEditor

Page 84: フィルタドライバ入門

デバイスドライバの概要 フィルタドライバの概要 ドライバとインスタンス IRP フィルタドライバの実装 フィルタドライバの登録 INF ファイル ←★

Page 85: フィルタドライバ入門

INFファイル 謎の書式でインストール情報を記述す

る devcon.exe 等からインストールすると

きや、カタログファイル( .CAT )を作るのに必要

GenINFである程度は作れる ただしWDK 6001 には存在しない

ChkINFでチェックできる 実態は Perl スクリプト

Page 86: フィルタドライバ入門

GenINF( 1 ) general info.

Page 87: フィルタドライバ入門

GenINF( 2 ) add files

アーキテクチャの指定

Page 88: フィルタドライバ入門

GenINF( 3 ) specific info.

Page 89: フィルタドライバ入門

GenINF( 4 ) bus types

Page 90: フィルタドライバ入門

GenINF( 5 ) x86 specific

Page 91: フィルタドライバ入門

GenINF( 6 ) service info.

Page 92: フィルタドライバ入門

GenINF( 7 ) IA64 specific

Page 93: フィルタドライバ入門

GenINF( 8 ) class specific info.

Page 94: フィルタドライバ入門

GenINF( 9 ) done!

Page 95: フィルタドライバ入門

…しかしながら そのままでは使えないので INFファイ

ルを修正する必要がある 近い動作のドライバの INFファイルを見るのが手っ取り早い

WDKのサンプルの INFファイルを改造して挙動を確かめる 記述が間違っているとインストールできな

Page 96: フィルタドライバ入門

デコレーション プラットフォーム毎(例えば x86と

x64)で、インストール先やインストールするファイルを変えたい場合に指定する 例:「 x86」「 NTamd64」

Windows XP 以前( 95/98/2000)の .INFは下位互換性維持のためひどい書式だったが、 XP 以降はデコレーションのおかげでシンプルになった

Page 97: フィルタドライバ入門

DriverVer 「 DriverVer= 5/1/2009 」の行を 「 DriverVer= 05/01/2009,1.0.0.1 」の

ように修正(一桁の数字はゼロで埋める) そのままだと signability に怒られる

Page 98: フィルタドライバ入門

[Manufacturer] ( 1 ) INF ファイルに含まれる製造元(ベン

ダー)の一覧を記述する それぞれのハードウェアは、ベンダー毎の

セクションで指定 プラットフォーム毎にインストール動

作を記述したい場合、 [Manufacturer]セクションにデコレーションを追記する 配布ファイルだけ異なるような場合には不

Page 99: フィルタドライバ入門

[Manufacturer] ( 2 ) x64 ( AMD64/Intel64 )に対応させた

い場合

[Manufacturer] %HOGE%=HOGE,NTamd64[HOGE.NTamd64]…

Page 100: フィルタドライバ入門

[Manufacturer] ( 3 ) Itanium に対応させたい場合

[Manufacturer] %HOGE%=HOGE,NTia64[HOGE.NTia64]…

Page 101: フィルタドライバ入門

[Manufacturer] ( 4 ) StrongARM アーキテクチャ( Intel

XScale )に対応させたい場合

[Manufacturer] %HOGE%=HOGE,SA[HOGE.SA]…

Page 102: フィルタドライバ入門

[Manufacturer] ( 5 ) SH アーキテクチャ( SH-3 、 SH-4 )

に対応させたい場合

[Manufacturer] %HOGE%=HOGE,SH[HOGE.SH]…

Page 103: フィルタドライバ入門

[Manufacturer] ( 6 ) MIPS アーキテクチャに対応させたい場

[Manufacturer] %HOGE%=HOGE,MIPS[HOGE.MIPS]…

Page 104: フィルタドライバ入門

[Manufacturer] ( 7 ) PowerPC アーキテクチャに対応させた

い場合

[Manufacturer] %HOGE%=HOGE,PPC[HOGE.PPC]…

Page 105: フィルタドライバ入門

[Manufacturer] ( 8 ) Alpha アーキテクチャに対応させたい場

[Manufacturer] %HOGE%=HOGE,Alpha[HOGE.Alpha]…

Page 106: フィルタドライバ入門

[Manufacturer] ( 9 ) Alpha AXP アーキテクチャに対応させ

たい場合

[Manufacturer] %HOGE%=HOGE,axp64[HOGE.axp64]…

Page 107: フィルタドライバ入門

ちなみに Windows XP は x86 版と x64 版しかリ

リースされていません

Alpha 版は beta すら出ていません

Page 108: フィルタドライバ入門

[SourceDisksNames] ファイルのコピー元のディレクトリ指

定 書式

disk_id_num = ,"label",,pathdisk_id_num は 1 以上で自分で定義する

デコレーションにより、アーキテクチャ毎にバイナリを用意できる

Page 109: フィルタドライバ入門

[DestinationDirs] ファイルのコピー先を drid で指定する

http://msdn.microsoft.com/en-us/library/ms790174.aspx 例: DefaultDestDir = 12

ドライバなら「 12 」 10 → C:\Windows 11 → C:\Windows\System32 12 → C:\Windows\System32\drivers

Page 110: フィルタドライバ入門

[ ~ _Inst.NTx86.HW.AddReg] レジストリに追加する値の指定

例:HKR,,"UpperFilters",0x00010008,"Hoge"

値の型に注意 MULTI_SZ ( 0x10000 )だと既存の値を

上書きする(既存のフィルタドライバを無効にする)

0x10008 → MULTI_SZ 型で追記

Page 111: フィルタドライバ入門

CAT ファイル カテゴリファイル INF ファイルから生成するバイナリ

ファイル デジタル署名可能 signability.exe などを利用して生成する

Page 112: フィルタドライバ入門

signability で .cat を生成 signability.exe /cat /driver:<INF ファイ

ルのあるフォルダのフルパス > /os:OS値 OS 値には、 OS に対応する数値の論理和

か、文字列( Windows_XP など) Windows 2000 … 2 Windows XP 32bit … 8 Windows Vista 32bit … 256

Page 113: フィルタドライバ入門

デジタル署名( 1 ) Vista 64bit では必須

Microsoft による署名のないドライバはロードできない

フィルタドライバがロードできないと、そのデバイスが使用不可能になる

Page 114: フィルタドライバ入門

デジタル署名( 2 ) 正式な証明書の場合

Verisign などから購入し、 Microsoft のクロス証明書を生成する

CrystalCPUID のブログなどを参照 オレオレ証明書の場合

適当な証明書を発行し、「信頼できるルート証明書」に格納する

テストモードでないとロードできない

Page 115: フィルタドライバ入門

signtool で署名 証明書の作り方は省略 詳しくは KMCS_Walkthrough.doc を参

照 http://www.microsoft.com

/whdc/winlogo/drvsign/kmcs_walkthrough.mspx

例: Hoge.cat を PrivateCertStore に格納してある証明書 HogeInc で署名する

signtool.exe sign /v /s PrivateCertStore /n HogeInc /t http://timestamp.verisign.com/scripts/timestamp.dll Hoge.cat

Page 116: フィルタドライバ入門

インストール devcon.exe でインストール可能

INF ファイルとハードウェア ID を指定する

devcon.exe install Hoge.inf *PNP0FAKE 謎のデバイスを強制的にインストール

する方法のため、不明なデバイスが追加される 削除してよい

Page 117: フィルタドライバ入門

余談: GNU make NMAKE 用の MAKEFILE が存在してい

る しかもMAKEFILE は「 DO NOT

EDIT 」 GNU make が使いたい

→ GNUMakefile というファイル名にする

Page 118: フィルタドライバ入門

DEMO1 : PassFilter 何もしないフィルタドライバ IRP をデバッグ出力

Page 119: フィルタドライバ入門

DEMO2 : SwapFilter キーボードの L キーと R キーを入れ替え

マウスの左クリックと右クリックを入れ替え

Scroll Lock を押すと BSoD

Page 120: フィルタドライバ入門

入れ替えの実装方法 Lower フィルタの場合

クラスドライバの配下に入る クラスドライバが提供するサービスコール

バックを利用する Upper フィルタの場合

ユーザーランドとクラスドライバとの間に入る

ユーザーランドとの入出力を加工できる

Page 121: フィルタドライバ入門

実装部 L の scan code= 0x26 R の scan code= 0x13 Scroll Lock の scan code= 0x46

if (Buffer[0].MakeCode == 0x26) { Buffer[0].MakeCode = 0x13; } else if (Buffer[0].MakeCode == 0x13) { Buffer[0].MakeCode = 0x26; } else if (Buffer[0].MakeCode == 0x46) { char *p = NULL; *p = 0; }

Page 122: フィルタドライバ入門

参考書籍 WindowsXP フィルタドライバプログラミング

Microsoft WDM プログラミング WDM デバイスドライバプログラミング完全ガイド

Windows NT ファイルシステム詳説

Page 123: フィルタドライバ入門

フィルタドライバプログラミング

絶版 入門書 評判はいまいち USBのフィルタドライバを

書くなら参考になる

Page 124: フィルタドライバ入門

Microsoft WDM プログラミング

良書 サンプルが豊富 Visual C++用の Wizardつ

Page 125: フィルタドライバ入門

WDM ~完全ガイド ソースコードなし どちらかというとリファレ

ンス的 概要を把握した上で、より深く理解するのに使える

Page 126: フィルタドライバ入門

NT ファイルシステム詳説 絶版 重厚 NT 用なので古い ファイルシステム周りとし

ては唯一の日本語書籍 ヤフオクで 3万円くらい

Page 127: フィルタドライバ入門

Thank you! ご意見ご質問があればお願いします