Help us understand the problem. What is going on with this article?

Windowsカーネルモードドライバでワークアイテムを登録する

kmdf2.png

はじめに

前回の記事: Windowsカーネルモードドライバ(KMDF)の開発環境を構築する

前回の記事でKMDF(KernelMode Driver Framework)の開発環境を構築しました。
今回は、カーネルモードドライバでシステム上で動作するワークアイテムを登録してみます。
ユーザーモードで出来ない処理や、カーネル領域で定期的に回す必要のある作業項目ルーチンを登録できます。

概要

今回のルーチンはシステムワーカースレッドで動作します。
カーネル(Ring0)で動くので、何でも出来ます。

「リングプロテクション」
300px-Priv_rings.svg.png

行う処理は以下の通りです。

0.メモリ領域確保
1.新しい作業項目を割り当てて初期化
2.コールバックルーチンを作業項目に関連付けて、システムワーカースレッドによって処理されるように作業項目をキューに配置
3.必要に応じてリソースを解放

ネイティブWORKITEM構造体

typedef struct _WORK_QUEUE_ITEM {
  LIST_ENTRY             List;
  PWORKER_THREAD_ROUTINE WorkerRoutine;
  __volatile PVOID       Parameter;
} WORK_QUEUE_ITEM, *PWORK_QUEUE_ITEM;

実際にやってみる

ルーチン

driver.c
VOID NTAPI myRoutine()
{
    DbgPrint("ROUTINE STARTED!\n");

    //やりたい処理

    DbgPrint("ROUTINE FINISHED!\n");
}

メモリ領域確保

PVOID ExAllocatePool(
  __drv_strictTypeMatch(__drv_typeExpr)POOL_TYPE PoolType,
  SIZE_T                                         NumberOfBytes
);
PWORK_QUEUE_ITEM WorkItem = 
(PWORK_QUEUE_ITEM)ExAllocatePool(NonPagedPool, sizeof(WORK_QUEUE_ITEM));

作業項目を割り当てて初期化

void ExInitializeWorkItem(
  PWORK_QUEUE_ITEM       Item,
  PWORKER_THREAD_ROUTINE Routine,
  PVOID                  Context
);
ExInitializeWorkItem(WorkItem, (PWORKER_THREAD_ROUTINE)myRoutine, WorkItem);

作業項目をキューに配置

ワークキュータイプ一覧:
基本的には、CustomPriorityWorkQueueを使用した方が良いです。
ユーザーモードではなくカーネルモードで動作するので、高い優先度でルーチンを回すと
他の重要な処理を妨げてしまいます。
Ring0では最新の注意を払う必要があります。

typedef enum _WORK_QUEUE_TYPE {
  CriticalWorkQueue,      //優先レベル13
  DelayedWorkQueue,       //優先レベル12
  HyperCriticalWorkQueue, //優先レベル15
  NormalWorkQueue,        //優先レベル8
  BackgroundWorkQueue,    //優先レベル7
  RealTimeWorkQueue,      //優先レベル18
  SuperCriticalWorkQueue, //優先レベル14
  MaximumWorkQueue,       //優先レベルなし
  CustomPriorityWorkQueue //優先レベル指定
} WORK_QUEUE_TYPE;

KeSetPriorityThreadでも優先レベルを変更できます。

KPRIORITY KeSetPriorityThread(
  PKTHREAD  Thread,
  KPRIORITY Priority
);

void ExQueueWorkItem(
  __drv_aliasesMem PWORK_QUEUE_ITEM WorkItem,
  WORK_QUEUE_TYPE                   QueueType
);
ExQueueWorkItem(WorkItem, DelayedWorkQueue);

リソース解放

IoUninitializeWorkItemして、IoFreeWorkItemします。

void IoUninitializeWorkItem(
  PIO_WORKITEM IoWorkItem
);
void IoFreeWorkItem(
  PIO_WORKITEM IoWorkItem
);
IoUninitializeWorkItem(WorkItem);
IoFreeWorkItem(WorkItem);

フルソースコード

driver.c
#include <wdm.h>

DRIVER_INITIALIZE DriverEntry;

VOID NTAPI myRoutine()
{
    DbgPrint("ROUTINE STARTED!\n");

    //やりたい処理
    DbgPrint("SETO KOUJI!\n");

    DbgPrint("ROUTINE FINISHED!\n");
}

NTSTATUS DriverEntry(PDRIVER_OBJECT dObject, PUNICODE_STRING regPath)
{
    UNREFERENCED_PARAMETER(dObject);
    UNREFERENCED_PARAMETER(regPath);

    NTSTATUS status = STATUS_SUCCESS;
    DbgPrint("HELLO WORLD!\n");

    //メモリ領域確保
    PWORK_QUEUE_ITEM WorkItem = (PWORK_QUEUE_ITEM)ExAllocatePool(NonPagedPool, sizeof(WORK_QUEUE_ITEM));
    ExInitializeWorkItem(WorkItem, (PWORKER_THREAD_ROUTINE)myRoutine, WorkItem);
    ExQueueWorkItem(WorkItem, DelayedWorkQueue);

    //リソース解放
    IoUninitializeWorkItem(WorkItem);
    IoFreeWorkItem(WorkItem);

    return status;
}

最後に

システムワーカースレッドは便利ですが、一歩間違えるとPC再起動まで永遠とシステムで動作するので、重いです。
あと、めっちゃ速いです。while(TRUE)すると数秒で数百万回ループします。流石Ring0

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした