Más contenido relacionado La actualidad más candente (20) Similar a フィルタドライバ入門 (20) フィルタドライバ入門2. 自己紹介
生息地
組込日記 http://d.hatena.ne.jp/firewood/
よく使う環境
Windows、Linux、Flash、C/C+
+、x86、ARM
趣味
エンバグ、デバッグ
キーボード蒐集
3. はじめに
書籍、 WDK、webの情報を元に記述
していますが、間違いがあれば教えて
ください
6. デバイスドライバの概要 ←★
フィルタドライバの概要
ドライバとインスタンス
IRP
フィルタドライバの実装
フィルタドライバの登録
INFファイル
7. デバイスドライバとは
デバイスドライバの定義
あるハードウェアをOSから利用可能にす
るためのソフトウェア(狭義の定義)
デバイスドライバの目的
ハードウェアを抽象化すること
基本的には、それぞれのハードウェアに応じ
たデバイスドライバが必要となる
10. 実行形式の種類
NTドライバ
Windows NT 3.1~4.0用
Windows Driver Model (WDM)
Windows 98および2000以降のドライバ
Windows用のドライバの多くがこの形式
WDF Driver Model
ユーザーモードのドライバも書ける新形式
11. WDMの特長
階層化
雛形を定義することによりデバイスド
ライバ開発を定型化
必要最小限の部分だけ実装することが
できる(ミニポートドライバ、フィル
タドライバ)
12. WDMの階層例
他にも
クラスドライバ
ミニクラスドライ
バ
ポートドライバ
ミニポートドライ
バ
など色々ある
uppe r フィルタドライバ
ファンクションドライバ
Lowe r フィルタドライバ
バスドライバ
Ha rdwa re Abs t ra c t ion La ye r(HAL)
13. デバイスドライバの概要
フィルタドライバの概要 ←★
ドライバとインスタンス
IRP
フィルタドライバの実装
フィルタドライバの登録
INFファイル
15. フックとは
デバイスドライバA
デバイスドライバB
デバイスドライバA
フィルタドライバ
デバイスドライバB
間にはさむ
デバイスドライバAからは、フィルタドライ
バがデバイスドライバBに見える
デバイスドライバBからは、フィルタドライ
バがデバイスドライバAに見える
16. フィルタドライバの例
アンチウィルスソフト
リアルタイムファイルシステム監視
VMware
ホストOSのキーボード、マウス、ネット
ワークなど入出力を横取りし、ゲストOS
に流す
葉隠れの術
「SONYがrootkit」とネットで話題に
17. フィルタドライバの特長
階層化
雛形を定義することによりデバイスド
ライバ開発を定型化
必要最小限の部分だけ実装することが
できる
WDMの特長 ≒ フィルタドライバの特
長
18. フィルタドライバの配置の種
類
UpperとLowerの二種類ある
Upperフィルタ
あるデバイスドライバの上位側を乗っ取る
Lowerフィルタ
あるデバイスドライバの下位側を乗っ取る
19. Upperフィルタ
あるデバイスドライ
バの上位側に追加す
る
ユーザーランド側の
入出力を乗っ取るこ
とができる
手軽だが、低レベル
の操作はできない
Uppe r フィルタドライバ
ファンクションドライバ
バスドライバ
20. Lowerフィルタ
あるデバイスドライ
バの下位側に追加す
る
低レベル入出力を
乗っ取ることができ
る
細かい操作が可能だ
が煩雑
ファンクションドライバ
Lowe r フィルタドライバ
バスドライバ
21. フィルタドライバの範囲の種
類
デバイスに対するフィルタドライバ
例:PS/2キーボードに対するドライバ
同種のデバイスのみに適用される
例:USBキーボードには適用されない
デバイスクラスに対するフィルタドラ
イバ
例:キーボードに対するドライバ
そのクラスに属する全デバイスに適用され
る
例:PS/2・USB両方に適用される
22. デバイスドライバの概要
フィルタドライバの概要
ドライバとインスタンス ←★
IRP
フィルタドライバの実装
フィルタドライバの登録
INFファイル
24. ドライバオブジェクト
デバイスドライバのインスタンス
デバイスドライバが必要になると、
カーネルがロード&実行
システム起動時やデバイスを挿したとき
デバイスドライバのロード
=ドライバオブジェクトの生成
DriverEntry関数が呼び出される
引数はドライバオブジェクト
25. デバイスオブジェクト
システム起動時やデバイスを挿したとき、デ
バイス毎に(バスドライバ等が)生成する
登録されているデバイスドライバそれぞれが
デバイスオブジェクトを生成する
総数=デバイス数×デバイスドライバ数
それぞれのデバイスドライバのAddDevice関
数が呼び出される
引数はドライバオブジェクトと、下位のデバイス
オブジェクト
29. ドライバ階層例
ドライバがディ
ジーチェーン接
続されている
vmkbd(フィルタドライバ)
kbdc la s s(クラスドライバ)
i8042prt(ポートドライバ)
Ha rdwa re Abs t ra c t ion La ye r(HAL)
30. インスタンスの生成順序
vmkbd の
ドライバオブジェクト
kbdc la s s の
ドライバオブジェクト
i8042prt の
ドライバオブジェクト
デバイス
オブジェクト
デバイス
オブジェクト
②通知
デバイス
オブジェクト
③生成
④連結
①生成
⑤通知
⑥生成
⑦連結
31. フィルタドライバの優先順位
Lower DO→FDO→Upper DOの順に生成
(対クラスよりも)デバイスに対する
フィルタドライバが先にインスタンス
化される
同種では記述順にインスタンス化され
る
32. フィルタドライバのリンク
次のようなリンクを形成する(はず)
上位(ユーザー空間) → クラスのUpper B
→ クラスのUpper A → デバイスのUpper
B → デバイスのUpper A → FDO → クラス
のLower B → クラスのLower A → デバイ
スのLower B → デバイスのLower A →
PDO → 下位(HAL)
生成は上記の逆順(デバイスのLowerか
ら)
33. デバイスドライバの概要
フィルタドライバの概要
ドライバとインスタンス
IRP ←★
フィルタドライバの実装
フィルタドライバの登録
INFファイル
34. IRPの概要
IRP
I/O Request Packet
何らかのイベントが発生することによ
り生成され、デバイスオブジェクトに
伝達される指示パケット
Read、Write、Plug&Playなど、様々
な内容のメッセージが定義されている
35. IRPの処理イメージ
上位のデバイス
オブジェクトが
、下位のデバイ
スオブジェクト
へIRPを伝播さ
せていく
IRP
イベント
発生 生成
デバイスオブジェクトA
IRP
デバイスオブジェクトB
36. IRPのスタック領域
IRP
デバイスオブジェクトX
デバイスオブジェクトY
デバイスオブジェクトZ
A用のスタック領域
B用のスタック領域
C 用のスタック領域
IRP内の自分用の領域に
アクセスし、次の階層へ
伝播させていく
ドライバオブジェクトA
ドライバオブジェクトB
ドライバオブジェクトC
38. デバイスドライバの概要
フィルタドライバの概要
ドライバとインスタンス
IRP
フィルタドライバの実装 ←★
フィルタドライバの登録
INFファイル
39. 開発に必要な環境(1)
DDK
Windows 2000で開発できる
Vista用のドライバが書けない
WDK
Windows XP以降で開発できる
2000/XP/Vistaのドライバ開発が可能
WinDbg
なくても開発は可能、あると便利
40. 開発に必要な環境(2)
VMwareホスト+VMwareゲスト
1台のPCで開発とテスト実行が可能
named pipe経由でWinDbg接続
デバイスドライバの種類によっては開発不
能
二台のPC(開発機と実験機)
シリアルクロスケーブル経由でWinDbg接
続
最終的には実機での検証が必要
44. 余談2:GsDriverEntry
/GSオプションありでビルドした場合
(WDK以降のデフォルト)のエントリ
ポイント
/GSつきだとスタックチェックのコードが
生成
ドライバファイルのエントリポイントに
GsDriverEntryのアドレスが入る
GsDriverEntry内でDriverEntryへジャンプ
sourcesでの設定で無効化できる
BUFFER_OVERFLOW_CHECKS=0
詳しくはwebで
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;
}
46. DriverUnload
静的に確保しているものがなければ空
でOK
管理しているデバイスオブジェクトが
ゼロになると呼び出される
デバイスオブジェクトを静的に確保してい
ると自動的にはアンロードされない
static void DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
}
47. AddDeviceの概要
デバイスが接続された時に呼び出され
る
接続=デバイスオブジェクトの生成
引数はドライバオブジェクトと、自分
の下位となるデバイスオブジェクト
下位のデバイスオブジェクト
通常はバスドライバ(のドライバオブジェ
クト)が生成したもの
通称PDO(Physical Device Object)
50. IRPハンドラの概要
特定の種類のIRPを処理する関数
いずれかのパターン
IRP毎に関数を用意する
一つの関数で共通処理を行い、関数内で
IRPの種類で分岐する
電源管理とPnP(Plug&Play)は他の
IRPと処理が異なるので、別の関数に
することが多い
51. 上位と下位
自分の上位と下位がある
上位=I/Oマネージャや、自分へアタッ
チしたデバイスオブジェクト
上位からIRPが送られてくる
下位=自分がアタッチしたデバイスオ
ブジェクト
IRPを送信することができる
54. IRPハンドラの定石
いくつかの処理パターンがある
自分で処理する・しない
下位に渡す・渡さない
下位の処理が終わるのを待つ・待たない
Microsoft KB「IRPのさまざまな処理
方法」
http://support.microsoft.com/kb/320275/ja
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);
}
56. シナリオ1の用途
「何もしない」=もらったものを中継
する
「何も足さない、何も引かない」
「どのIRPが」「いつ」あったかを監
視できる
デバッグ出力、ロギング
そのIRPの処理結果(いつ完了し、ど
ういう結果が得られたか)は、シナリ
オ1ではわからない
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;
}
58. シナリオ2の用途
処理の完了を待つものに使用する
典型的な使用例は、デバイスの使用開始待
ち(IRP_MN_START_DEVICE)
完了するまで上位に制御を返さない
KeWaitForSingleObject()で待つと、
他のIRPディスパッチ処理も停止する
(かも)
そのため、下位の処理が短時間に終わらな
いIRPには適用すべきでない
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);
}
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;
}
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;
}
65. BSoD
BlueScreen of Death (死の青画面)
デバイスドライバのバグやメモリエ
ラー等で発生
デバッガ接続している場合はBSoDは
表示されず、デバッガプロンプトにな
る
BSoD発生時、クラッシュダンプに追
加情報を格納することも可能
67. 実行レベル
カーネル空間では、スレッドの実行レ
ベルが状況に応じて動的に変化する
割り込み処理などで一時的に高くなる
ユーザープロセスの優先度とはまた別
全ユーザープロセスよりもカーネルが優先
フィルタドライバで使う実行レベルは
主に以下の2レベル
高=DISPATCH_LEVEL
低=PASSIVE_LEVEL
68. ページング
ページング=ページを1単位としたメ
モリブロックを外部記憶装置(HDD)
へ追い出す
スワップ=プロセス単位(IT用語辞典)
デバイスドライバのソースコードにお
いて、ある関数または変数がページン
グ可能かどうかを指定できる
指定方法はコードとデータで異なる
確保時に固定(動的に変化しない)
70. PASSIVE_LEVEL
実行優先度が低く、処理の自由度が高
い
応答性が不要の処理を記述する
IRPのディスパッチなど
ページングする(できる)
ページアウトされた領域にアクセスすると
ページインする(BSoDにならない)
DISPATCH_LEVELでないと呼び出せない
関数は、一時的に実行レベルを上げて呼び
出す
73. コードのページング指定
関数宣言のあとにpragmaで指定
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, DriverUnload)
ページング可である関数に「PAGE」
を指定する
初期化時しか使わないコード
(DriverEntry )にはINITを指定する
初期化処理の完了後、解放される
75. データのページ指定
ページ可能ヒープから確保
ExAllocatePoolWithTag(PagedPool)
非ページヒープから確保
ExAllocatePoolWithTag(NonPagedPool
)
#pragma data_seg ()でデータをペー
ジング可能領域(PAGEセクション)
に置けるが、データだけ別ファイルに
する必要がある
78. デバイスドライバの概要
フィルタドライバの概要
ドライバとインスタンス
IRP
フィルタドライバの実装
フィルタドライバの登録 ←★
INFファイル
79. フィルタドライバの登録
(1)
デバイスドライバとしてインストール
しておく
Win32APIのCreateService()
レジストリエントリに追加する
Upperフィルタの場合:値 UpperFilters
Lowerフィルタの場合:値 LowerFilters
値はMULTI_SZ型
複数登録できる
80. フィルタドライバの登録
(2)
デバイスに対するフィルタドライバの
追加
Win32APIの
SetupDiSetDeviceRegistryProperty() を使
用して登録する
レジストリエントリ
HKEY_LOCAL_MACHINESYSTEMCurre
ntControlSetEnum以下に登録される(レ
ジストリエディタでは読み取りのみ可能)
81. フィルタドライバの登録
(3)
デバイスクラスに対するフィルタドラ
イバの追加
HKEY_LOCAL_MACHINESYSTEMCurre
ntControlSetControlClass
{CLASS_GUID}以下を、レジストリ操作
関数で設定する
RegOpenKeyEx()、RegSetValueEx()
84. デバイスドライバの概要
フィルタドライバの概要
ドライバとインスタンス
IRP
フィルタドライバの実装
フィルタドライバの登録
INFファイル ←★
85. INFファイル
謎の書式でインストール情報を記述す
る
devcon.exe等からインストールすると
きや、カタログファイル(.CAT)を作
るのに必要
GenINFである程度は作れる
ただしWDK 6001には存在しない
ChkINFでチェックできる
実態はPerlスクリプト
96. デコレーション
プラットフォーム毎(例えばx86と
x64)で、インストール先やインス
トールするファイルを変えたい場合に
指定する
例:「x86」「NTamd64」
Windows XP以前(95/98/2000)
の.INFは下位互換性維持のためひどい
書式だったが、XP以降はデコレーショ
ンのおかげでシンプルになった
97. DriverVer
「DriverVer= 5/1/2009 」の行を
「DriverVer= 05/01/2009,1.0.0.1 」の
ように修正(一桁の数字はゼロで埋め
る)
そのままだとsignability に怒られる
98. [Manufacturer] (1)
INFファイルに含まれる製造元(ベン
ダー)の一覧を記述する
それぞれのハードウェアは、ベンダー毎の
セクションで指定
プラットフォーム毎にインストール動
作を記述したい場合、 [Manufacturer]
セクションにデコレーションを追記す
る
配布ファイルだけ異なるような場合には不
要
99. [Manufacturer] (2)
x64(AMD64/Intel64 )に対応させた
い場合
[Manufacturer]
%HOGE%=HOGE,NTamd64
[HOGE.NTamd64]
…
101. [Manufacturer] (4)
StrongARMアーキテクチャ(Intel
XScale)に対応させたい場合
[Manufacturer]
%HOGE%=HOGE,SA
[HOGE.SA]
…
106. [Manufacturer] (9)
Alpha AXPアーキテクチャに対応させ
たい場合
[Manufacturer]
%HOGE%=HOGE,axp64
[HOGE.axp64]
…
109. [DestinationDirs]
ファイルのコピー先をdridで指定する
http://msdn.microsoft.com/en-us/library/ms790174.aspx
例:DefaultDestDir = 12
ドライバなら「12」
10 → C:Windows
11 → C:WindowsSystem32
12 → C:WindowsSystem32drivers
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
113. デジタル署名(1)
Vista 64bitでは必須
Microsoftによる署名のないドライバは
ロードできない
フィルタドライバがロードできないと、そ
のデバイスが使用不可能になる
114. デジタル署名(2)
正式な証明書の場合
Verisignなどから購入し、Microsoftのク
ロス証明書を生成する
CrystalCPUIDのブログなどを参照
オレオレ証明書の場合
適当な証明書を発行し、「信頼できるルー
ト証明書」に格納する
テストモードでないとロードできない
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
116. インストール
devcon.exe でインストール可能
INFファイルとハードウェアIDを指定す
る
devcon.exe install Hoge.inf *PNP0FAKE
謎のデバイスを強制的にインストール
する方法のため、不明なデバイスが追
加される
削除してよい
117. 余談:GNU make
NMAKE用のMAKEFILEが存在してい
る
しかもMAKEFILEは「DO NOT
EDIT」
GNU makeが使いたい
→ GNUMakefileというファイル名にする
120. 入れ替えの実装方法
Lowerフィルタの場合
クラスドライバの配下に入る
クラスドライバが提供するサービスコール
バックを利用する
Upperフィルタの場合
ユーザーランドとクラスドライバとの間に
入る
ユーザーランドとの入出力を加工できる
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;
}