Cisco Japan Blog

悪意のある Windows ドライバに関する分析(パート 2):I/O システム、IRP、スタック位置、IOCTL ほか

1 min read



このブログは連載記事の一部なので、読み進める前にこちらのパート 1 をお読みいただくことをおすすめします。

連載記事『悪意のある Windows ドライバに関する分析』のパート 1 では、最後に I/O システムと IRP について触れました。続くパート 2 では、これらのテーマについてさらに詳しく説明します。また、IOCTL、デバイススタック、I/O スタック位置など、I/O システムのさまざまな側面を紹介していきます。いずれも、I/O 操作で重要となる要素です。

この連載では、ドライバの概念、Windows カーネル、悪意のあるドライバの基本的分析について紹介します。コード例や Microsoft ドキュメントへのリンクをぜひ参照してください。この記事で説明している概念について、そのコンテキストを得ることができます。

I/O 操作は非常に大きな影響力を持つプロセスであり、I/O 操作によって攻撃者はカーネルレベルでさまざまな操作を実行できるようになります。カーネルレベルのアクセスによって、ネットワークトラフィックを目立たないように操作(キャプチャ、開始、変更など)できるほか、システム上のファイルへのアクセスや変更が可能になります。仮想保護モードなどの仮想化保護機能は悪意のあるドライバに対する防御に効果を発揮しますが、一般的な Windows 環境ではデフォルトで有効になっていません。保護機能を有効にしたとしても、カーネルモードドライバを効果的に守るには特定の設定が必要です。

悪意のあるドライバの機能を制限する要素は、作成者個人のスキルレベルと知識、そして攻撃対象となるシステムの設定のみです。一方、開発時に検討すべき要素が多いので、信頼性の高い悪意のあるドライバの作成は非常に難しいものです。この検討要素の 1 つに、対象システムのクラッシュを起こさずに I/O 操作を正しく実装することがあります。適切に対策しなければ、簡単にクラッシュが発生します。

I/O システム、I/O 要求パケット(IRP)、デバイススタック

前回の記事で説明したように、I/O マネージャとエグゼクティブレイヤの他のコンポーネントは、ドライバに送られるデータを I/O 要求パケット(IRP)内にカプセル化します。すべての IRP は、wdm.h で「_IRP」として定義される構造体で表されます。

IRP は、システムコンポーネント、ドライバ、またはユーザーモード アプリケーションが、ドライバに対して設計どおりの操作を実行するよう要求した結果作成されるものです。要求を行う方法は複数あり、ユーザーモードの要求元かカーネルモードの要求元かで方法が異なります。

要求:ユーザーモード

I/O 要求は、Windows カーネルとユーザーモードの基本的メカニズムの 1 つです。ユーザーモードでの単純な操作にはテキストファイルの作成などがありますが、これには I/O システムにより IRP が作成され、ドライバに送られることが必要です。テキストファイルを作成してハードドライブに保存する操作の場合は、ディスクに物理的変更が加えられるまで、複数のドライバが IRP を送受信します。

ユーザーモード アプリケーションが要求を開始するシナリオの 1 つは、ドライバに対し何らかの読み取り操作を指示する ReadFile ルーチンの呼び出しです。アプリケーションがドライバのデバイスオブジェクトにハンドルを ReadFile の hFile パラメータとして渡すと、この指示を受けた I/O マネージャが、IRP を作成して指定されたドライバに送信します。

ハンドルを渡すにあたり適したものを取得するため、アプリケーションは CreateFile 関数を呼び出し、ドライバのデバイス名を lpFileName パラメータとして渡します。関数が正常に完了すると、指定されたドライバへのハンドルが返されます。

注:CreateFile 関数は、名前がファイル作成のみを示しているため誤解を招くことがありますが、ファイルまたはデバイスを開き、それらにハンドルを返すこともできます。 

上のpopup_iconにあるように、「\\\\.\\IoctlTest」の値は lpFileName パラメータで渡されます。デバイス名をパラメータとして渡す場合は「\\.\」を先頭に追加する必要があります。バックスラッシュはエスケープする必要があるため、「\\\\.\\」となります。

要求:カーネルモード

システムコンポーネントやドライバが IRP を送信するには、DEVICE_OBJECT と IRP へのポインタ(PIRP)をパラメータとして指定して IoCallDriver ルーチンを呼び出す必要があります。IoCallDriver は実質的に IofCallDriver のラッパーであり、Microsoft 社が絶対に直接呼び出さないよう推奨している点に注意が必要です。

