驅動程序多線程 PsCreateSystemThread

  內核函數PsCreateSystemThread負責建立新線程。該函數能夠建立兩種線程,一種是用戶線程,它屬於當前進程中的線程。另外一種是系統線程,系統線程不屬於當前用戶進程,而是屬於系統進程,通常PID爲4,名字爲「System」的進程。html

    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來演示事件的建立過程。spa

   

	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建立了一個內核事件
htm

                2.PsCreateSystemThread建立新的系統線程,將建立好的KEVENT結構傳參給新建立的線程。 再調用KeSetEvent事件激活對象

                3.線程中調用KeWaitForSingleObject等待事件激活狀態(受信),執行後續代碼,最後PsTerminateSystemThread結束線程blog

 

  源代碼:進程

 

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);
}
相關文章
相關標籤/搜索