セキュリティエンジニアのためのWindowsカーネルモードドライバ開発入門 其ノ壱


# はじめに

Joanna Rutlowskaは、Introducing Stealth Malware Taxonomy(Black Hat 2006)の中でマルウェアをType 1から3に分類することを提唱しました。Type 1とType 2のマルウェアは、少なくとも一部がカーネルモードで動作するものです。これらのマルウェアの解析のためには、カーネルモードでのプログラミングやデバッグの知識が必要とされます。Windowsでは、カーネルモードでプログラムを動作させるには、カーネルモードドライバとして作成する必要があります。つまり、マルウェアの解析のためには、Windowsのドライバを作ることができる必要があります。

Windows用のデバイスドライバの開発では、通常のユーザモードアプリケーションの開発に利用されるSoftware Development Kit(SDK)ではなく、Windows Driver Kit(WDK)を利用します。さらに、デバッグにはVisual Studioの統合デバッガではなく、カーネルモードデバッガであるWinDBGを利用します。こうした開発技法などの違いがあるため、ドライバプログラミングは通常のアプリケーション開発よりも敷居が高いものになっています。

# 予定

- 其ノ壱：ドライバ開発入門
 - WDKの紹介などを行います。
- 其ノ弐：環境設定からHello World!まで
 - Mac OSX環境 + VMware Fusionか、Windows + VirtualBoxで環境を構築します。
- 其ノ参：SSDTフックなどを扱う予定
- 其ノ四：ユーザモードとのやり取りを扱う予定

# 開発に必要なもの

ドライバの開発に必要なものは以下のようなものです。個々に説明していきます。

- WDK
- Visual Studio
- テスト環境
- カーネルデバッガ
- SysInternals

## Windows Driver Kit(WDK)

WDKはWindows用のドライバを作成するために利用するSDKの一種です。以前は、Driver Development Kit(DDK)という名称でリリースされていて、独立したビルドのシステムを持っているものでした。名称がWDKと変更されたWDK8から、Visual Studioのアドオンとしてインストールされるようになりました。開発できる対象OSが違うため、バージョンの異なる複数のWDK/DDKを一つの開発環境にインストールして、使い分けができるようになっています。

DDKにはドライバ開発用の専用コンパイラが付属し、buildコマンドを利用してビルドを行っていました。buildコマンドは、SOOURCE、MAKEFILEといった入力ファイルを利用してロード可能なバイナリの作成までを行います(コンパイラドライバ)。付属するコンパイラは、Cコンパイラであるため、変数宣言をブロックの先頭で行う必要があるなどの(C++に慣れた開発者から見ると)制限がありました。WDK8からは、Visual Studioのコンパイラと統合されたため、C++を利用してドライバを開発することが可能となっています。

C++の機能を利用可能となっていますが、ドライバのデバッグ環境は比較的貧弱であることもあり、リソースの管理などをメインのプログラムから隠蔽したり、抽象化を行ってコードの再利用などを行うC++とドライバプログラミングの相性はあまりよくありません。また、カーネルモードドライバを作成する場合、ユーザモードのAPIは呼べなくなるため、ユーザモードのAPIに依存するライブラリなどは利用できません。具体的には、Cの標準ライブラリ関数であるmallocなどは利用できないため、内部でmallocを呼び出すnewも利用できません。これは、newを内部で呼び出してリソース管理を自動で行うコンテナなどがそのままでは利用できないということを意味します。もちろんC++の文法で記述自体はできますので、自分でテンプレートを書いたりすることによって、大きな省力化や重複排除などを実現することは可能です。

C/C++で開発可能でありながら、mallocを代表とするlibc(msvcrt.dll)で実装されている標準ライブラリは利用できないなど、ユーザモードでのプログラミングとは別にカーネルモードでのプログラミングを学ぶ必要があるところが、ドライバプログラミングの敷居を高くしている原因の一つとなっています。

WDK8までは、Windows Driver Model(WDM)というモデルでのプログラミングでしたが、WDK8からはWindows Driver Framework(WDF)というフレームワークが利用可能になっています。これは、プログラミングだけではなく、テスト環境なども含めたフレームワークとなっています。この記事では、WDMのみを扱います。

WDKにはいくつかのバージョンがありますが、サポートしたい環境に応じて以下のようなWDKをインストールしておけばよいでしょう。古いWDKを利用して作成したバイナリでも、結構新しい環境で動作するようです。

|サポートしたい(最も古い)環境|WDKのバージョン|
|:----------|:-----------|
|XP / 2003|DDK 2003SP1|
|Vista / 7 / 2008|WDK 7.1.0|
|8 / 8.1 / 2012|WDK 8.1|
|10|WDK 10|

## Visual Studio

WDK8以降では、Visual Studioのコンパイラと統合されたため、Visual Studioのインストールが必要になります。MFCやATLなどの有償ライブラリを利用する必要はないため、無償のExpress for Windows Desktopで開発することができます。