ドライバ間の要求はドライバの機能の重要な部分ですが、ここでは割愛します。

デバイスノードとデバイスツリー

IRP の説明を続ける前に、IRP の目的と機能に対する理解が深まるよう、ここでデバイススタックとデバイスツリーの概念について触れておきます。

IRP は、目的のドライバに到達するために、「デバイススタック」と呼ばれるものを通じて送信されます。これは「デバイスノード」や「devnode」と呼ばれる場合もあります。デバイススタックは、階層化された「スタック」に論理的に配置されたデバイスオブジェクトの順序指定済みリストと考えてよいでしょう。スタックの各レイヤは、個別のドライバを表す DEVICE_OBJECT 構造体で構成されています。重要なのは、ドライバが作成するデバイスオブジェクトが 1 つのみに制限されていない点です。複数作成されることは一般的にあります。

注:「デバイススタック」と「デバイスノード」は同義で用いられることが多くありますが、厳密にいえば定義は若干違っています。根本的には同じことを指しているものの、コンテキストが異なります。具体的には、「デバイススタック」はデバイスツリーの「デバイスノード」の内部にあるデバイスオブジェクトのリストを指します。

各デバイスノードとその内部にあるデバイススタックは、オペレーティングシステムによって認識されるさまざまな種類のデバイスやバス(USB デバイス、オーディオコントローラ、ディスプレイアダプタなど)を表します。Windows では、これらのデバイスノードを「デバイスツリー」もしくは「プラグアンドプレイ デバイスツリー」と呼ばれる大規模な構造で整理しています。

ツリー内のノードは親子関係で接続されており、各ノードは接続されている他のノードに依存します。ツリー最下部のノードは、ツリー階層のすべてのノードが他のノードと関連しながら最終的にこのノードに接続されることから「ルートデバイスノード」と呼ばれます。起動時、プラグアンドプレイ(PnP)マネージャが接続されたデバイスに対し子デバイスノードをすべて列挙するよう要求することによって、デバイスツリーが作成されます。デバイスツリーとノードの仕組みの詳細については、こちらの MSDN ドキュメントを参照してください。

