驱动程序多线程 PsCreateSystemThread

内核函数PsCreateSystemThread负责创建新线程。该函数可以创建两种线程,一种是用户线程,它属于当前进程中的线程。另一种是系统线程,系统线程不属于当前用户进程,而是属于系统进程,一般PID为4,名字为“System”的进程。

1

2

3

4

5

6

7

8

9

10

扫描二维码关注公众号,回复: 2404555 查看本文章

11

12

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来演示事件的创建过程。

   

1

2

3

4

5

6

7

KEVENT Event;

//创建一个同步事件

KeInitializeEvent(

    &Event,               //要初始化的KEVENT结构对象

    SynchronizationEvent, //事件类型

    FALSE);       <br><br>

      KeSetEvent(
        &Event, //被激活的事件
        IO_NO_INCREMENT, //被唤醒线程临时提升线程优先级的增量,传0
        FALSE); //If TRUE, the KeSetEvent call must be followed by a call to KeWaitForMultipleObjects, KeWaitForMutexObject, or KeWaitForSingleObject.

  

1

2

3

4

5

6

7

8

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

1

2

3

4

5

6

7

8

9

10

11

12

#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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

#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);

}

猜你喜欢

转载自blog.csdn.net/qq1841370452/article/details/81231074