内核函数PsCreateSystemThread负责创建新线程。该函数可以创建两种线程,一种是用户线程,它属于当前进程中的线程。另一种是系统线程,系统线程不属于当前用户进程,而是属于系统进程,一般PID为4,名字为“System”的进程。
NTSTATUS PsCreateSystemThread( OUT PHANDLE ThreadHandle, //新创建的线程句柄 IN ULONG DesiredAccess, //创建的权限 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,//线程的属性,一般设为NULL IN HANDLE ProcessHandle OPTIONAL,//指定创建用户线程还是系统线程。如果为NULL,则为系统进程,如果该值是一个进程句柄,则新创建的线程属于这个指定的进程。DDK提供的NTCurrentProcess可以得到当前进程的句柄。 OUT PCLIENT_ID ClientId OPTIONAL, IN PKSTART_ROUTINE StartRoutine,//新线程的运行地址 IN PVOID StartContext //新线程接收的参数 );
在内核模式下创建的线程是无法自动退出的,必须使用PsTerminateSystemThread强制结束线程。
通过内核事件KEVENT和内核等待KeWaitForSingleObject来演示事件的创建过程。
KEVENT Event; //创建一个同步事件 KeInitializeEvent( &Event, //要初始化的KEVENT结构对象 SynchronizationEvent, //事件类型 FALSE);
KeSetEvent(
&Event, //被激活的事件
IO_NO_INCREMENT, //被唤醒线程临时提升线程优先级的增量,传0
FALSE); //If TRUE, the KeSetEvent call must be followed by a call to KeWaitForMultipleObjects, KeWaitForMutexObject, or KeWaitForSingleObject.
KeWaitForSingleObject(
&Event, //同步对象的指针,
Executive, //等待的原因,一般为Executive
KernelMode, //等待模式,一般为KernelMode
FALSE, //指明等待是否为“警惕”的,一般为FALSE
NULL); //等待时间,如果为NULL,就表示无限期等待,直到同步对象变为激发态
DbgPrint("ThreadProcedure() Exit
");
PsTerminateSystemThread(STATUS_SUCCESS);
总结一下代码流程:
1.驱动程序KeInitializeEvent创建了一个内核事件
2.PsCreateSystemThread创建新的系统线程,将创建好的KEVENT结构传参给新创建的线程。 再调用KeSetEvent将事件激活
3.线程中调用KeWaitForSingleObject等待事件激活状态(受信),执行后续代码,最后PsTerminateSystemThread结束线程。
源代码:
KEvent.h
#pragma once #include <ntifs.h> #define DELAY_ONE_MICROSECOND (-10) #define DELAY_ONE_MILLISECOND (DELAY_ONE_MICROSECOND*1000) VOID DriverUnload(PDRIVER_OBJECT DriverObject); VOID KSleep(LONG MilliSecond); void ThreadProcedure(PVOID ParameterData);
KEvent.c
#include "KEvent.h"
//http://www.cnblogs.com/dacainiao/p/5923147.html
//同步事件(SynchronizationEvent)
//当事件对象为激发时,如遇到KeWaitForXX等内核函数,事件对象则自动变回未激发态
//通知事件(NotificationEvent)
//当事件对象为激发时,如遇到KeWaitForXX等内核函数,事件对象则不会变回未激发态
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath)
{
int i = 0;
NTSTATUS Status = STATUS_SUCCESS;
HANDLE ThreadHandle = NULL;
PDEVICE_OBJECT DeviceObject = NULL;
KEVENT Event;
CLIENT_ID ClientID = {0};
DriverObject->DriverUnload = DriverUnload;
//创建一个同步事件
KeInitializeEvent(
&Event, //要初始化的KEVENT结构对象
SynchronizationEvent, //事件类型
FALSE); //如果为真,初始为激发态
//创建一个通知事件
//KeInitializeEvent(&Event, NotificationEvent,
// FALSE);
//创建一个System进程下运行的线程
for (i=0;i<2;i++)
{
Status = PsCreateSystemThread(
&ThreadHandle, //新创建的线程句柄
0, //创建的权限
NULL, //线程的属性,一般设为NULL
NtCurrentProcess(), //指定创建用户线程还是系统线程。如果为NULL,则为系统进程,如果该值是一个进程句柄,则新创建的线程属于这个指定的进程。DDK的NTCurrentProcess可以得到当前进程的句柄。
&ClientID,
(PKSTART_ROUTINE)ThreadProcedure, //新线程的运行地址
(PVOID)&Event); //新线程接收的参数
}
KSleep(3000);
KeSetEvent(
&Event, //被激活的事件
IO_NO_INCREMENT, //被唤醒线程临时提升线程优先级的增量,传0
FALSE); //If TRUE, the KeSetEvent call must be followed by a call to KeWaitForMultipleObjects, KeWaitForMutexObject, or KeWaitForSingleObject.
return Status;
}
void ThreadProcedure(PVOID ParameterData)
{
KEVENT Event = *((PKEVENT)ParameterData);
NTSTATUS Status;
KeWaitForSingleObject(
&Event, //同步对象的指针,
Executive, //等待的原因,一般为Executive
KernelMode, //等待模式,一般为KernelMode
FALSE, //指明等待是否为“警惕”的,一般为FALSE
NULL); //等待时间,如果为NULL,就表示无限期等待,直到同步对象变为激发态
DbgPrint("ThreadProcedure() Exit
");
PsTerminateSystemThread(STATUS_SUCCESS);
}
VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
DbgPrint("DriverUnload()
");
}
VOID KSleep(LONG MilliSecond)
{
LARGE_INTEGER Interval = {0};
Interval.QuadPart = DELAY_ONE_MILLISECOND;
Interval.QuadPart *= MilliSecond;
KeDelayExecutionThread(KernelMode, 0, &Interval);
}