デバイスツリーの図(出典:MSDN ドキュメント

この時点では、デバイスツリーはシステムにインストールまたは接続されたすべてのドライバ、バス、デバイスのマップのようなものと考えてかまいません。

デバイスの種類

各デバイススタック内のレイヤを構成するデバイスオブジェクトには、物理デバイスオブジェクト(PDO)、機能デバイスオブジェクト(FDO)、フィルタ デバイス オブジェクト(FiDO)の 3 種類があります。下に示したように、デバイスオブジェクトの種類はそれを作成するドライバの機能によって決まります。

  • PDO:物理的なものではなく、USB または PCI など特定のバスのドライバによって作成されるデバイスオブジェクトです。このデバイスオブジェクトは、スロットに接続された実際の物理デバイスを表します
  • FiDO:フィルタドライバによって作成されます(この連載ではあまり取り上げません)。レイヤ間にあるドライバは、デバイスに機能を追加したり、デバイスを変更したりできます。
  • FDO:システムに接続されているデバイスの機能を提供するためにドライバによって作成されます。最も一般的なのはベンダーが提供する特定のデバイス用のドライバですが、用途は多種多様です。悪意のあるドライバの多くはこの種類に該当するため、この連載記事の大部分は FDO に関する内容となります。

さまざまなオブジェクトタイプの詳細については、こちらの MSDN ドキュメントを参照してください。

デバイスツリーと同様に PnP マネージャもまた、デバイスノード作成時に正しいドライバを読み込む役割を持っています。読み込みは最下位レイヤから開始されます。デバイススタックが作成されると、最下位レイヤに PDO が配置され、通常は FDO が少なくとも 1 つあります。一方 FiDO は任意であり、レイヤ間またはスタックの最上部に配置されます。デバイススタックは、デバイスオブジェクトの数や種類に関係なく、常に上から下に処理されるリスト構造になっています。言い換えると、スタック最上位のオブジェクトが常に最初に処理され、最下位のオブジェクトは常に最後に処理されます。

IRP が送信される際、目的のドライバに直接向かうのではなく、目的のドライバのデバイスオブジェクトを含むデバイスノードに向かいます。上ですでに説明したように、正しいノードが IRP を受け取ると、上から下に向かって通過し始めます。IRP が正しいデバイスノードを見つけた後は、正しいレイヤに行き着く必要があります。ここで I/O スタック位置が関係することになります。

I/O スタック位置

IRP がメモリに割り当てられると、IO_STACK_LOCATION として定義される I/O スタック位置という他の構造体も割り当てられます。複数の IO_STACK_LOCATION が割り当てられる場合がありますが、少なくとも 1 つは必要です。I/O スタック位置は IRP 構造体の一部ではなく、IRP の最後に「追加」された独自の定義済み構造体です。

IRP に付随する I/O スタック位置の数は、IRP の送信先となるデバイススタック内のデバイスオブジェクトの数と同じです。あとで簡単に説明しますが、デバイススタックの各ドライバは I/O スタック位置のうち 1 つを受け持つことになります。デバイススタック内のドライバは、IRP が処理対象かどうかをスタック位置から判断します。処理対象と判断されれば、要求された操作が実行されます。そうでない場合は、IRP は次のレイヤに渡されます。

IO_STACK_LOCATION 構造体には複数のメンバーが含まれており、IRP との関連性を判断するためにドライバによって使用されます。

構造体の最初のメンバーが、この連載のパート 1 で紹介した MajorFunctionMinorFunction です。これらのメンバーには関数コードが含まれます。IRP が作成され、IRP を受け取るドライバに送信される際に関数コードが指定されます。ドライバに対して要求された操作の内容を表したものが関数コードです。たとえば IRP に IRP_MJ_READ 関数コードが含まれている場合、何らかの読み取り操作が要求されています。MinorFunction については要求に IRP_MN_START_DEVICE などのマイナー関数コードが含まれる場合にのみ使用されます。

構造体の Parameters メンバーは、現在の関数コードと併せて使用される、構造体の大きな集合体です。これらの構造体は、要求された操作の詳細な情報をドライバに提供するために使用されます。また、各構造体は、特定の関数コードのコンテキストにおいてのみ使用されます。たとえば MajorFunctionIRP_MJ_READ に設定されている場合、Parameters.Read複数の異なる操作を使用して要求に関する追加情報を含めることができます。この記事の後半で IOCTL の処理について説明する際に Parameters メンバーを再度取り上げます。Parameters と構造体の他のメンバーの詳細な説明については、こちらの MSDN ドキュメントを参照してください。

IRP フロー

すべての IRP は、デバイススタック内のデバイスオブジェクトの種類に関係なく、目的のデバイスノードに到達すると同じ方法で処理されます。IRP は、目的のドライバに到達するまで、スタックの上から下に向かって各レイヤ間で「渡されて」いきます。レイヤ間を通っていきタスクが完了すると、今度はノードを遡るように下から上に向かって渡されていき、I/O マネージャに戻ります。

IRP がスタックを通過する際、各レイヤは要求をどう扱うかを判断する必要があります。スタック内の各レイヤを担当するドライバによって要求の扱いが異なります。そのレイヤで処理するようになっている要求であれば、プログラムされたとおりに要求が処理されますが、関連性がない要求は、スタック内の下位レイヤに渡されます。要求を受け取るレイヤがフィルタドライバに関連していれば、(該当する場合は)そのレイヤの関数が実行され、要求がスタックの下位に渡されます。

要求がレイヤに渡されると、ドライバは IRP へのポインタ(PIRP)を受け取り、関数 IoGetCurrentIrpStackLocation を呼び出してポインタをパラメータとして渡します。

このルーチンにより、ドライバは要求内で受け持つ I/O スタックの位置を確認し、その位置に基づいて、要求された操作を実行するか、次のドライバに渡すかを判断します。

要求がレイヤのドライバに関係ない場合、次のレイヤに IRP が渡されます。これはフィルタドライバによって頻繁に実行される操作です。要求が下位レイヤに渡される前に、いくつかの処理が行われます。関数 IoSkipCurrentIrpStackLocation が呼び出され、次に IoCallDriver が呼び出されます。IoSkipCurrentIrpStackLocation を呼び出すことで、要求がスタック内の次のドライバに渡されます。その後 IoCallDriver が 2 つのパラメータ(スタック内の次のドライバのデバイスオブジェクトへのポインタと、IRP へのポインタ)を指定して呼び出されます。これらの 2 つのルーチンが完了すると、スタック内の次のドライバが要求を処理します。

スタック内の各ドライバが目的の要求を受け取ると、そのドライバは設計されたとおりに要求を完了できます。要求の処理方法に関係なく、処理が完了すると IoCompleteRequest を呼び出す必要があります。IoCompleteRequest が呼び出されると、要求はたどった道を遡り、最終的に I/O マネージャに戻ります。

要求における IRP のフローの詳細については、以下の MSDN ドキュメントを参照してください。

IRP の処理と完了

この連載記事のパート 1 でも触れましたが、ドライバには「ディスパッチルーチン」という関数があり、処理可能な MajorFunction コードを含む IRP をドライバが受け取ると呼び出されます。ディスパッチルーチンはドライバに機能を提供する主要メカニズムの 1 つであるため、ドライバを分析する場合は理解しておくことが重要です。

たとえば、ドライバに IRP_MJ_READ 関数コードを処理する ExampleRead というディスパッチルーチンがある場合、IRP_MJ_READ を含む IRP を処理する際にそのルーチンが実行されます。ディスパッチルーチンは IRP_MJ_READ を処理するので、その名前が示すとおり、何らかの読み取り操作が実行されます。この関数コードは、一般的に ReadFileZwReadFile などの関数に関連しています。ディスパッチルーチンと各ルーチンの処理の詳細については、こちらの MSDN ドキュメントをお読みいただくことをおすすめします。

MajorFunction コードをディスパッチルーチンのエントリポイントに割り当てる例

ここまでのまとめ

これまでに説明した I/O 要求についての情報をすべてまとめると、ずっと簡単にプロセスを思い浮かべられるようになります。プロセスには非常に多くの側面があり、1 つの連載ではすべてに触れることができませんが、ここまでに I/O 要求の作成と送信、処理、完了について主要なロジックを紹介してきました。以下は、一般的な I/O 要求のフローを簡単にまとめたものです。

  • I/O マネージャにより IRP が作成され、必要な I/O スタック位置が追加されます。
  • その後、適切なデバイススタックに IRP が送信されます。
  • IRP は、目的のドライバのデバイスオブジェクトに到達するまで、スタックを通過します。スタック内の各ドライバは、要求を処理するか、次のレイヤに渡します。
  • 要求が正しいレイヤに到達すると、ドライバが呼び出されます。
  • ドライバが I/O スタック位置の MajorFunction メンバーを読み取って、関数コードに関連付けられているディスパッチルーチンを実行します。
  • ドライバが操作を完了すると IoCompleteRequest が呼び出され、IRP はスタックを遡るように渡されていきます。
  • IRP が I/O マネージャに戻ります。

これらの概念を理解することで、複雑で込み入ったドライバと Windows カーネルについて学ぶための土台ができます。このようなトピックは本質的に複雑で抽象的に思われることも多く、学ぶには時間がかかるうえ、直接触れてみないと身に付きにくい性質があります。

デバイス入出力制御、IOCTL

IRP は、ここまでの説明とは少し違った方法で要求を送ることができます。ドライバには要求の送信モードが別にあり、これには I/O 制御コード(IOCTL)というものが使用されます。デバイス入出力制御も IOCTL と呼ばれることがありますが、これは、ユーザーモード アプリケーションと他のドライバが特定のドライバに特定のディスパッチルーチンを実行するよう要求できるインターフェイスです。ディスパッチルーチンには事前定義済みの I/O 制御コードが割り当てられています。

注:混乱を避けるために、この連載記事で「IOCTL」を使用する場合は、I/O 制御コードを指すこととします。「デバイス入出力制御」のことではありませんのでご注意ください。

IOCTL はドライバに定義されているハードコードされた 32 ビットの値であり、そのドライバの特定の関数を表します。IOCTL 要求は IRP によって送信されます。上で説明したのとほぼ同じ方法です。ただし、IOCTL 要求で使用される特定の MajorFunction コードがあります。ユーザーモード アプリケーションとドライバは両方とも IOCTL 要求を開始できますが、そのための要件に若干の違いがあります。

MajorFunction コードと IOCTL

IOCTL に関連した MajorFunction コードは、これまでに説明した関数コードと同じ方法で送信されます。I/O マネージャが送信する IRP を用いてコードが送られ、受け取ったドライバによって処理されます。すべての IOCTL 要求は、IRP_MJ_DEVICE_CONTROLIRP_MJ_INTERNAL_DEVICE_CONTROL のいずれかを使用します。これらは、前述したのと同じ方法でドライバのディスパッチルーチンのエントリポイントに割り当てられます。

IRP_MJ_DEVICE_CONTROL のディスパッチルーチン エントリポイントへの割り当て(出典:GitHubpopup_icon

IRP_MJ_DEVICE_CONTROL IRP_MJ_INTERNAL_DEVICE_CONTROL は両方とも IOCTL の処理に使用されますが、提供される機能は若干異なっています。IOCTL がユーザーモード アプリケーションで使用される場合は、IRP_MJ_DEVICE_CONTROL が使用される必要があります。IOCTL が他のドライバでのみ使用可能になっている場合は、IRP_MJ_INTERNAL_DEVICE_CONTROL が使用される必要があります。

IOCTL の定義

IOCTL を処理するには、ドライバで IOCTL を定義して名前を付け、処理される際に実行される関数を実装する必要があります。以下のように、IOCTL は通常、システムによって提供される CTL_CODE という名前のマクロを使用して、ヘッダーファイルに定義されています

Microsoft 社では、IOCTL に名前を付ける際の命名規則として IOCTL_Device_Function を使用することを推奨しています。読んですぐにデバイスと機能を理解できるようにするためです。この命名規則の例が MSDN で紹介されており、IOCTL_VIDEO_ENABLE_CURSOR となっています。アプリケーションとドライバは通常、要求を行う際に IOCTL の名前をパラメータとして渡します。32 ビットの値ではありません。命名規則による読み取りやすさと一貫性が生かされています。

IOCTL に命名すること以外にも、CTL_CODE は 4 つの引数を取ります。

  • デバイスタイプ:この値は、ドライバの DEVICE_OBJECT 構造体の DeviceType メンバーと同じ値に設定される必要があります。ドライバが対応しているハードウェアのタイプを定義するものです。デバイスタイプの詳細については、こちらの MSDN ドキュメントを参照してください。
  • 関数:IOCTL 要求で実行される関数です。0x987 のように 32 ビットの 16 進数(ダブルワード)の値で表されます。0x800 未満の値は、Microsoft 社が使用するために予約されています。
  • メソッド:要求元と要求を処理するドライバ間でデータを渡すために使用されるメソッドです。設定可能な値は 4 つあり、METHOD_BUFFERED、METHOD_IN_DIRECT、METHOD_OUT_DIRECT、METHOD_NEITHER のいずれかです。これらのメソッドの詳細については、次のセクションに記載したメモリ操作に関するリンクを参照してください。
  • アクセス:要求を処理するために必要なアクセスのレベルです。設定可能な値は、FILE_ANY_ACCESS、FILE_READ_DATA、FILE_WRITE_DATA のいずれかです。要求元が読み取りと書き込みの両方のアクセスを必要とする場合、FILE_READ_DATA と FILE_WRITE_DATA を OR 演算子「|」で区切って一緒に渡します(例:FILE_READ_DATA | FILE_WRITE_DATA)。

IOCTL 定義の例(出典:GitHubpopup_icon

注:上の画像は、GitHub の「Windows-driver-samplespopup_icon」リポジトリにあるドライバのヘッダーファイルのもので、Windows ドライバについて学べる非常に貴重な技術情報です。Microsoft 社は多数のソースコードサンプルを提供しており、文書化されている WDM KMDF の多くの機能とマクロの実装方法がサンプルに示されています。また、すべてのサンプルには、コンテキストがわかるようコメントが付けられています。

IOCTL 要求の処理

I/O 制御コードが定義されると、適切なディスパッチ関数が実装される必要があります。ドライバは IOCTL 要求を処理するために、通常は「XxxDeviceControl」の命名規則で名前が付けられた関数を持ちます。たとえば Microsoft のサンプルドライバpopup_iconでは I/O 制御要求を処理する関数に「SioctlDeviceControl」の名前が使用されています。

一般的には、受け取った IOCTL に応じて異なる関数を実行する switch ステートメントがこれらの関数に含まれています。詳細な例については、GitHub リポジトリにある Microsoft のサンプルドライバをこちらpopup_iconからご確認いただけます。

上の画像にあるように、このデバイス制御関数では、デバイスオブジェクトへのポインタ(PDEVICE_OBJECT DeviceObject)と IRP へのポインタ(PIRP Irp)の 2 つの引数を取ります。DeviceObject パラメータは、要求の送信元が IOCTL に操作を実行させたいデバイスへのポインタです。これは、ディレクトリ、ファイル、ボリュームのデバイスオブジェクトや、Windows 環境の他のタイプのオブジェクトへのポインタです。関数が取る 2 つ目のパラメータは、IOCTL 要求が送信された際にドライバが受け取った IRP へのポインタです。

デバイス制御関数が実行されると、IOCTL を取得するためにドライバが受け取った IRP 構造体のメンバーを持つ Parameters.DeviceIoControl.IoControlCode を読み取ります。次に IOCTL はドライバ内で定義されている IOCTL と比較され、一致があれば適切なルーチンを実行します。処理と必要なクリーンアップが完了すると、IoCompleteRequest を呼び出すことによって要求は完了します。

DeviceIoControl

要求元は、DeviceIoControl を呼び出すことによって IOCTL 要求を開始します。ここでいくつかのパラメータを渡すことができます。

話をシンプルにするために、hDevicedwIoControlCode の最初の 2 つのパラメータのみについて説明します。残りのパラメータは操作に関連していますが、トピックが複雑で説明が長くなるため、このブログでは取り上げません。I/O 操作を実行するドライバでは、データバッファに関連したやり取りがよく発生します。さらに、ドライバ分析を行うためには、これらの概念に精通することが重要です。詳細を確認するには、MSDN ドキュメントが最適な情報源となります。以下に関連するリンクを記載します。

DeviceIoControl を呼び出す際、呼び出し元は目的のドライバのデバイスオブジェクトへのハンドルを提供し、要求している IOCTL を指定する必要があります。これらのパラメータはそれぞれ、hDevice dwIoControlCode という引数として渡されます。IOCTL 要求を行う際、呼び出し元は要求を送る前に I/O 制御コードの値を把握していることが重要です。さらに、ドライバは認識できない制御コードの受け取りが可能でなければなりません。そうでない場合はクラッシュを起こします。

ドライバによる他のドライバへの IOCTL の送信

場合によっては、上位のドライバが下位のデバイスドライバに IOCTL 要求を送ることが必要になります。これは「内部要求」として知られています。特定の IOCTL はユーザーモード アプリケーションからは要求できず、IRP_MJ_INTERNAL_DEVICE_CONTROLMajorFunction コードを使用します。要求を処理するディスパッチルーチンは通常、ドライバが IRP_MJ_DEVICE_CONTROL を受け取る場合は DispatchDeviceControl と呼ばれ、IRP_MJ_INTERNAL_DEVICE_CONTROL を受け取る場合は DispatchInternalDeviceControl と呼ばれます。この 2 つの主な違いは、DispatchDeviceControl がユーザーモードを発信元とする要求を処理するのに対し、DispatchInternalDeviceControl は内部要求を処理する点です。

簡潔にしたいので、プロセスの詳細はここでは説明しません。詳細については、こちらの MSDN ドキュメントを参照してください。あるドライバから他のドライバに送られる IOCTL については触れませんが、比較的理解しやすいユーザーモード アプリケーションから送られる IOCTL は取り上げることにします。基礎を理解すると、ドライバ間の I/O について習得するのがずっと簡単になります。IOCTL に関するトピックは、次のパートでドライバのデバッグについて説明して締めくくりとなります。

まとめ

さらに学習したい方は、リンクを記載した MSDN ドキュメントを参照したり、Microsoft 社のサンプルドライバを GitHub リポジトリで探したりして、詳細な情報をご確認ください。MSDN にあるドライバ関連ドキュメントの I/O セクションが参考になるのでぜひ確認してみてください。ほとんどは、このブログ記事でリンクを記載しています。I/O セクションにはこちらからアクセスできます。

この連載の次のパートでは、ドライバのインストール、実行、デバッグのほか、関連するセキュリティの概念について説明します。分析に必要な基本的セットアップとツール類、分析において見るべきポイントなどについて説明する予定です。デバッガの使用について示すために、ドライバが IOCTL を処理しディスパッチルーチンを実行する方法を紹介します。

 

本稿は 2024 年 06 月 18 日にTalos Grouppopup_icon のブログに投稿された「Exploring malicious Windows drivers (Part 2): the I/O system, IRPs, stack locations, IOCTLs and morepopup_icon」の抄訳です。

 

コメントを書く