zoukankan      html  css  js  c++  java
  • 驱动程序多线程 PsCreateSystemThread

      内核函数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);
    }
    

      

  • 相关阅读:
    Spring 事务不回滚
    Druid详细配置信息
    Servlet和JSP规范及版本对应关系
    CDN(内容分发网络)技术原理
    开发者需要了解的WebKit
    浏览器的渲染原理简介
    在浏览器中输入Google.com并且按下回车之后发生了什么?
    为什么说DOM操作很慢
    亿级Web系统搭建——单机到分布式集群
    linux下用rinetd做端口转发
  • 原文地址:https://www.cnblogs.com/lsh123/p/7357468.html
Copyright © 2011-2022 走看看