內核函數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\r\n"); 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\r\n"); PsTerminateSystemThread(STATUS_SUCCESS); } VOID DriverUnload(PDRIVER_OBJECT DriverObject) { DbgPrint("DriverUnload()\r\n"); } VOID KSleep(LONG MilliSecond) { LARGE_INTEGER Interval = {0}; Interval.QuadPart = DELAY_ONE_MILLISECOND; Interval.QuadPart *= MilliSecond; KeDelayExecutionThread(KernelMode, 0, &Interval); }