转载请注明来源:
enjoy5512的博客 : http://blog.csdn.net/enjoy5512
GitHub : https://github.com/whu-enjoy
1. 在驱动中使用文件
在Windows执行体中,通过文件对象来代表文件,该文件对象是一种由对象管理器管理的执行体对象。例如:目录也是由文件对象代表的。
内核组件通过对象名来引用文件,即在文件的全路径前面加\DosDevices。(在Windows 2000及后续操作系统中,\??等同于\DosDevices)。例如,文件C:\WINDOWS\example.txt的对象名为\DosDevices\C:\WINDOWS\example.txt。你需要用对象名来打开文件以获取句柄。
使用文件步骤:
1. 打开文件返回文件句柄。
2. 调用合适的ZwXxxFile 函数以完成对文件的操作。
3. 调用ZwClose函数关闭打开的文件句柄。
当打开一个指向文件的文件句柄时,Windows执行体就创建了一个文件对象来代表该文件,同时返回一个代表该对象的文件句柄。因此,对于单个文件来说,会存在多个文件对象的情况。同样,由于用户模式的应用程序可能会复制文件句柄,因此,对于同一个文件对象,也会存在多个文件句柄。只有当所有指向一个文件对象的文件句柄都关闭后,Windows执行体才会删除该文件对象。
1.1 打开文件句柄
- 定义一个OBJECT_ATTRIBUTES结构体变量,然后调用InitializeObjectAttributes函数初始化该变量。关键是设置改变量的ObjectName字段为文件对象名。
InitializeObjectAttributes宏,初始化一个OBJECT_ATTRIBUTES结构体,它指定对象句柄的属性,供打开句柄的例程使用。VOID InitializeObjectAttributes([out] POBJECT_ATTRIBUTES InitializedAttributes,[in] PUNICODE_STRING ObjectName,[in] ULONG Attributes,[in] HANDLE RootDirectory,[in, optional] PSECURITY_DESCRIPTOR SecurityDescriptor);参数:InitializedAttributes [out]指定要初始化的OBJECT_ATTRIBUTES结构体指针。ObjectName [in]一个指向UNICODE字符串对象的指针,它包含将要打开句柄的对象名称。它必须是一个完整的对象名称或者是相对于RootDirectory参数指定目录的相对路径。Attributes [in]指定一个或多个以下列标志:OBJ_INHERIT这个句柄可以被当前进程的子进程继承。OBJ_PERMANENT此标志仅应用于对象管理器命名的对象。默认情况下,这样的对象会在关闭所有它们打开的句柄时删除。如果指定了此标志,对象不会在所有打开的句柄关闭时删除,驱动可以使用ZwMakeTemporaryObject删除固定的对象。OBJ_EXCLUSIVE这个对象只可以有一个打开的句柄。意味着仅有一个进程可以访问此对象。OBJ_CASE_INSENSITIVE如果指定了此标志,在对ObjectName参数与已存在的对象名称进行匹配时,会不区分大小写。OBJ_OPENIF如果在创建对象的例程中指定此标志,当对象已经存在时,例程将会打开些对象。否则,创建对象的例程会返回值为STATUS_OBJECT_NAME_COLLISION的NTSTATUS代码。OBJ_KERNEL_HANDLE指定句柄仅能在内核模式访问。OBJ_FORCE_ACCESS_CHECK打开句柄的例程,应执行所有的访问检查,即使是在内核模式下也如此。RootDirectory [in]root目录对象句柄,用于ObjectName参数指定的相对路径时。如果ObjectName参数是一个完整的对象名,RootDirectory是NULL。使用ZwCreateDirectoryObject获取对象目录的句柄。SecurityDescriptor [in, optional]指定对象创建时应用的一个安全描述符。此参数是可选的。对象如果接受默认的安全设置,驱动程序可以指定NULL。更多信息,参见下面的备注节。返回值:无备注:InitializeObjectAttributes初始化一个OBJECT_ATTRIBUTES结构体,它设置将被打开的对象句柄的属性。调用者可以传递一个此结构的指针到实际打开句柄的例程。驱动程序运行进程上下文中,若要运行在系统进程,需要设置OBJ_KERNEL_HANDLE标志到Attributes参数。这个标志限制,使用此打开的句柄的进程仅能运行在内核模式。否则句柄可以在驱动运行的进程上下文中访问。注意,InitializeObjectAttributes始终设置OBJCECT_ATTRIBUTES的SecurityQualityOfService成员为NULL。如果驱动程序需要一个非空的值,可以直接设置SecurityQualityOfService成员。
- 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
- 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
2 调用IoCreateFile, ZwCreateFile, 或者 ZwOpenFile,传递上面定义的结构体变量,成功就会返回执行该文件的句柄。
注:驱动一般用ZwCreateFile和ZwOpenFile,IoCreateFile很少使用,当调用ZwCreateFile,ZwOpenFile或IoCreateFile时,Windows执行体创建一个代表该文件的新的文件对象,并返回一个指向该对象的句柄。文件对象一直存在,知道你关闭了所有指向它的文件句柄。
原型:NTSYSAPINTSTATUSNTAPIZwCreateFile(OUT PHANDLE FileHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,OUT PIO_STATUS_BLOCK IoStatusBlock,IN PLARGE_INTEGER AllocationSize OPTIONAL,IN ULONG FileAttributes,IN ULONG ShareAccess,IN ULONG CreateDisposition,IN ULONG CreateOptions,IN PVOID EaBuffer OPTIONAL,IN ULONG EaLength);参数理解:OUT-FileHandle--------这是一个指向一个变量的指针,用来最后存放file object handle的IN-DesiredAccess----这个参数指定一个访问权限,大概有以下的权限:FILE_ANY_ACCESS 0x0000 FILE_READ_ACCESS 0x0001 FILE_READ_DATA 0x0001 FILE_LIST_DIRECTORY 0x0001 FILE_WRITE_ACCESS 0x0002 FILE_WRITE_DATA 0x0002 FILE_ADD_FILE 0x0002 FILE_APPEND_DATA 0x0004 FILE_ADD_SUBDIRECTORY 0x0004 FILE_CREATE_PIPE_INSTANCE 0x0004 FILE_READ_EA 0x0008 FILE_WRITE_EA 0x0010 FILE_EXECUTE 0x0020 FILE_TRAVERSE 0x0020 FILE_DELETE_CHILD 0x0040 FILE_READ_ATTRIBUTES 0x0080 FILE_WRITE_ATTRIBUTES 0x0100 FILE_ALL_ACCESS STANDARD_RIGHTS_ALL最后一个权限最大,这里面要注意的是范围问题,有的值只适合目录,有的只适合管道,有的只适合命名管道,有的同时适用,想下这个地方可以做什么文章ObjectAttributes---指向下面这个结构的一个变量,就是来表明文件对象的属性的。typedef struct _OBJECT_ATTRIBUTES {ULONG Length;HANDLE RootDirectory;PUNICODE_STRING ObjectName;ULONG Attributes;PVOID SecurityDescriptor; PVOID SecurityQualityOfService; } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;这个结构是针对很多对象的,不光是针对文件对象的,所以OBJ_PERMANENT(永久), OBJ_EXCLUSIVE(互斥),and OBJ_OPENLINK这三个实际上对于文件对象来说始终是无效的IoStatusBlock-----这个也是个指针变量,指向一个叫做IO_STATUS_BLOCK的结构体,最后函数返回的时候,这个结构体的成员 里面要填充一些值,具体的呢就是完成状态,请求操作的一些信息,最重要的一个成员就是Information成员,他显示了函数对文件的处理方式,他的值 可能是下面的几个:FILE_SUPERSEDED(替代)FILE_OPENED(打开)FILE_CREATED(创建)FILE_OVERWRITTEN(重写)FILE_EXISTS(存在)FILE_DOES_NOT_EXIST(文件不存在)再看下这个IO_STATUS_BLOCK的具体结构:typedef struct _IO_STATUS_BLOCK {union {NTSTATUS Status;PVOID Pointer;} DUMMYUNIONNAME;ULONG_PTR Information;} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;AllocationSize---这是个可选的参数,他是指定初始化文件需要的内存字节数的,所以可向而知,他只有在真正的涉及到文件创建的时候才有意义,也就是说创建,重写,替换这些操作的时候。指向一个LARGE_INTEGER:typedef union _LARGE_INTEGER {_ANONYMOUS_STRUCT struct{ULONG LowPart;LONG HighPart;} DUMMYSTRUCTNAME;struct{ULONG LowPart;LONG HighPart;} u;#endif LONGLONG QuadPart;} LARGE_INTEGER, *PLARGE_INTEGER;FileAttributes---这个参数指定文件的属性,刚才是文件对象的属性。可以是以下的:FILE_ATTRIBUTE_READONLYFILE_ATTRIBUTE_HIDDENFILE_ATTRIBUTE_SYSTEMFILE_ATTRIBUTE_DIRECTORYFILE_ATTRIBUTE_ARCHIVEFILE_ATTRIBUTE_NORMALFILE_ATTRIBUTE_TEMPORARYFILE_ATTRIBUTE_SPARSE_FILEFILE_ATTRIBUTE_REPARSE_POINTFILE_ATTRIBUTE_COMPRESSEDFILE_ATTRIBUTE_OFFLINEFILE_ATTRIBUTE_NOT_CONTENT_INDEXEDFILE_ATTRIBUTE_ENCRYPTEDShareAccess---指定共享的权限,以下三种的组合:FILE_SHARE_READFILE_SHARE_WRITEFILE_SHARE_DELETECreateDisposition---这个参数指定要对文件干嘛,可以是下面的值:FILE_SUPERSEDEFILE_OPENFILE_CREATEFILE_OPEN_IFFILE_OVERWRITEFILE_OVERWRITE_IFCreateOptions---这个参数指定创建或者打开文件的时候做的一些事情,可以是以下的组合:FILE_DIRECTORY_FILEFILE_WRITE_THROUGHFILE_SEQUENTIAL_ONLYFILE_NO_INTERMEDIATE_BUFFERINGFILE_SYNCHRONOUS_IO_ALERTFILE_SYNCHRONOUS_IO_NONALERTFILE_NON_DIRECTORY_FILEFILE_CREATE_TREE_CONNECTIONFILE_COMPLETE_IF_OPLOCKEDFILE_NO_EA_KNOWLEDGEFILE_OPEN_FOR_RECOVERYFILE_RANDOM_ACCESSFILE_DELETE_ON_CLOSEFILE_OPEN_BY_FILE_IDFILE_OPEN_FOR_BACKUP_INTENTFILE_NO_COMPRESSIONFILE_RESERVE_OPFILTERFILE_OPEN_REPARSE_POINTFILE_OPEN_NO_RECALLFILE_OPEN_FOR_FREE_SPACE_QUERYEaBuffer---这个是个可选的参数,用来存放一些扩展的属性EaLength---存放扩展属性的字节大小返回值理解:如果成功,返回STATUS_SUCCESS如果失败,返回STATUS_ACCESS_DENIED,STATUS_OBJECT_NAME_NOT_FOUND, STATUS_OBJECT_NAME_COLLISION,STATUS_OBJECT_NAME_INVALID, STATUS_SHARING_VIOLATION, STATUS_NOT_A_DIRECTORY, orSTATUS_FILE_IS_A_DIRECTORY.
- 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
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 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
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
1.2 文件操作
下表列出了驱动中常用的利用文件句柄操作文件的函数
操作 | 函数 | 读文件ZwReadFile写文件ZwWriteFile读文件属性ZwQueryInformationFile设置文件属性ZwSetInformationFileNTSTATUSZwReadFile(IN HANDLE FileHandle,IN HANDLE Event OPTIONAL,IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,IN PVOID ApcContext OPTIONAL,OUT PIO_STATUS_BLOCK IoStatusBlock,OUT PVOID Buffer,IN ULONG Length,IN PLARGE_INTEGER ByteOffset OPTIONAL,IN PULONG Key OPTIONAL);各参数的简要介绍如下所示:FileHandle:函数ZwCreateFile 返回的句柄。如果它是一个内核句柄,则ZwReadFile 和ZwCreateFile 并不需要在同一个进程中,因为内核句柄是各进程通用的。Event :一个事件,用于异步完成读时;我们忽略这个参数。ApcRoutine Apc:回调例程,用于异步完成读时;我们忽略这个参数。IoStatusBlock:返回结果状态,与ZwCreateFile 中的同名参数相同。Buffer:缓冲区,如果读取文件的内容成功,则内容将被读取到这里。Length:描述缓冲区的长度,即试图读取文件的长度。ByteOffset:要读取的文件的偏移量,也就是要读取的内容在文件中的位置。一般来说,不要将其设置为NULL,文件句柄不一定支持直接读取当前偏移。Key:读取文件时用的一种附加信息,一般不使用。当函数执行成功时返回STATUS_SUCCESS,实际上只要能够读取到任意字节的数据(不管它是否符合参数Length 的要求),都返回成功;但是,如果仅读取文件长度之外的部分,则返回STATUS_END_OF_FILE。ZwWriteFile 的参数与ZwReadFile 基本相同。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
ZwQueryInformationFile与ZwSetInformationFile参数基本相同ZwSetInformationFile 函数:NTSTATUSZwSetInformationFile(IN HANDLE FileHandle,OUT PIO_STATUS_BLOCK IoStatusBlock,IN PVOID FileInformation,IN ULONG Length,IN FILE_INFORMATION_CLASS FileInformationClass);ParametersFileHandle [in]Handle to the file object. This handle is created by a successful call to ZwCreateFile or ZwOpenFile.IoStatusBlock [out]Pointer to an IO_STATUS_BLOCK structure that receives the final completion status and information about the requested operation. The Information member receives the number of bytes set on the file.FileInformation [in]Pointer to a buffer that contains the information to set for the file. The particular structure in this buffer is determined by the FileInformationClass parameter. Setting any member of the structure to zero tells ZwSetInformationFile to leave the current information about the file for that member unchanged.Length [in]The size, in bytes, of the FileInformation buffer.FileInformationClass [in]The type of information, supplied in the buffer pointed to by FileInformation, to set for the file. Device and intermediate drivers can specify any of the following FILE_INFORMATION_CLASS values.
- 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
- 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
2. 代码示例
VOID FileOption(){ HANDLE SourceFileHandle = NULL; HANDLE TargetFileHandle = NULL; NTSTATUS Status = STATUS_SUCCESS; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING SourceFilePath = RTL_CONSTANT_STRING(L"\\??\\c:\\source.txt"); UNICODE_STRING TargetFilePath = RTL_CONSTANT_STRING(L"\\??\\c:\\target.txt"); UNICODE_STRING String = {0}; IO_STATUS_BLOCK IoStatusBlock; PVOID Buffer = NULL; USHORT Length = 0; LARGE_INTEGER Offset = {0}; InitializeObjectAttributes( &ObjectAttributes, &SourceFilePath, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwCreateFile( &SourceFileHandle, GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE| FILE_RANDOM_ACCESS| FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if (!NT_SUCCESS(Status)) { DbgPrint("Open source file fault !! - %#x\n", Status); return Status; } Buffer = (PWCHAR)ExAllocatePoolWithTag(NonPagedPool, 1024, 'Tag1'); if (NULL == Buffer) { DbgPrint("申请Buffer失败!!\n"); ZwClose(SourceFileHandle); Status = STATUS_INSUFFICIENT_RESOURCES; return Status; } RtlInitEmptyUnicodeString(&String, Buffer, 512*sizeof(WCHAR)); RtlCopyUnicodeString(&String, &SourceFilePath); RtlAppendUnicodeStringToString(&String, &TargetFilePath); RtlAppendUnicodeToString(&String, L"别问我这是啥"); Length = String.Length; Offset.QuadPart = 0; Status = ZwWriteFile( SourceFileHandle, NULL, NULL, NULL, &IoStatusBlock, Buffer, Length, &Offset, NULL); if (!NT_SUCCESS(Status)) { DbgPrint("写入源文件失败!!\n - %#X", Status); ZwClose(SourceFileHandle); ExFreePool(Buffer); return Status; } InitializeObjectAttributes( &ObjectAttributes, &TargetFilePath, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwCreateFile( &TargetFileHandle, GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, NULL, FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE| FILE_RANDOM_ACCESS| FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if (!NT_SUCCESS(Status)) { DbgPrint("目标文件打开失败!! - %#X", Status); ZwClose(SourceFileHandle); ExFreePool(Buffer); return Status; } Offset.QuadPart = 0; while(1) { Status = ZwReadFile( SourceFileHandle, NULL, NULL, NULL, &IoStatusBlock, Buffer, 1, &Offset, NULL); if (!NT_SUCCESS(Status)) { if (STATUS_END_OF_FILE == NULL) { Status = STATUS_SUCCESS; } break; } Status = ZwWriteFile( TargetFileHandle, NULL, NULL, NULL, &IoStatusBlock, Buffer, 1, &Offset, NULL); Offset.QuadPart += 1; } ZwClose(SourceFileHandle); ZwClose(TargetFileHandle); ExFreePool(Buffer);
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
转载请注明来源:
enjoy5512的博客 : http://blog.csdn.net/enjoy5512
GitHub : https://github.com/whu-enjoy
1. 在驱动中操作注册表
注册表项相当于文件夹,注册表子项子文件夹(类似目录)
1.1 打开注册表键
ZwCreateKey/ZwOpenKey
代码中测试了ZwOpenKey的使用方式
先初始化OBJECT_ATTRIBUTES结构体,然后打开注册表键
NTSTATUS ZwCreateKey( _Out_ PHANDLE KeyHandle, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes, _Reserved_ ULONG TitleIndex, _In_opt_ PUNICODE_STRING Class, _In_ ULONG CreateOptions, _Out_opt_ PULONG Disposition);ParametersKeyHandle [out]Pointer to a HANDLE variable that receives a handle to the key.DesiredAccess [in]Specifies an ACCESS_MASK value that determines the requested access to the object. In addition to the access rights that are defined for all types of objects (see ACCESS_MASK), the caller can specify one or more of the following access rights, which are specific to object directories:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
DesiredAccess flag | Allows caller to do this | KEY_QUERY_VALUERead key values.KEY_SET_VALUEWrite key values.KEY_CREATE_SUB_KEYCreate subkeys for the key.KEY_ENUMERATE_SUB_KEYSRead the key’s subkeys.KEY_CREATE_LINKCreate a symbolic link to the key. This flag is not used by device and intermediate drivers.KEY_NOTIFYAsk to receive notification when the name, value, or attributes of the key change. For more information, see ZwNotifyChangeKey.The caller can also specify one of the following constants, which combines several ACCESS_MASK flags.
Constant Consists of these | ACCESS_MASK flags | KEY_READSTANDARD_RIGHTS_READ, KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, and KEY_NOTIFYKEY_WRITESTANDARD_RIGHTS_WRITE, KEY_SET_VALUE, and KEY_CREATE_SUBKEYKEY_EXECUTESame as KEY_READ.KEY_ALL_ACCESSSTANDARD_RIGHTS_ALL, KEY_QUERY_VALUE, KEY_SET_VALUE, KEY_CREATE_SUB_KEY, KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, and KEY_CREATE_LINKObjectAttributes [in]Pointer to an OBJECT_ATTRIBUTES structure that specifies the object name and other attributes. Use InitializeObjectAttributes to initialize this structure. If the caller is not running in a system thread context, it must set the OBJ_KERNEL_HANDLE attribute when it calls InitializeObjectAttributes.TitleIndexDevice and intermediate drivers set this parameter to zero.Class [in, optional]Pointer to a Unicode string that contains the key's object class. This information is used by the configuration manager.CreateOptions [in]Specifies the options to apply when creating or opening a key, specified as a compatible combination of the following flags.
CreateOptions flag | Description | REG_OPTION_VOLATILEKey is not preserved when the system is rebooted.REG_OPTION_NON_VOLATILEKey is preserved when the system is rebooted.REG_OPTION_CREATE_LINKThe newly created key is a symbolic link. This flag is not used by device and intermediate drivers.REG_OPTION_BACKUP_RESTOREKey should be created or opened with special privileges that allow backup and restore operations. This flag is not used by device and intermediate drivers.Disposition [out, optional]Pointer to a variable that receives a value indicating whether a new key was created or an existing one opened.
Disposition value | Description | REG_CREATED_NEW_KEYA new key was created.REG_OPENED_EXISTING_KEYAn existing key was opened.Return valueZwCreateKey returns STATUS_SUCCESS on success, or the appropriate NTSTATUS error code on failure.
NTSTATUS ZwOpenKey( _Out_ PHANDLE KeyHandle, _In_ ACCESS_MASK DesiredAccess, _In_ POBJECT_ATTRIBUTES ObjectAttributes);ParametersKeyHandle [out]Pointer to the HANDLE variable that receives the handle to the key.DesiredAccess [in]Specifies an ACCESS_MASK value that determines the requested access to the object. For more information, see the DesiredAccess parameter of ZwCreateKey.ObjectAttributes [in]Pointer to an OBJECT_ATTRIBUTES structure that specifies the object name and other attributes. Use InitializeObjectAttributes to initialize this structure. If the caller is not running in a system thread context, it must set the OBJ_KERNEL_HANDLE attribute when it calls InitializeObjectAttributes.Return valueZwOpenKey returns STATUS_SUCCESS if the given key was opened. Otherwise, it can return an error status, including the following:STATUS_INVALID_HANDLESTATUS_ACCESS_DENIED
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
1.2 读注册表键值
1)用ZwQueryValueKey 获取数据结构的长度。
2)分配如此长度的内存。
3)再次调用ZwQueryValueKey 查询。
4)回收内存
NTSTATUS ZwQueryValueKey( _In_ HANDLE KeyHandle, _In_ PUNICODE_STRING ValueName, _In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, _Out_opt_ PVOID KeyValueInformation, _In_ ULONG Length, _Out_ PULONG ResultLength);ParametersKeyHandle [in]Handle to the key to read value entries from. This handle is created by a successful call to ZwCreateKey or ZwOpenKey.ValueName [in]Pointer to the name of the value entry to obtain data for.KeyValueInformationClass [in]A KEY_VALUE_INFORMATION_CLASS value that determines the type of information returned in the KeyValueInformation buffer.KeyValueInformation [out, optional]Pointer to a caller-allocated buffer that receives the requested information.Length [in]Specifies the size, in bytes, of the KeyValueInformation buffer.ResultLength [out]Pointer to a variable that receives the size, in bytes, of the key information. If the ZwQueryValueKey routine returns STATUS_SUCCESS, callers can use the value of this variable to determine the amount of data returned. If the routine returns STATUS_BUFFER_OVERFLOW or STATUS_BUFFER_TOO_SMALL, callers can use the value of this variable to determine the size of buffer required to hold the key information.Return valueZwQueryValueKey returns STATUS_SUCCESS on success, or the appropriate error code on failure. Possible error code values include:
- 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
- 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
Return code | Description | STATUS_OBJECT_NAME_NOT_FOUNDThe registry value was not available.STATUS_BUFFER_OVERFLOWThe buffer supplied is too small, and only partial data has been written to the buffer. *ResultLength is set to the minimum size required to hold the requested information.STATUS_BUFFER_TOO_SMALLThe buffer supplied is too small, and no data has been written to the buffer. *ResultLength is set to the minimum size required to hold the requested information.STATUS_INVALID_PARAMETERThe KeyInformationClass parameter is not a valid KEY_VALUE_INFORMATION_CLASS value.Warning If you specify KeyValueBasicInformation for KeyValueInformationClass, Windows 98 and Windows Me return STATUS_SUCCESS even if the registry key or value name does not exist.
1.3 写注册表键值
调用ZwSetValueKey
NTSTATUS ZwSetValueKey( _In_ HANDLE KeyHandle, _In_ PUNICODE_STRING ValueName, _In_opt_ ULONG TitleIndex, _In_ ULONG Type, _In_opt_ PVOID Data, _In_ ULONG DataSize);ParametersKeyHandle [in]Handle to the registry key to write a value entry for. This handle is created by a successful call to ZwCreateKey or ZwOpenKey.ValueName [in]Pointer to the name of the value entry for which the data is to be written. This parameter can be a NULL pointer if the value entry has no name. If a name string is specified and the given name is not unique relative to its containing key, the data for an existing value entry is replaced.TitleIndex [in, optional]This parameter is reserved. Device and intermediate drivers should set this parameter to zero.Type [in]One of the following system-defined types of data to write.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
Type Value | Meaning | REG_BINARYBinary data in any form.REG_DWORDA 4-byte numerical value.REG_DWORD_LITTLE_ENDIANA 4-byte numerical value with the least significant byte at the lowest address. Identical to REG_DWORD.REG_DWORD_BIG_ENDIANA 4-byte numerical value with the least significant byte at the highest address.REG_EXPAND_SZA null-terminated Unicode string that contains unexpanded references to environment variables, such as “%PATH%”.REG_LINKA Unicode string that names a symbolic link. This type is irrelevant to device and intermediate drivers.REG_MULTI_SZAn array of null-terminated strings, terminated by another zero.REG_NONEData with no particular type.REG_SZA null-terminated Unicode string.REG_RESOURCE_LISTA device driver’s list of hardware resources, used by the driver or one of the physical devices it controls, in the \ResourceMap treeREG_RESOURCE_REQUIREMENTS_LISTA device driver’s list of possible hardware resources it or one of the physical devices it controls can use, from which the system writes a subset into the \ResourceMap treeREG_FULL_RESOURCE_DESCRIPTORA list of hardware resources that a physical device is using, detected and written into the \HardwareDescription tree by the systemNote Device drivers should not attempt to call ZwSetValueKey to explicitly write value entries in a subkey of the \Registry...\ResourceMap key. Only the system can write value entries to the \Registry...\HardwareDescription tree.Data [in, optional]Pointer to a caller-allocated buffer that contains the data for the value entry.DataSize [in]Specifies the size, in bytes, of the Data buffer. If Type is REG_XXX_SZ, this value must include space for any terminating zeros.Return valueZwSetValueKey returns an NTSTATUS value. Possible return values include:STATUS_SUCCESSSTATUS_ACCESS_DENIEDSTATUS_INVALID_HANDLE
2. 示例代码
NTSTATUSRegistryOption(){ HANDLE KeyHandle = NULL; NTSTATUS Status = STATUS_SUCCESS; UNICODE_STRING KeyPath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"); OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING SourceKeyName = RTL_CONSTANT_STRING(L"SystemRoot"); UNICODE_STRING TargetKeyName = RTL_CONSTANT_STRING(L"test"); PKEY_VALUE_PARTIAL_INFORMATION AcKeyInfo = NULL; KEY_VALUE_PARTIAL_INFORMATION KeyInfo; ULONG Length = 0; InitializeObjectAttributes( &ObjectAttributes, &KeyPath, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = ZwOpenKey(&KeyHandle, KEY_READ|KEY_WRITE, &ObjectAttributes); if (!NT_SUCCESS(Status)) { DbgPrint("Open the Key Handle Faild!! -- %#X\n", Status); return Status; } Status = ZwQueryValueKey( KeyHandle, &SourceKeyName, KeyValuePartialInformation, &KeyInfo, sizeof(KEY_VALUE_PARTIAL_INFORMATION), &Length); if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL) { DbgPrint("读取SystemRoot键值失败!! - %#X\n", Status); ZwClose(KeyHandle); return Status; } AcKeyInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ExAllocatePoolWithTag(NonPagedPool, Length, "tag2"); if (NULL == AcKeyInfo) { DbgPrint("在分配保存Key键值的内存空间时失败!!"); ZwClose(KeyHandle); Status = STATUS_INSUFFICIENT_RESOURCES; return Status; } Status = ZwQueryValueKey( KeyHandle, &SourceKeyName, KeyValuePartialInformation, AcKeyInfo, Length, &Length); if (!NT_SUCCESS(Status)) { DbgPrint("读取SystemRoot键值失败!! - %#X\n", Status); ZwClose(KeyHandle); ExFreePool(AcKeyInfo); return Status; } Status = ZwSetValueKey( KeyHandle, &TargetKeyName, 0, AcKeyInfo->Type, AcKeyInfo->Data, AcKeyInfo->DataLength); if (!NT_SUCCESS(Status)) { DbgPrint("写入test键值失败!! - %#X ", Status); ZwClose(KeyHandle); ExFreePool(AcKeyInfo); return Status; } ZwClose(KeyHandle); ExFreePool(AcKeyInfo); return Status;}
- 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
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 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
- 97
- 98
- 99
- 100
- 101
- 102
- 103
找到一篇很不错的博客:
http://www.cnblogs.com/mydomain/archive/2
010/10/29/1864013.html
转载请注明来源:
enjoy5512的博客 : http://blog.csdn.net/enjoy5512
GitHub : https://github.com/whu-enjoy
1. 获取系统开机时间
获得当前“滴答数”:
获得系统日前和时间往往是为了写日志,获得启动毫秒数则很适合用来做一个随机数的种子。有时也使用时间相关的函数来寻找程序的性能瓶颈。
在Win32开发中,我们使用GetTickCount()函数来返回系统自启动之后经历的毫秒数。在驱动开发中,对应的函数是 KeQueryTickCount():
VOID KeQueryTickCount( OUT PLARGE_INTEGER TickCount )
需要注意的是,返回到TickCount中的并不是一个简单的毫秒数,而是一个“滴答”数,这个数在不同硬件环境中是不一样的,所以,我们需要结合使用另一个函数:
ULONG KeQueryTimeIncrement(void);
2. 获取系统时间
获得当前系统时间:
使用KeQuerySystemTime()函数得到的当前时间是格林威治时间,接着使用ExSystemTimeToLocalTime()函数转换成当地时间:
VOID KeQuerySystemTime( OUT PLARGE_INTEGER CurrentTime )
VOID ExSystemTimeToLocalTime( IN PLARGE_INTEGER SystemTime, OUT PLARGE_INTEGER LocalTime )
由于这两个函数使用的时间是长长整型,不便于阅读,因此,需通过函数RtlTimeToTimeFields转换成TIME_FIELDS:
VOID RtlTimeToTimeFields( IN PLARGE_INTEGER Time, IN PTIME_FIELDS TimeFields );
3. 示例代码
//程序说明开始//==================================================================================// 功能 : 获取系统时间// 参数 : // (入口) // (出口) 无// 返回 : VOID// 主要思路 : // 调用举例 : // 日期 : 2016年7月6日 22:58:19 - 2016年7月6日 23:42:41//==================================================================================//程序说明结束VOIDGetTime(){ LARGE_INTEGER TickCount = {0}; LARGE_INTEGER GelinTime = {0}; LARGE_INTEGER LocalTime = {0}; TIME_FIELDS NowFields; ULONG Inc = 0; ULONG Day = 0; ULONG Hour = 0; ULONG Minute = 0; ULONG Second = 0; Inc = KeQueryTimeIncrement(); KeQueryTickCount(&TickCount); TickCount.QuadPart *= Inc; TickCount.QuadPart /= 10000; Day = TickCount.QuadPart / (1000*60*60*24); Hour = TickCount.QuadPart % (1000*60*60*24) / (1000*60*60); Minute = TickCount.QuadPart % (1000*60*60*24) % (1000*60*60) / (1000*60); Second = TickCount.QuadPart % (1000*60*60*24) % (1000*60*60) % (1000*60) / 1000; KdPrint(("系统启动了%2d天%2d小时%2d分钟%2d秒\n", Day, Hour, Minute, Second)); KeQuerySystemTime(&GelinTime); ExSystemTimeToLocalTime(&GelinTime, &LocalTime); RtlTimeToTimeFields(&LocalTime, &NowFields); KdPrint(("系统当前时间 : %4d年%2d月%2d日 %2d:%2d:%2d\n", NowFields.Year, NowFields.Month, NowFields.Day, NowFields.Hour, NowFields.Minute, NowFields.Second));}
版权声明:本文为博主原创文章,未经博主允许不得转载。
转载请注明来源:
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);ParametersThreadHandle[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
- 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);ParametersWaitMode [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 valueKeDelayExecutionThread 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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
Return code | Description | STATUS_SUCCESSThe delay completed because the specified interval elapsed.STATUS_ALERTEDThe delay completed because the thread was alerted.STATUS_USER_APCA 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. 使用同步事件
VOIDKeInitializeEvent(IN PRKEVENT Event, IN EVENT_TYPE Type, IN BOOLEAN State );
LONG KeSetEvent( _Inout_ PRKEVENT Event, _In_ KPRIORITY Increment, _In_ BOOLEAN Wait);ParametersEvent [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 valueIf 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
- 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);ParametersObject [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 valueKeWaitForSingleObject 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
- 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_SUCCESSThe dispatcher object specified by the Object parameter satisfied the wait.STATUS_ALERTEDThe wait was interrupted to deliver an alert to the calling thread.STATUS_USER_APCThe wait was interrupted to deliver a user asynchronous procedure call (APC) to the calling thread.STATUS_TIMEOUTA 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_EventNTSTATUSThread(){ static UNICODE_STRING str = RTL_CONSTANT_STRING(L"test thread"); HANDLE ThreadHandle = NULL; NTSTATUS Status = STATUS_SUCCESS; KdPrint(("启动线程函数\n")); KeInitializeEvent(&s_Event, SynchronizationEvent, FALSE); Status = PsCreateSystemThread( &ThreadHandle, 0,NULL,NULL,NULL, ThreadProc, (PVOID)&str); if (!NT_SUCCESS(Status)) { DbgPrint("线程启动失败!!-%#X"); return Status; } KdPrint(("做一些事!!\n")); KdPrint(("线程启动函数结束!!\n")); ZwClose(ThreadHandle); KeWaitForSingleObject(&s_Event, Executive, KernelMode, 0, 0); KdPrint(("线程启动函数返回!!\n")); return Status;}VOIDThreadProc(__in PVOID Context){ PUNICODE_STRING str = (PUNICODE_STRING)Context; LARGE_INTEGER Interval; LONG Msec = 3000; KdPrint(("进入线程函数 : %wZ\n", str)); 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);}