驱动程序多线程 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);
}
相关文章
相关标签/搜索