Joe1sn's Cabin

windows内核驱动 8-计时器与通知

在内核中使用定时器、通知和回调

…学到一半打靶场去了

定时器

CPU最短能统计时间为100纳秒 100ns

内核中使用LARGEINT来表示时间长度

1s = -10 *1000 * 1000

基于设备的IO定时器

DriverEntry里面尝试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
VOID TimeWorker(PVOID CONTEXT) {
DbgPrint("Irql: %d\n", KeGetCurrentIrql());
DbgPrint("Process: %s\n", PsGetProcessImageFileName(PsGetCurrentProcess()));
}
NTSTATUS
DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
// ...
IoInitializeTimer(pDevice, TimeWorker, NULL);
IoStartTimer(pDevice);
}
Unload(){
IoStopTimer(DriverObject->DeviceObject);
}

image-20240327161718432

主要API

  • IoInitializeTimer:创建定时

  • IoStartTimer:开启定时

  • IoStopTimer:关闭定时

技巧

  • 同时启用两个定时器可以关闭PCHUNTER
  • 做认证

结合DPC的定时器

1
2
3
4
5
6
7
8
9
10
11
12
//全局变量
KDPC kDPC = { 0 };
LARGE_INTEGER DpcTime = { 0 };

KeInitializeTimer(&keTimer);
KDPC kDPC = { 0 };
KeInitializeDpc(&kDPC, &DpcRoutineFunc, NULL);
LARGE_INTEGER DpcTime = { 0 };
DpcTime.QuadPart = -10 * 1000 * 2000;
KeSetTimer(&keTimer, DpcTime, &kDPC);

KeCancelTimer(&keTimer);

image-20240327164409369

  • 后续可以通过KeWait来判断超时之类的
  • 这个只会触发一次

放在工作队列线程池中运行

1
2
ExInitializeWorkItem(&work_item, WorkItemRoutine, NULL);
ExQueueWorkItem(&work_item, CriticalWorkQueue);

image-20240327170200351

  • 例程级别很低
  • WorkItemRoutine别陷入死循环,同步

通知

通知:发生某一件事变更,知道事情变更,但不能操作变更的结果。PsCreateNotify

回调:能拦截相关信息,更改流程和结果。

windows内核驱动 6-链表与进程讲了部分

模块加载回调:

使用PsGetProcessImageFileName需要添加声明

1
PCHAR PsGetProcessImageFileName(PEPROCESS EProcess);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
VOID ImageRoutine(
PUNICODE_STRING FullImageName,
HANDLE ProcessId, // pid into which image is being mapped
PIMAGE_INFO ImageInfo
) {
//DbgPrint("Triigered callback\n");
PEPROCESS temppe = NULL;
NTSTATUS status = STATUS_SUCCESS;
status = PsLookupProcessByProcessId(ProcessId, &temppe);
if (NT_SUCCESS(status)) {
ObDereferenceObject(temppe);
PUCHAR imagename = PsGetProcessImageFileName(temppe);
DbgPrint("[%s] load [%wZ] with baseaddr [%llx]\n", imagename, FullImageName, ImageInfo->ImageBase);
}
//DbgPrint("FullImageName: %wZ---PID: %d\n", FullImageName, ProcessId);

}

// PsSetCreateProcessNotifyRoutine()
PsSetLoadImageNotifyRoutine(ImageRoutine);
PsRemoveLoadImageNotifyRoutine(ImageRoutine);

image-20240327175140251

其他的也很类似

PsSetCreateThreadNotifyRoutine

对应的注销语句PsRemoveCreateThreadNotifyRoutine

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <ntifs.h>

PCHAR PsGetProcessImageFileName(PEPROCESS EProcess);

VOID MyCreateThreadNotify(
HANDLE ProcessId,
HANDLE ThreadId,
BOOLEAN Create) {

if (Create) {
PEPROCESS temppe = NULL;
NTSTATUS status = STATUS_SUCCESS;
status = PsLookupProcessByProcessId(ProcessId, &temppe);
if (NT_SUCCESS(status)) {
ObDereferenceObject(temppe);
PCHAR imageName = PsGetProcessImageFileName(temppe);
DbgPrint("[%s] create thread <%d>\n", imageName, ThreadId);
}
}
}

VOID
DriverUnload(PDRIVER_OBJECT DriverObject)
{
UNREFERENCED_PARAMETER(DriverObject);
DbgPrint("Driver Stopping -> %wZ\n", &DriverObject->DriverName);
PsRemoveCreateThreadNotifyRoutine(MyCreateThreadNotify);
}

NTSTATUS
DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
UNREFERENCED_PARAMETER(RegistryPath);

DbgPrint("Driver Running -> %wZ\n", &DriverObject->DriverName);
DriverObject->DriverUnload = DriverUnload;

NTSTATUS status = STATUS_SUCCESS;
status = PsSetCreateThreadNotifyRoutine(MyCreateThreadNotify);

return STATUS_SUCCESS;
}

image-20260306193335115

利用掩码设置0b111,全部写0,移除回调,但是只能停止已经注册掉的开关

image-20260306194738678