內核函數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);
}
