转载请注明来源:
enjoy5512的博客 : http://blog.csdn.net/enjoy5512
GitHub : https://github.com/whu-enjoy


.1. 使用系统线程

PsCreateSystemThread

NTSTATUS
PsCreateSystemThread(
_Out_PHANDLE ThreadHandle,
_In_ULONG DesiredAccess, //所需访问权限
_In_opt_POBJECT_ATTRIBUTES ObjectAttributes,
_In_opt_HANDLE ProcessHandle,
_Out_opt_PCLIENT_ID ClientId,
_In_PKSTART_ROUTINE StartRoutine,//线程中要执行的函数
_In_opt_PVOID StartContext//传递给上述要执行的函数的参数
); Parameters
ThreadHandle[out] 线程句柄[输出参数]
指向一个用于接收此句柄的变量。一旦此句柄 不再使用,驱动必须用ZwClose关闭此句柄。此句柄在WindowsVista 及以后版本的Windows系统中是内核句柄。在较早版本的Windows 里,此句柄不可以是内核句柄。 DesiredAccess[in]所需访问权限[输入参数]
指定ACCESS_MASK值用于指明对所创建线程的存取权限要求。 ObjectAttributes[in, optional]对象属性[输入参数,可选]
指向一个结构,它指定对象的属性。OBJ_PERMANENT,OBJ_EXCLUSIVE,和OBJ_OPENIF不是线程对象的有效属性。在Windows XP和更高版本的Windows,如果对方不在系统进程的上下文中运行,它必须为ObjectAttributes设置OBJ_KERNEL_HANDLE属性。对微软的Windows 2000和Windows 98/Me的驱动必须只在系统进程上下文中调用PsCreateSystemThread。对于WindowsVista 及其后版本的WindowsVista,此句柄将是一个内核句柄。 ProcessHandle[in, optional] 进程句柄[输入参数,可选]
指定“在其地址空间中运行线程的那个进程”的一个打开的句柄。调用者的线程必须对这个进程有process_create_thread访问权限。如果不提供此参数,则将在初始系统进程中创建线程。在为一个驱动程序创建的线程里,这个值应该是空的。可使用定义在ntddk.H中的NtCurrentProcess宏,来指定当前进程。 ClientId[out, optional]客户标识[输出参数,可选]
指向用于“接收新线程的客户端标识符”的结构。在为一个驱动程序创建的线程里,这个值应该是空的。 StartRoutine[in]开始例程[输入参数]
新创建的系统线程的入口点。这个参数是一个函数指针,指向能接收一个参数的ThreadStart例程,参数值是由调用者提供的startcontext参数。 StartContext[in, optional]开始语境[输入参数,可选]
当本函数(PsCreateSystemThread)开始执行时,提供一个单独的参数传递给所创建的线程。 返回值
PsCreateSystemThread如果成功创建线程则返回STATUS_SUCCESS.
  • 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

2. 线程中睡眠

NTSTATUS KeDelayExecutionThread(
_In_ KPROCESSOR_MODE WaitMode,
_In_ BOOLEAN Alertable,
_In_ PLARGE_INTEGER Interval
); Parameters WaitMode [in]
Specifies the processor mode in which the caller is waiting, which can be either KernelMode or UserMode. Lower-level drivers should specify KernelMode. Alertable [in]
Specifies TRUE if the wait is alertable. Lower-level drivers should specify FALSE. Interval [in]
Specifies the absolute or relative time, in units of 100 nanoseconds, for which the wait is to occur. A negative value indicates relative time. Absolute expiration times track any changes in system time; relative expiration times are not affected by system time changes. Return value
KeDelayExecutionThread returns one of the following values that describes how the delay was completed:
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
Return code Description
STATUS_SUCCESS The delay completed because the specified interval elapsed.
STATUS_ALERTED The delay completed because the thread was alerted.
STATUS_USER_APC A user-mode APC was delivered before the specified Interval expired.

Note that the NT_SUCCESS macro recognizes all of these status values as “success” values.


3. 使用同步事件

VOID
KeInitializeEvent(
IN PRKEVENT Event, // 这个参数是初始化事件对象的指针
IN EVENT_TYPE Type, // 这个参数是事件的类型。一类是“通知事件”对应参数为 NotificationEvent。另一类是“同步事件”,对应参数 SynchronizationEvent
IN BOOLEAN State // TRUE:事件对象初始化状态为激发。FALSE:事件对象初始化状态为未激发
);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
LONG KeSetEvent(
_Inout_ PRKEVENT Event,
_In_ KPRIORITY Increment,
_In_ BOOLEAN Wait
); Parameters Event [in, out]
A pointer to an initialized event object for which the caller provides the storage. Increment [in]
Specifies the priority increment to be applied if setting the event causes a wait to be satisfied. Wait [in]
Specifies whether the call to KeSetEvent is to be followed immediately by a call to one of the KeWaitXxx routines. If TRUE, the KeSetEvent call must be followed by a call to KeWaitForMultipleObjects, KeWaitForMutexObject, or KeWaitForSingleObject. For more information, see the following Remarks section. Return value
If the previous state of the event object was signaled, a nonzero value is returned.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
NTSTATUS KeWaitForSingleObject(
_In_ PVOID Object,
_In_ KWAIT_REASON WaitReason,
_In_ KPROCESSOR_MODE WaitMode,
_In_ BOOLEAN Alertable,
_In_opt_ PLARGE_INTEGER Timeout
); Parameters Object [in]
Pointer to an initialized dispatcher object (event, mutex, semaphore, thread, or timer) for which the caller supplies the storage. WaitReason [in]
Specifies the reason for the wait. A driver should set this value to Executive, unless it is doing work on behalf of a user and is running in the context of a user thread, in which case it should set this value to UserRequest. WaitMode [in]
Specifies whether the caller waits in KernelMode or UserMode. Lowest-level and intermediate drivers should specify KernelMode. If the given Object is a mutex, the caller must specify KernelMode. Alertable [in]
Specifies a Boolean value that is TRUE if the wait is alertable and FALSE otherwise. Timeout [in, optional]
Pointer to a time-out value that specifies the absolute or relative time, in 100-nanosecond units, at which the wait is to be completed.
A positive value specifies an absolute time, relative to January 1, 1601. A negative value specifies an interval relative to the current time. Absolute expiration times track any changes in the system time; relative expiration times are not affected by system time changes.
If *Timeout = 0, the routine returns without waiting. If the caller supplies a NULL pointer, the routine waits indefinitely until the dispatcher object is set to the signaled state. For more information, see the following Remarks section. Return value
KeWaitForSingleObject can return one of the following:
  • 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
Return code Description
STATUS_SUCCESS The dispatcher object specified by the Object parameter satisfied the wait.
STATUS_ALERTED The wait was interrupted to deliver an alert to the calling thread.
STATUS_USER_APC The wait was interrupted to deliver a user asynchronous procedure call (APC) to the calling thread.
STATUS_TIMEOUT A time-out occurred before the object was set to a signaled state. This value can be returned when the specified set of wait conditions cannot be immediately met and Timeout is set to zero.

Note that the NT_SUCCESS macro recognizes all of these status values as “success” values.


4. 示例代码

static KEVENT s_Event

//程序说明开始
//==================================================================================
// 功能 : 测试线程函数
// 参数 :
// (入口)
// (出口) 无
// 返回 : VOID
// 主要思路 :
// 调用举例 :
// 日期 : 2016年7月7日 07:24:03 - 2016年7月7日 07:44:41
//==================================================================================
//程序说明结束
NTSTATUS
Thread()
{
static UNICODE_STRING str = RTL_CONSTANT_STRING(L"test thread");
HANDLE ThreadHandle = NULL;
NTSTATUS Status = STATUS_SUCCESS; KdPrint(("启动线程函数\n"));
//初始化事件
//第二个参数是事件的类型,一类是“通知事件”,对应参数是NotificationEvent。
//另一类是“同步事件”,对应是SynchronizationEvent
//第三个参数如果为真,事件对象的初始化状态为激发状态。
//如果为假,则事件对象的初始化状态为未激发状态
//如果创建的事件对象是“通知事件”,当事件对象变为激发状态时,
//程序员需要手动将其改回未激发
//如果创建的事件对象是“同步事件”,当事件对象为激发状态时,
//如果遇到KeWaitForXXX等内核函数,事件对象则自动变回未激发状态
// 当是TRUE 时初始化事件是有信号状态.,当是FALSE时初始化事件是没信号状态,
//如果此处为TRUE,则为有信号状态,KeWaitForSingleObject会直接通过,
//此时需要调用KeResetEvent来设置为无信号
KeInitializeEvent(&s_Event, SynchronizationEvent, FALSE);
//KeResetEvent(&s_Event);//指定的事件对象设置为无信号状态。 //启动线程
Status = PsCreateSystemThread(
&ThreadHandle,
0,NULL,NULL,NULL,
ThreadProc,
(PVOID)&str);
if (!NT_SUCCESS(Status))
{
DbgPrint("线程启动失败!!-%#X");
return Status;
} //Do Something
KdPrint(("做一些事!!\n")); KdPrint(("线程启动函数结束!!\n"));
ZwClose(ThreadHandle);
KeWaitForSingleObject(&s_Event, Executive, KernelMode, 0, 0);
KdPrint(("线程启动函数返回!!\n"));
return Status;
} //程序说明开始
//==================================================================================
// 功能 : 线程函数
// 参数 :
// (入口)
// (出口) 无
// 返回 : VOID
// 主要思路 :
// 调用举例 :
// 日期 : 2016年7月7日 07:44:29 - 2016年7月7日 08:51:17
//==================================================================================
//程序说明结束
VOID
ThreadProc(__in PVOID Context)
{
PUNICODE_STRING str = (PUNICODE_STRING)Context;
LARGE_INTEGER Interval;
LONG Msec = 3000; //打印字符串
KdPrint(("进入线程函数 : %wZ\n", str)); //Msec若为1000,则 睡眠的时间为: 1000 * 100 ns * 10 *1000 =1s
Interval.QuadPart = DELAY_ONE_MILLISECOND;
Interval.QuadPart *= Msec; GetTime();
GetTime();
KeDelayExecutionThread(KernelMode, 0, &Interval);
GetTime(); KdPrint(("线程函数结束\n"));
//设置事件
KeSetEvent(&s_Event, 0, TRUE);
//结束自己
PsTerminateSystemThread(STATUS_SUCCESS);
}
  • 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
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • jpg 改 rar 

