フィルタドライバ入門
TRANSCRIPT
フィルタドライバ入門
firewood@hatenahotpepsi@twitter
自己紹介 生息地
組込日記 http://d.hatena.ne.jp/firewood/ よく使う環境
Windows 、 Linux 、 Flash 、 C/C++ 、 x86 、 ARM
趣味 エンバグ、デバッグ キーボード蒐集
はじめに 書籍、 WDK 、 web の情報を元に記述
していますが、間違いがあれば教えてください
目的 ユーザー空間からカーネル空間まで全
体的にざっと理解する 「 WDM ドライバ開発完全ガイド」を
何となく読めるようになる 自分の理解を深める
概要 Windows のデバイスドライバについて フィルタドライバの概要、種類、機能
、実装 インストール方法
デバイスドライバの概要 ←★ フィルタドライバの概要 ドライバとインスタンス IRP フィルタドライバの実装 フィルタドライバの登録 INF ファイル
デバイスドライバとは デバイスドライバの定義
あるハードウェアを OS から利用可能にするためのソフトウェア(狭義の定義)
デバイスドライバの目的 ハードウェアを抽象化すること
基本的には、それぞれのハードウェアに応じたデバイスドライバが必要となる
ユーザーランドとカーネル
ユーザー
ユーザーランド
カーネル
デバイス
ユー
ザー
空間
カ
ーネ
ル空
間
操作
CUI や GUI、 ライブラリ、 アプリケーション
ハードウェア抽象化 ハードウェア毎の 違いを吸収
デバイスドライバの位置
ユーザー
ユーザーランドAPI kernel32.dll など
カーネルランド本体 ntoskrnl.exe など
デバイス
ユー
ザー
空間
カ
ーネ
ル空
間
操作
アプリケーション
デバイスドライバ
実行形式の種類 NT ドライバ
Windows NT 3.1 ~ 4.0 用 Windows Driver Model ( WDM )
Windows 98 および 2000 以降のドライバ Windows 用のドライバの多くがこの形式
WDF Driver Model ユーザーモードのドライバも書ける新形式
WDM の特長 階層化 雛形を定義することによりデバイスド
ライバ開発を定型化 必要最小限の部分だけ実装することが
できる(ミニポートドライバ、フィルタドライバ)
WDM の階層例他にも クラスドライバ ミニクラスドライ
バ ポートドライバ ミニポートドライ
バなど色々ある
Lowe r フィルタドライバ
バスドライバ
Ha rdwa re Abs t ra c t ion Laye r(HAL)
ファンクションドライバ
uppe r フィルタドライバ
デバイスドライバの概要 フィルタドライバの概要 ←★ ドライバとインスタンス IRP フィルタドライバの実装 フィルタドライバの登録 INF ファイル
フィルタドライバの概要 機能追加のためのデバイスドライバ フル実装ではなく、部分実装
ほとんどの処理を既存のデバイスドライバに任せ、必要な処理だけ行う
デバイスドライバとデバイスドライバの間にはさまる、いわゆる「フック」を行う 加工したり横取りしたりできる
フックとは
デバイスドライバ A からは、フィルタドライバがデバイスドライバ B に見える
デバイスドライバ B からは、フィルタドライバがデバイスドライバ A に見える
デバイスドライバ A
デバイスドライバ B
デバイスドライバ A
フィルタドライバ
デバイスドライバ B
間にはさむ
フィルタドライバの例 アンチウィルスソフト
リアルタイムファイルシステム監視 VMware
ホスト OS のキーボード、マウス、ネットワークなど入出力を横取りし、ゲスト OSに流す
葉隠れの術 「 SONYが rootkit 」とネットで話題に
フィルタドライバの特長 階層化 雛形を定義することによりデバイスド
ライバ開発を定型化 必要最小限の部分だけ実装することが
できる
WDM の特長 ≒ フィルタドライバの特長
フィルタドライバの配置の種類 Upper と Lower の二種類ある Upper フィルタ
あるデバイスドライバの上位側を乗っ取る Lower フィルタ
あるデバイスドライバの下位側を乗っ取る
Upper フィルタ あるデバイスドライ
バの上位側に追加する
ユーザーランド側の入出力を乗っ取ることができる
手軽だが、低レベルの操作はできない
バスドライバ
ファンクションドライバ
Uppe r フィルタドライバ
Lower フィルタ あるデバイスドライ
バの下位側に追加する
低レベル入出力を乗っ取ることができる
細かい操作が可能だが煩雑
バスドライバ
ファンクションドライバ
Lowe r フィルタドライバ
フィルタドライバの範囲の種類 デバイスに対するフィルタドライバ
例: PS/2 キーボードに対するドライバ 同種のデバイスのみに適用される
例:USB キーボードには適用されない デバイスクラスに対するフィルタドラ
イバ 例:キーボードに対するドライバ そのクラスに属する全デバイスに適用され
る 例: PS/2・USB両方に適用される
デバイスドライバの概要 フィルタドライバの概要 ドライバとインスタンス ←★ IRP フィルタドライバの実装 フィルタドライバの登録 INF ファイル
ドライバとインスタンス デバイスドライバ
実行ファイル ドライバオブジェクト
デバイスドライバのインスタンス(通常一つ)
デバイスオブジェクト 個別のデバイスのインスタンス
ドライバオブジェクト デバイスドライバのインスタンス デバイスドライバが必要になると、
カーネルがロード&実行 システム起動時やデバイスを挿したとき
デバイスドライバのロード =ドライバオブジェクトの生成 DriverEntry 関数が呼び出される
引数はドライバオブジェクト
デバイスオブジェクト システム起動時やデバイスを挿したとき、デ
バイス毎に(バスドライバ等が)生成する 登録されているデバイスドライバそれぞれが
デバイスオブジェクトを生成する 総数=デバイス数 ×デバイスドライバ数
それぞれのデバイスドライバの AddDevice関数が呼び出される 引数はドライバオブジェクトと、下位のデバイスオブジェクト
デバイスマネージャで見てみる あるデバイスには複数のデバイスドラ
イバ(フィルタドライバ含む)が登録されている
レジストリで見てみる( 1 ) PS/2 キーボード
レジストリで見てみる( 2 ) キーボードクラス
ドライバ階層例 ドライバがディジーチェーン接続されている
kbdc la s s (クラスドライバ)
i8042prt(ポートドライバ)
Ha rdwa re Abs t ra c t ion Laye r(HAL)
vmkbd(フィルタドライバ)
インスタンスの生成順序
kbdc la s s の ドライバオブジェクト
i8042prt の ドライバオブジェクト
vmkbd の ドライバオブジェクト
デバイス オブジェクト
②通知
デバイス オブジェクト
③生成
④連結
デバイス オブジェクト
①生成
⑤通知
⑥生成
⑦連結
フィルタドライバの優先順位 Lower DO→FDO→Upper DO の順に生成 (対クラスよりも)デバイスに対する
フィルタドライバが先にインスタンス化される
同種では記述順にインスタンス化される
フィルタドライバのリンク 次のようなリンクを形成する(はず)
上位(ユーザー空間) → クラスの Upper B → クラスの Upper A → デバイスの Upper B → デバイスの Upper A → FDO → クラスの Lower B → クラスの Lower A → デバイスの Lower B → デバイスの Lower A → PDO → 下位( HAL )
生成は上記の逆順(デバイスの Lower から)
デバイスドライバの概要 フィルタドライバの概要 ドライバとインスタンス IRP ←★ フィルタドライバの実装 フィルタドライバの登録 INF ファイル
IRP の概要 IRP
I/O Request Packet 何らかのイベントが発生することによ
り生成され、デバイスオブジェクトに伝達される指示パケット
Read 、 Write 、 Plug&Play など、様々な内容のメッセージが定義されている
IRP の処理イメージ 上位のデバイス
オブジェクトが、下位のデバイスオブジェクトへ IRP を伝播させていく
デバイスオブジェクトA
IRP
イベント 発生 生成
IRP
デバイスオブジェクトB
IRP のスタック領域
IRP
デバイスオブジェクトY
デバイスオブジェクトZ
デバイスオブジェクトX
A 用のスタック領域
IRP 内の自分用の領域に アクセスし、次の階層へ 伝播させていく
B 用のスタック領域
C 用のスタック領域
ドライバオブジェクトA
ドライバオブジェクトB
ドライバオブジェクトC
概要編終了 すいませんがあと 90 枚あります
デバイスドライバの概要 フィルタドライバの概要 ドライバとインスタンス IRP フィルタドライバの実装 ←★ フィルタドライバの登録 INF ファイル
開発に必要な環境( 1 ) DDK
Windows 2000 で開発できる Vista 用のドライバが書けない
WDK Windows XP 以降で開発できる 2000/XP/Vista のドライバ開発が可能
WinDbg なくても開発は可能、あると便利
開発に必要な環境( 2 ) VMware ホスト+ VMware ゲスト
1 台の PC で開発とテスト実行が可能 named pipe 経由で WinDbg 接続 デバイスドライバの種類によっては開発不
能 二台の PC (開発機と実験機)
シリアルクロスケーブル経由で WinDbg 接続
最終的には実機での検証が必要
最小限の実装 単純なフィルタドライバは以下の処理
だけで OK 初期化( DriverEntry/DriverUnload ) デバイスの追加( AddDevice ) IRP ハンドラ
ファイルシステム等はもっと複雑
DriverEntry の概要 ドライバのロード完了時に呼び出され
る WinMain() や DllMain() に相当 この関数だけあればビルドはできる
引数はドライバオブジェクトとレジストリのパス
主な責務は、 AddDevice や IRP ハンドラ等関数ポインタをドライバオブジェクトに設定すること
余談 1 :エントリポイント PE ヘッダにアドレスが記録されている
手動リンクするならシンボルは何でもよい
余談 2 : GsDriverEntry /GS オプションありでビルドした場合
( WDK 以降のデフォルト)のエントリポイント /GS つきだとスタックチェックのコードが
生成 ドライバファイルのエントリポイントに
GsDriverEntry のアドレスが入る GsDriverEntry 内で DriverEntry へジャンプ
sources での設定で無効化できる BUFFER_OVERFLOW_CHECKS=0
詳しくは web で
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;
}
DriverUnload 静的に確保しているものがなければ空
で OK 管理しているデバイスオブジェクトが
ゼロになると呼び出される デバイスオブジェクトを静的に確保してい
ると自動的にはアンロードされない static void DriverUnload(IN PDRIVER_OBJECT DriverObject) { }
AddDevice の概要 デバイスが接続された時に呼び出され
る 接続=デバイスオブジェクトの生成
引数はドライバオブジェクトと、自分の下位となるデバイスオブジェクト
下位のデバイスオブジェクト 通常はバスドライバ(のドライバオブジェ
クト)が生成したもの 通称 PDO ( Physical Device Object )
典型的な AddDevice の処理 新しいデバイスオブジェクト objを生成
する objのメンバーを初期化する
RemoveLock の初期化など objを PDO にアタッチする
アタッチすると、下位のデバイスオブジェクト(ポインタ)が得られる
アタッチ IoAttachDeviceToDeviceStack ()に
よってデバイスオブジェクトのチェーンに追加する IRP を受け取れるようになる
PDO
生成したデバイス オブジェクト
PDO
アタッチ
IRP ハンドラの概要 特定の種類の IRP を処理する関数 いずれかのパターン
IRP毎に関数を用意する 一つの関数で共通処理を行い、関数内で
IRP の種類で分岐する 電源管理と PnP ( Plug&Play )は他の
IRP と処理が異なるので、別の関数にすることが多い
上位と下位 自分の上位と下位がある 上位= I/Oマネージャや、自分へアタッ
チしたデバイスオブジェクト 上位から IRP が送られてくる
下位=自分がアタッチしたデバイスオブジェクト IRP を送信することができる
IRP ハンドラの責務 自分の上位( IRP の送信元)に対して
、処理結果をステータスとして返す 自前で IRP を処理するか、下位で処理
してもらうかを決める 自分で処理しない場合は、下位に IRP
を渡し、その処理結果を上位に返す
フィルタドライバの IRP 処理 基本は「何もしないフィルタドライ
バ」 ここでいう「何もしない」とは、上位
から受け取った IRP を、加工せずに下位に渡すこと いわゆるスルー出力
下位に対して、特定の IRP を渡さないことにより、機能を無効化できる(例:書込禁止)
IRP ハンドラの定石 いくつかの処理パターンがある
自分で処理する・しない 下位に渡す・渡さない 下位の処理が終わるのを待つ・待たない
Microsoft KB「 IRP のさまざまな処理方法」 http://support.microsoft.com/kb/320275/ja
シナリオ 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);
}
シナリオ 1 の用途 「何もしない」=もらったものを中継
する 「何も足さない、何も引かない」
「どの IRP が」「いつ」あったかを監視できる デバッグ出力、ロギング
その IRP の処理結果(いつ完了し、どういう結果が得られたか)は、シナリオ 1 ではわからない
シナリオ 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;
}
シナリオ 2 の用途 処理の完了を待つものに使用する
典型的な使用例は、デバイスの使用開始待ち( IRP_MN_START_DEVICE )
完了するまで上位に制御を返さない KeWaitForSingleObject ()で待つと、他の IRP ディスパッチ処理も停止する(かも) そのため、下位の処理が短時間に終わらな
い IRP には適用すべきでない
シナリオ 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);
}
シナリオ 3の用途 下位の処理結果( I/O読み込みの結果
等)を加工したい場合に使える シナリオ 2 は処理完了まで上位をブ
ロックするが、シナリオ 3だと下位が非同期処理をしていれば上位に制御が戻る
明示的に非同期処理をしたい場合はシナリオ 4にする
シナリオ 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;
}
シナリオ 4の用途 その IRP を別のスレッドで処理したい
場合に使用する 非同期処理を行う場合、他のスレッド
との競合を考慮したコードを書く必要がある スピンロックによる排他制御や、他のス
レッドによって IRP がキャンセルされたかどうかのチェック等
シナリオ 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;
}
シナリオ 5の用途 フィルタドライバで追加実装した機能
など、自分で処理する必要がある IRPの場合 独自の DeviceIoControl など
特定の機能を上書きしたり禁止できる 例:ある条件下では書き込みを禁止する
BSoD BlueScreen of Death (死の青画面) デバイスドライバのバグやメモリエ
ラー等で発生 デバッガ接続している場合は BSoD は
表示されず、デバッガプロンプトになる
BSoD 発生時、クラッシュダンプに追加情報を格納することも可能
余談:色を変える BSOD Properties NT
実行レベル カーネル空間では、スレッドの実行レ
ベルが状況に応じて動的に変化する 割り込み処理などで一時的に高くなる
ユーザープロセスの優先度とはまた別 全ユーザープロセスよりもカーネルが優先
フィルタドライバで使う実行レベルは主に以下の 2 レベル 高= DISPATCH_LEVEL 低= PASSIVE_LEVEL
ページング ページング=ページを 1 単位としたメ
モリブロックを外部記憶装置( HDD )へ追い出す スワップ=プロセス単位( IT 用語辞典)
デバイスドライバのソースコードにおいて、ある関数または変数がページング可能かどうかを指定できる 指定方法はコードとデータで異なる 確保時に固定(動的に変化しない)
DISPATCH_LEVEL 実行優先度が高く、処理の自由度が低
い 応答性が必要な処理などで使用する
DPC ( Deferred Procedure Call )など ページングしない(できない)
ページアウトされた領域にアクセスするとBSoD
ページアウトを伴う可能性のある関数は呼び出せない
PASSIVE_LEVEL 実行優先度が低く、処理の自由度が高
い 応答性が不要の処理を記述する
IRP のディスパッチなど ページングする(できる)
ページアウトされた領域にアクセスするとページインする( BSoD にならない)
DISPATCH_LEVEL でないと呼び出せない関数は、一時的に実行レベルを上げて呼び出す
non-paged ページング不可、通称「非ページ」 メモリが不足してもページアウトされ
ない ページング指定がないものはページン
グ不可になる システム全体のパフォーマンスに影響
するので、必要最小限に抑える PASSIVE_LEVEL でも使える
paged ページング可、通称「ページ」 ページアウトされる可能性がある ユーザー空間のプログラムと同じレベ
ルのリソース DISPATCH_LEVEL では使えない
コードのページング指定 関数宣言のあとに pragma で指定
#pragma alloc_text(INIT, DriverEntry) #pragma alloc_text(PAGE, DriverUnload)
ページング可である関数に「 PAGE 」を指定する
初期化時しか使わないコード( DriverEntry )には INIT を指定する 初期化処理の完了後、解放される
PAGED_CODE () ページング可能な領域に配置された
コードであることを示すマクロ PASSIVE_LEVEL で実行されるべきという
印 実行時のチェック
PASSIVE_LEVEL よりも高い優先度で実行されると警告をデバッグ出力
データのページ指定 ページ可能ヒープから確保
ExAllocatePoolWithTag ( PagedPool ) 非ページヒープから確保
ExAllocatePoolWithTag ( NonPagedPool)
#pragma data_seg ()でデータをページング可能領域( PAGE セクション)に置けるが、データだけ別ファイルにする必要がある
ページング指定とセクション ページング不可のコードは .text セク
ションに入る ページング不可のデータは .data
や .rodata セクションに入る ページング可のデータは PAGE セク
ションに入る リスティングファイルや IDA Pro でわ
かる
豆知識: pageable ページ可能は「 pageable 」 でもなぜか DO_POWER_PAGABLE と
…いう定義が
デバイスドライバの概要 フィルタドライバの概要 ドライバとインスタンス IRP フィルタドライバの実装 フィルタドライバの登録 ←★ INFファイル
フィルタドライバの登録( 1 ) デバイスドライバとしてインストール
しておく Win32API の CreateService()
レジストリエントリに追加する Upper フィルタの場合:値 UpperFilters Lower フィルタの場合:値 LowerFilters 値はMULTI_SZ型 複数登録できる
フィルタドライバの登録( 2 ) デバイスに対するフィルタドライバの
追加 Win32API の
SetupDiSetDeviceRegistryProperty() を使用して登録する
レジストリエントリHKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum 以下に登録される(レジストリエディタでは読み取りのみ可能)
フィルタドライバの登録( 3) デバイスクラスに対するフィルタドラ
イバの追加 HKEY_LOCAL_MACHINE\SYSTEM\Curre
ntControlSet\Control\Class\{CLASS_GUID}以下を、レジストリ操作関数で設定する
RegOpenKeyEx() 、 RegSetValueEx()
フィルタドライバの削除 SetupDiGetDeviceRegistryProperty() または
RegQueryValueEx() により既存の値を読み取る
MULTI_SZ型の値から、対象文字列を削除する
SetupDiSetDeviceRegistryProperty() またはRegSetValueEx() により値を設定する
DeleteService() によりデバイスドライバの登録を削除する
GUI で設定 DevFilterEditor
デバイスドライバの概要 フィルタドライバの概要 ドライバとインスタンス IRP フィルタドライバの実装 フィルタドライバの登録 INF ファイル ←★
INFファイル 謎の書式でインストール情報を記述す
る devcon.exe 等からインストールすると
きや、カタログファイル( .CAT )を作るのに必要
GenINFである程度は作れる ただしWDK 6001 には存在しない
ChkINFでチェックできる 実態は Perl スクリプト
GenINF( 1 ) general info.
GenINF( 2 ) add files
アーキテクチャの指定
GenINF( 3 ) specific info.
GenINF( 4 ) bus types
GenINF( 5 ) x86 specific
GenINF( 6 ) service info.
GenINF( 7 ) IA64 specific
GenINF( 8 ) class specific info.
GenINF( 9 ) done!
…しかしながら そのままでは使えないので INFファイ
ルを修正する必要がある 近い動作のドライバの INFファイルを見るのが手っ取り早い
WDKのサンプルの INFファイルを改造して挙動を確かめる 記述が間違っているとインストールできな
い
デコレーション プラットフォーム毎(例えば x86と
x64)で、インストール先やインストールするファイルを変えたい場合に指定する 例:「 x86」「 NTamd64」
Windows XP 以前( 95/98/2000)の .INFは下位互換性維持のためひどい書式だったが、 XP 以降はデコレーションのおかげでシンプルになった
DriverVer 「 DriverVer= 5/1/2009 」の行を 「 DriverVer= 05/01/2009,1.0.0.1 」の
ように修正(一桁の数字はゼロで埋める) そのままだと signability に怒られる
[Manufacturer] ( 1 ) INF ファイルに含まれる製造元(ベン
ダー)の一覧を記述する それぞれのハードウェアは、ベンダー毎の
セクションで指定 プラットフォーム毎にインストール動
作を記述したい場合、 [Manufacturer]セクションにデコレーションを追記する 配布ファイルだけ異なるような場合には不
要
[Manufacturer] ( 2 ) x64 ( AMD64/Intel64 )に対応させた
い場合
[Manufacturer] %HOGE%=HOGE,NTamd64[HOGE.NTamd64]…
[Manufacturer] ( 3 ) Itanium に対応させたい場合
[Manufacturer] %HOGE%=HOGE,NTia64[HOGE.NTia64]…
[Manufacturer] ( 4 ) StrongARM アーキテクチャ( Intel
XScale )に対応させたい場合
[Manufacturer] %HOGE%=HOGE,SA[HOGE.SA]…
[Manufacturer] ( 5 ) SH アーキテクチャ( SH-3 、 SH-4 )
に対応させたい場合
[Manufacturer] %HOGE%=HOGE,SH[HOGE.SH]…
[Manufacturer] ( 6 ) MIPS アーキテクチャに対応させたい場
合
[Manufacturer] %HOGE%=HOGE,MIPS[HOGE.MIPS]…
[Manufacturer] ( 7 ) PowerPC アーキテクチャに対応させた
い場合
[Manufacturer] %HOGE%=HOGE,PPC[HOGE.PPC]…
[Manufacturer] ( 8 ) Alpha アーキテクチャに対応させたい場
合
[Manufacturer] %HOGE%=HOGE,Alpha[HOGE.Alpha]…
[Manufacturer] ( 9 ) Alpha AXP アーキテクチャに対応させ
たい場合
[Manufacturer] %HOGE%=HOGE,axp64[HOGE.axp64]…
ちなみに Windows XP は x86 版と x64 版しかリ
リースされていません
Alpha 版は beta すら出ていません
[SourceDisksNames] ファイルのコピー元のディレクトリ指
定 書式
disk_id_num = ,"label",,pathdisk_id_num は 1 以上で自分で定義する
デコレーションにより、アーキテクチャ毎にバイナリを用意できる
[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
[ ~ _Inst.NTx86.HW.AddReg] レジストリに追加する値の指定
例:HKR,,"UpperFilters",0x00010008,"Hoge"
値の型に注意 MULTI_SZ ( 0x10000 )だと既存の値を
上書きする(既存のフィルタドライバを無効にする)
0x10008 → MULTI_SZ 型で追記
CAT ファイル カテゴリファイル INF ファイルから生成するバイナリ
ファイル デジタル署名可能 signability.exe などを利用して生成する
signability で .cat を生成 signability.exe /cat /driver:<INF ファイ
ルのあるフォルダのフルパス > /os:OS値 OS 値には、 OS に対応する数値の論理和
か、文字列( Windows_XP など) Windows 2000 … 2 Windows XP 32bit … 8 Windows Vista 32bit … 256
デジタル署名( 1 ) Vista 64bit では必須
Microsoft による署名のないドライバはロードできない
フィルタドライバがロードできないと、そのデバイスが使用不可能になる
デジタル署名( 2 ) 正式な証明書の場合
Verisign などから購入し、 Microsoft のクロス証明書を生成する
CrystalCPUID のブログなどを参照 オレオレ証明書の場合
適当な証明書を発行し、「信頼できるルート証明書」に格納する
テストモードでないとロードできない
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
インストール devcon.exe でインストール可能
INF ファイルとハードウェア ID を指定する
devcon.exe install Hoge.inf *PNP0FAKE 謎のデバイスを強制的にインストール
する方法のため、不明なデバイスが追加される 削除してよい
余談: GNU make NMAKE 用の MAKEFILE が存在してい
る しかもMAKEFILE は「 DO NOT
EDIT 」 GNU make が使いたい
→ GNUMakefile というファイル名にする
DEMO1 : PassFilter 何もしないフィルタドライバ IRP をデバッグ出力
DEMO2 : SwapFilter キーボードの L キーと R キーを入れ替え
マウスの左クリックと右クリックを入れ替え
Scroll Lock を押すと BSoD
入れ替えの実装方法 Lower フィルタの場合
クラスドライバの配下に入る クラスドライバが提供するサービスコール
バックを利用する Upper フィルタの場合
ユーザーランドとクラスドライバとの間に入る
ユーザーランドとの入出力を加工できる
実装部 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; }
参考書籍 WindowsXP フィルタドライバプログラミング
Microsoft WDM プログラミング WDM デバイスドライバプログラミング完全ガイド
Windows NT ファイルシステム詳説
フィルタドライバプログラミング
絶版 入門書 評判はいまいち USBのフィルタドライバを
書くなら参考になる
Microsoft WDM プログラミング
良書 サンプルが豊富 Visual C++用の Wizardつ
き
WDM ~完全ガイド ソースコードなし どちらかというとリファレ
ンス的 概要を把握した上で、より深く理解するのに使える
NT ファイルシステム詳説 絶版 重厚 NT 用なので古い ファイルシステム周りとし
ては唯一の日本語書籍 ヤフオクで 3万円くらい
Thank you! ご意見ご質問があればお願いします