開発環境のOSは、32bitと64bitのどちらのでも利用可能です。Visual Studio自体は、32bit版しか提供されていません。

## テスト環境

カーネルモードドライバのバグは、BSODやOSのフリーズに直結します。物理マシンを利用すると再起動などが頻発するため、開発にとても時間がかかってしまいます。そのため、開発環境とは別に仮想マシンのテスト環境を用意することになります。

また、実用的なドライバを作成したいのであれば、動作環境のOSごとに動作テストが必要になりますので、想定する動作環境ごとにテスト用の仮想マシンを用意することになります。MSDNなどが利用できない場合、最もターゲットにしたいOSのバージョンと32/64bitを考えて環境を用意することになると思います。

Windows上に仮想マシンを構築してテストすることも、Mac上で2台の仮想マシンを構築してテストすることもできます。

## カーネルデバッガ

デバッガには、通常のプロセスをデバッグするユーザモードデバッガと、デバイスドライバやOS自身をデバッグするためのカーネルモードデバッガに分けられます。Visual Studioに統合されているデバッガやマルウェアの解析でよく利用されるImmunity DebuggerやIDA Proは、ユーザモードデバッガです。

Microsoftが提供しているGUIを備えたデバッガであるWinDBGは、ユーザモードとカーネルモードの両方をデバッグすることが可能となっています。WinDBGでは、USB接続やネットワークを利用したリモートデバッグが可能となっています。


|type|ユーザモード|カーネルモード|
|:---|:----------|:-----------|
|CUI|Microsoft Console Debugger (CDB), Microsoft NT Symbolic Debugger (NTSD)  |Microsoft Kernel Debugger (KD) |
|GUI|Microsoft Windows Debugger (WinDbg)|Microsoft Windows Debugger (WinDbg)|

表以外には、Visual Studio with integrated Windows debuggers、NTKD、LiveKd(SysInternals)があります。

## SysInternals

ユーザモードでしか開発経験がない方でもSysInternalsはよく利用されていると思います。カーネルモードの開発でもSysInternalsのツール群が必須です。

# マルウェアの分類
この分類は、ワーム・RATというような機能に着目した分類ではなく、マルウェアの存在の隠蔽手法によった分類です。数値の大きな方が隠蔽手法としては、高度なものとなります。
http://bandwidthco.com/whitepapers/compforensics/malware/rk/Introducing%20Stealth%20Malware%20Taxonomy.pdf


## Type 0
マルウェア自体の隠蔽のために特別な活動を行わないマルウェアです。システムへの感染という観点からはマルウェアと分類されないこともありますが、プロセスの権限に応じてファイルの削除や情報の詐取など有害な(malcious)活動を行うことができます。

Type 0マルウェアは、アンチウィルスのシグニチャマッチングで対応することができます。

## Type 1 (Consistency)
Type 1マルウェアは、システムの中で比較的静的なリソースを改ざんすることによって、隠蔽を行うマルウェアです。他のプロセスやカーネルのコード改変、さまざまなレベルでのフック作成といった活動を行います。

Type 1マルウェアは、システムの一貫性をチェックすることによって検知することが可能です。ディスク上の署名されたバイナリコードとの比較や、システムファイルの改ざんを防止するPatch Guardの仕組みなどで対応することができます。

## Type 2 (Integrity)
Type 2マルウェアは、システムの動的なリソースを改ざんするマルウェアです。他のプロセスやカーネルの保持する動的なデータを改ざんすることにより、隠蔽などを行います。具体的には、カーネルの保持しているプロセスのダブルリンクリストから隠蔽したいプロセスを外す、セキュリティソフトウェアのメモリを改ざんして、検知させないようにするといった活動を行います。

Type 2マルウェアが改ざんするリソースは、もともと動的なものであるため、比較対象とする正しい状態を定義することはできません。そのため、比較ではなく、完全性のチェックを行う必要があります。完全性チェックのためには、サードパーティ製も含めたシステムに重要なすべての動的データの完全性をチェックするルールを用意する必要があります。これは非常に困難なことですが、不可能ではないかもしれません。完全性チェックの実現のためには、そもそもシステム自体が完全性をチェック可能なものとして設計されている必要があります。

## type 3

Type 3マルウェアは、ファイルやメモリなどのOSから見えるものをまったく改ざんすることなしに存在を隠蔽するマルウェアです。このタイプとして実証されているものは、VMMとして実装されているマルウェア、BIOS・UEFI・HDDのファームウェアなどのハードウェアに近い部分に感染するマルウェアといったものが存在してます。一部のマルウェアは、Intel CPUの機能であるTrusted Exception2を利用して実装されたMcAfeeのDeepSAFE技術やSecure Bootなどで検知が可能であると思われます。