Windows驱动开发之线程与同步事件的更多相关文章

  1. C++第三十三篇 -- 研究一下Windows驱动开发(一)内部构造介绍

    因为工作原因,需要做一些与网卡有关的测试,其中涉及到了驱动这一块的知识,虽然程序可以运行,但是不搞清楚,心里总是不安,觉得没理解清楚.因此想看一下驱动开发.查了很多资料,看到有人推荐Windows驱动 ...

  2. Windows 驱动开发 - 5

    上篇<Windows 驱动开发 - 4>我们已经完毕了硬件准备. 可是我们还没有详细的数据操作,比如接收读写操作. 在WDF中进行此类操作前须要进行设备的IO控制,已保持数据的完整性. 我 ...

  3. windows 驱动开发入门——驱动中的数据结构

    最近在学习驱动编程方面的内容,在这将自己的一些心得分享出来,供大家参考,与大家共同进步,本人学习驱动主要是通过两本书--<独钓寒江 windows安全编程> 和 <windows驱动 ...

  4. Windows 驱动开发 - 7

    在<Windows 驱动开发 - 5>我们所说的读写操作在本篇实现. 在WDF中实现此功能主要为:EvtIoRead和EvtIoWrite. 首先,在EvtDeviceAdd设置以上两个回 ...

  5. Windows 驱动开发 - 8

    最后的一点开发工作:跟踪驱动. 一.驱动跟踪 1. 包括TMH头文件 #include "step5.tmh" 2. 初始化跟踪 在DriverEntry中初始化. WPP_INI ...

  6. Windows驱动开发-IRP的完成例程

    <Windows驱动开发技术详解 >331页, 在将IRP发送给底层驱动或其他驱动之前,可以对IRP设置一个完成例程,一旦底层驱动将IRP完成后,IRP完成例程立刻被处罚,通过设置完成例程 ...

  7. Windows驱动开发(中间层)

    Windows驱动开发 一.前言 依据<Windows内核安全与驱动开发>及MSDN等网络质料进行学习开发. 二.初步环境 1.下载安装WDK7.1.0(WinDDK\7600.16385 ...

  8. [Windows驱动开发](一)序言

    笔者学习驱动编程是从两本书入门的.它们分别是<寒江独钓——内核安全编程>和<Windows驱动开发技术详解>.两本书分别从不同的角度介绍了驱动程序的制作方法. 在我理解,驱动程 ...

  9. windows驱动开发推荐书籍

    [作者] 猪头三 个人网站 :http://www.x86asm.com/ [序言] 很多人都对驱动开发有兴趣,但往往找不到正确的学习方式.当然这跟驱动开发的本土化资料少有关系.大多学的驱动开发资料都 ...

随机推荐

  1. (笔记)Linux下的简单CGI编程

    为什么要进行CGI编程?  在HTML中,当客户填写了表单,并按下了发送(submit)按钮后,表单的内容被发送到了服务器端,一般的,这时就需要有一个服务器端脚本来对表单的内容进行一些处理,或者是把它 ...

  2. Java数组排序和搜索

    如何排序数组并搜索其中的元素? 以下示例显示如何使用sort()和binarySearch()方法来完成任务.用户定义的方法printArray()用于显示数组输出: package com.yiib ...

  3. 我的openwrt开发相关文章

    openwrt学习笔记: 在openwrt的学习过程中,走了非常多的弯路.一直以来有个期盼.希望能够出个简易教程,希望openwrt的同仁们能够更加高速的入手. . openwrt学习笔记(三十二): ...

  4. VS2013 此模板尝试加载组件程序集”NuGet.VisualStudio.interop,Version=1.0.0.0 的解决办法

    此模板尝试加载组件程序集 NuGet.VisualStudio.Interop   分析错误 既然错误信息提示模板尝试加载组件程序集,那说明NuGet.VisualStudio.Interop程序集不 ...

  5. dendrogram 和 barplot 的组合

    示例代码: data <- mtcars[1:10, ] hc <- hclust(dist(data)) hcd <- as.dendrogram(hc) par(mfrow = ...

  6. Java常量池的理解

    1.常量池的好处常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现了对象的共享.例如字符串常量池,在编译阶段就把所有的字符串文字放到一个常量池中.(1)节省内存空间:常量池中所有相同的字符串常 ...

  7. 单用户模式&救援模式&克隆虚拟机&Linux机器相互登录

    1.13 单用户模式 1.14 救援模式 1.15 克隆虚拟机 1.16 Linux机器相互登录 1.单用户模式 关机:init 0 .poweroff 重启:init 6 .reboot 关机:in ...

  8. A potentially dangerous Request.Path value was detected from the client异常解决方案

    场景: 当URL中存在“<,>,*,%,&,:,/”特殊字符时,页面会抛出A potentially dangerous Request.Path value was detect ...

  9. 基于maven使用IDEA创建多模块项目

    原文地址:http://blog.csdn.net/williamhappy/article/details/54376855 鉴于最近学习一个分布式项目的开发,讲一下关于使用IntelliJ IDE ...

  10. npm install mongoose错误解决

    今天安装mongoose一直报错,上图 具体的错误记录: info it worked if it ends with ok verbose cli [ 'C:\\Program Files\\nod ...