这篇文章主要复习Windows内核中字符串处理函数,文件读写函数,注册表读写函数。
内核模式下的字符串操作:
1.ASCII字符串和宽字符串
在应用程序中,往往使用两种字符:一种是char型字符串,负责记录ANSI字符集。它是指向一个char数组的指针,每个char型变量的大小为一个字节,字符串是以0标志结尾。还有一种是wchar_t型的宽字符,负责描述unicode字符集的字符串,他是一个指向wchar_t数组的指针,wchar_t字符串大小为两个字节字符串以0标志字符串结束。
ANSI字符串构造如下:
char * str1 = "abc";
wchar_t *str2 = L"abc";
2.ANSI_STRING字符串和UNICODE_STRING字符串
DDK鼓励程序员使用DDK自定义的字符串,这种数据格式定义如下:
typedef struct _STRING { USHORT Length; USHORT MaximumLength; PCHAR Buffer; }STRING; typedef STRING ANSI_STRING; typedef PSTRING PANSI_STRING; typedef STRING OEM_STRING; typedef PSTRING POEM_STRING;
Length:字符串的长度
MaximumLength:整个字符串缓冲区的最大长度
Buffer:缓冲区的指针。
与ANSI_STRING相对应,DDK将宽字符封装成UNICODE_STRING数据结构:
typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; }UNICODE_STRING;
ANSI_STRING ansiString; //省去对ansiString初始化 KdPrint("%Z\n",&ansiString); UNICODE_STRING uniString; //省去对uniString的初始化 KdPrint("%wZ\n",&uniString);
3.字符串的初始化与销毁
ANSI_STRIN字符串和UNICODE_STRING字符串使用前需要进行初始化。有两种办法构造这个数据结构。
(1)使用DDK提供的函数
初始化ANSI_STRING字符串:
VOID RtlInitAnsiString( IN PANSI_STRING DestinationString, IN PCSZ SourceString );DestinationString:要初始化的ANSI_STRING字符串
SourceString:字符串的内容
初始化UNICODE_STRING字符串:
VOID RtlInitUnicodeString( IN PUNICODE_STRING DestinationString, IN PCWSTR SourceString );
SourceString:字符串的内容
看下面一段代码:
//用RtlInitAnsiString初始化字符串 ANSI_STRING AnsiString1; CHAR * string1 = "hello"; //初始化ANSI_STRING字符串 RtlInitAnsiString(&AnsiString1,string1); KdPrint(("AnsiString1:%Z\n",&AnsiString1));//打印hello string1[0] = 'H'; string1[1] = 'E'; string1[2] = 'L'; string1[3] = 'L'; string1[4] = 'O'; //改变string1,AnsiString1同样会导致变化 KdPrint(("AnsiString1:%Z\n",&AnsiString1));//打印HELLO
//程序员自己初始化字符串 #define BUFFER_SIZE 1024 UNICODE_STRING UnicodeString1 = {0}; //设置缓冲区大小 UnicodeString1.MaximumLength = BUFFER_SIZE; //分配内存 UnicodeString1.Buffer = (PWSTR)ExAllocatePool(PagedPool,BUFFER_SIZE); WCHAR * wideString = L"hello"; //设置字符串长度,因为是宽字符,所以是字符长度的2倍 UnicodeString1.Length = 2*wcslen(wideString); //保证缓冲区足够大,否则程序终止 ASSERT(UnicodeString1.MaximumLength >= UnicodeString1.Length); //内存拷贝 RtlCopyMemory(UnicodeString1.Buffer,wideString,UnicodeString1.Length); //设置字符长度 UnicodeString1.Length = 2*wcslen(wideString); KdPrint(("UnicodeString:%wZ\n",&UnicodeString1)); //清理内存 ExFreePool(UnicodeString1.Buffer); UnicodeString1.Buffer = NULL; UnicodeString1.Length = UnicodeString1.MaximumLength = 0;
DDK提供了针对ANSI_STRING和UNICODE_STRING字符串的复制字符串命令,分别是:
ANSI_STRING:
VOID RtlCopyString( IN PSTRING DestinationString, IN PSTRING SourceString );
VOID RtlCopyUnicodeString( IN PUNICODE_STRING DestinationString, IN PUNICODE_STRING SourceString );
SourceString:源字符串
请看如下代码:
//初始化Unicodestring1 UNICODE_STRING UnicodeString1; RtlInitUnicodeString(&UnicodeString1,L"Hello World"); //初始化UnicodeString2 UNICODE_STRING UnicodeString2={0}; UnicodeString2.Buffer = (PWSTR)ExAllocatePool(PagedPool,BUFFER_SIZE); UnicodeString2.MaximumLength = BUFFER_SIZE; //初始化Unicodestring2拷贝到UnicodeString1 RtlCopyUnicodeString(&UnicodeString2,&UnicodeString1); //分别显示UnicodeString1和UnicodeString2 KdPrint(("UnicodeString1:%wZ\n",&UnicodeString1)); KdPrint(("UnicodeString2:%wZ\n",&UnicodeString2)); //销毁UnicodeString2 //注意!!UnicodeString1不用销毁 RtlFreeUnicodeString(&UnicodeString2);
DDK提供了对ANSI_STRING和UNICODE_STRING字符串的相关字符串比较操作。
ANSI_STRING:
LONG RtlCompareString( IN PSTRING String1, IN PSTRING String2, BOOLEAN CaseInSensitive );UNICODE_STRING:
LONG RtlCompareUnicodeString( IN PUNICODE_STRING String1, IN PUNICODE_STRING String2, BOOLEAN CaseInSensitive );String1:要比较的第一个字符串
String2:要比较的第二个字符串
CaseInSensitive:是否对大小写敏感
下面代码演示如何使用RtlCompareUnicodeString函数:
if (RtlEqualUnicodeString(&UnicodeString1,&UnicodeString2,TRUE)) { KdPrint(("UnicodeString1 and UnicodeString2 are equal\n")); } else { KdPrint(("UnicodeString1 and UnicodeString2 are NOT equal\n")); }
DDK提供了对ANSI_STRING和UNICODE_STRING字符串的相关字符串大小写转化的函数。
(1)ANSI_STRING字符串转化成大写
VOID RtlUpperString( OUT PSTRING DestinationString, OUT PSTRING SourceString );
SourceString:源字符串
(2)UNICODE_STRING字符串转化成大写
NTSTATUS RtlUpcaseUnicodeString( IN OUT PUNICODE_STRING DestinationString, IN PCUNICODE_STRING SourceString, IN BOOLEAN AllocateDestinationString );
SourceString:源字符串
AllocateDestinationString:是否为目的字符串分配内存
返回值:返回转换是否成功
DDK虽然提供了转化成大写的函数,但却没有提供转化成小写的函数。下面代码演示了如何使用RtlUpcaseUnicodeString函数:
//初始化UnicodeString1 UNICODE_STRING UnicodeString1; RtlInitUnicodeString(&UnicodeString1,L"Hello World"); //变化前 KdPrint(("UnicodeString1:%wZ\n",&UnicodeString1)); //变大写 RtlUpcaseUnicodeString(&UnicodeString1,&UnicodeString1,FALSE); //变化后 KdPrint(("UnicodeString1:%wZ\n",&UnicodeString1));
DDK提供了UNICODE_STRING字符串与整数相互转换的内核函数。
(1)将UNICODE_STRING字符串转换成整数
这个函数是RtlUnicodeStringToInteger,其声明是:
NTSTATUS RtlUnicodeStringToInteger( IN PUNICODE_STRING String, IN ULONG Base, OUT PULONG Value );
Base:转换的数的进制
Vlaue:需要转换的数字
返回值:指明是否转换成功
(2)将整数转换成UNICODE_STRING字符串
这个函数RtlIntegerToUnicodeString,其声明时:
NTSTATUS RtlIntegerToUnicodeString( IN ULONG Value, IN ULONG Base, IN OUT PUNICODE_STRING String );
Base:转换的数的进制
String:需要转换的字符串
返回值:是否转换成功
以下是字符串和数字之间的相互转换:
//字符串转换成数字 //初始化UnicodeString1 UNICODE_STRING UnicodeString1; RtlInitUnicodeString(&UnicodeString1,L"-100"); ULONG lNumber; NTSTATUS nStatus = RtlUnicodeStringToInteger(&UnicodeString1,10,&lNumber); if (NT_SUCCESS(nStatus)) { KdPrint(("Convert to integer successfully\n")); } else { KdPrint(("Convert to integer unsuccessfully\n")); } //数字转换成字符串 UNICODE_STRING UnicodeString2 = {0}; UnicodeString2.Buffer = (PWSTR)ExAllocatePool(PagedPool,BUFFER_SIZE); UnicodeString2.MaximumLength = BUFFER_SIZE; nStatus = RtlIntegerToUnicodeString(200,10,&UnicodeString2); if (NT_SUCCESS(nStatus)) { KdPrint(("Conver to string successfully!\n")); KdPrint(("Result: %wZ\n",&UnicodeString2)); } else { KdPrint(("Convert to string unsuccessfully!\n")); } //销毁UnicodeString2 //注意!!UnicodeString1不用销毁 RtlFreeUnicodeString(&UnicodeString2);
DDK提供了ANSI_STRING字符串和UNICODE_STRING字符串相互转换的相关函数
(1)将UNICODE_STRING字符串转换为ANSI_STRING字符串
DDK提供了函数:RtlUnicodeStringToAnsiString,其声明是:
NTSTATUS RtlUnicodeStringToAnsiString( IN OUT PANSI_STRING DestinationString, IN PUNICODE_STRING SourceString, IN BOOLEAN AllocateDestinationString );
SourceString:需要转换的源字符串
AllocateDestinationString:是否需要对被转换字符分配内存
返回值:指明是否分配成功
(2)将ANSI_STRING字符串转换为UNICODE_STRING字符串
DDK提供函数:RtlAnsiStringToUnicodeString,其声明:
NTSTATUS RtlAnsiStringToUnicodeString( IN OUT PUNICODE_STRING DestinationString, IN PANSI_STRING SourceString, IN BOOLEAN AllocateDestinationString );
DestinationString:需要被转换的字符串
SourceString:需要转换的源字符串
AllocateDestinationString:是否需要对被转换字符分配内存
返回值:指明是否分配成功
//将UNICODE_STRING字符串转换成ANSI_STRING字符串 //初始化UnicodeString1 UNICODE_STRING UnicodeString1; RtlInitUnicodeString(&UnicodeString1,L"Hello World"); ANSI_STRING AnsiString1; NTSTATUS nStatus = RtlUnicodeStringToAnsiString(&AnsiString1,&UnicodeString1,TRUE); if (NT_SUCCESS(nStatus)) { KdPrint(("Conver successfully!\n")); KdPrint(("Result:%Z\n",&AnsiString1)); } else { KdPrint(("Conver unsuccessfully!\n")); } //销毁AnsiString1 RtlFreeAnsiString(&AnsiString1); //将ANSI_STRING字符串转换成UNICODE_STRING字符串 //初始化AnsiString2 ANSI_STRING AnsiString2; RtlInitAnsiString(&AnsiString2,"Hello World"); UNICODE_STRING UnicodeString2; nStatus = RtlAnsiStringToUnicodeString(&UnicodeString2,&AnsiString2,TRUE); if (NT_SUCCESS(nStatus)) { KdPrint(("Conver succussfully!\n")); KdPrint(("Result:%wZ\n",&UnicodeString2)); } else { KdPrint(("Conver unsuccessfully!\n")); } //销毁UnicodeString2 RtlFreeUnicodeString(&UnicodeString2);
1.文件的创建
对文件的创建或者打开都是通过ZwCreateFile实现的。和Windows API类似,这个内核函数返回一个文件句柄,文件的所有操作都是依靠这个句柄进行操作的。在操作完毕后,需要关闭这个句柄。
NTSTATUS ZwCreateFile( 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 );
DesireAccess:对打开文件操作的描述
ObjectAttributes:是OBJECT_ATTRIBUTES结构的地址,该结构包含要打开的文件名
IoStatuesBlock:指向一个IO_STATUS_BLOCK结构,该结构接收ZwCreateFile操作的结果状态
AllocateSize:是一个指针,指向一个64位整数,指定文件初始分配的大小
FileAttributes:0或FILE_ATTRIBUTES_NORMAL,指定新创建文件的属性
ShareAccess:FILE_OPEN_READ或0,指定文件的共享方式
CreateDisposition:FILE_OPEN或FILE_OVERWRITE_IF,表明当文件存在或不存在时应如何处理
CreateOptions:FILE_SYNCHRONOUS_IO_NONALERT,指定控制文件打开操作和句柄使用的附加标志位
EaBuffer:一个指针,指向可选的扩展属性区
EaLength:扩展属性区的长度
这个函数需要填写CreateDisposition参数。如果想打开文件,CreateDisposition参数设置成FILE_OPEN。如果想创建文件,CreateDisposition参数设置成FILE_OVERWRITE_IF。此时无论文件是否存在,都会创建新文件。
文件名的指定是通过设定第三个参数ObjectAttributes。这个参数是一个OBJECT_ATTRIBUTES结构。DDK提供对OBJECT_ATTRIBUTES结构初始化的宏InitializeObjectAttributes.
VOID InitializeObjectAttributes( OUT POBJECT_ATTRIBUTES InitializedAttributes, IN PUNICODE_STRING ObjectName, IN ULONG Attributes, IN HANDLE RootDirectory, IN PSECURITY_DESCRIPTOR SecurityDescriptor );
ObjectName:对象名称,用UNICODE_STRING描述,这里设置的是文件名
Attributes:一般设置为OBJ_CASE_INSENSITIVE,对大小写敏感
后两个参数一般设置为NULL
下面代码演示如何在驱动程序中创建和打开文件
(1)创建文件
VOID CreateFileTest() { OBJECT_ATTRIBUTES objectAtrributes; IO_STATUS_BLOCK iostatus; HANDLE hfile; UNICODE_STRING logFileUnicodeString; //初始化UNICODE_STRING字符串 RtlInitUnicodeString(&logFileUnicodeString, L"\\??\\C:\\1.log"); //初始化objectAtrributes InitializeObjectAttributes(&objectAtrributes, &logFileUnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL); //创建文件 NTSTATUS ntStatus = ZwCreateFile(&hfile, GENERIC_WRITE, &objectAtrributes, &iostatus, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if (NT_SUCCESS(ntStatus)) { KdPrint(("Create file successfully!\n")); } else { KdPrint(("Create file unseccessfully!\n")); } //文件操作 //。。。。。。。。 //关闭文件句柄 ZwClose(hfile); }
#pragma INITCODE VOID OpenFileTest1() { OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK iostatus; HANDLE hfile; UNICODE_STRING logFileUnicodeString; //初始化UNICODE_STRING字符串 RtlInitUnicodeString(&logFileUnicodeString, L"\\??\\C:\\1.log"); //初始化objectAttributes InitializeObjectAttributes(&objectAttributes, &logFileUnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL); //创建文件 NTSTATUS ntStatus = ZwCreateFile(&hfile, GENERIC_READ, &objectAttributes, &iostatus, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if (NT_SUCCESS(ntStatus)) { KdPrint(("Open file succssfully!\n")); } else { KdPrint(("Open file unsuccssfully!\n")); } //文件操作 //。。。。 //关闭文件句柄 ZwClose(hfile); }
2.文件的打开
除了使用ZwCreateFile函数可以打开文件,DDK还提供了一个内核函数ZwOpenFile。ZwOpenFile内核函数的参数比ZwCreateFile的参数简化,方便程序员打开文件。
该函数声明如下:
NTSTATUS ZwOpenFile( OUT PHANDLE FileHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG ShareAccess, IN ULONG OpenOptions );
DesireAccess:打开的权限,一般设置为GENERIC_ALL
ObjectAttributes:OBJECT_ATTRIBUTES结构体
IoStatusBlock:指向一个结构体的指针,该结构体指明打开文件的状态
ShareAccess:共享的权限。可以是FILE_SYNCHRONOUS_IO_NONALERT
返回值:指明文件是否被成功打开
下面代码演示了如何使用ZwOpenFile打开文件:
OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK iostatus; HANDLE hfile; UNICODE_STRING logFileUnicodeString; //初始化UNICODE_STRING字符串 RtlInitUnicodeString(&logFileUnicodeString, L"\\??\\C:\\1.log"); //初始化objectAttributes InitializeObjectAttributes(&objectAttributes, &logFileUnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL); //创建文件 NTSTATUS ntStatus = ZwOpenFile(&hfile, GENERIC_ALL, &objectAttributes, &iostatus, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_NONALERT); if (NT_SUCCESS(ntStatus)) { KdPrint(("Create file successfully!\n")); } else { KdPrint(("Create file unsuccessfully!\n")); } //文件操作 //。。。。。。。。。。 //关闭文件句柄 ZwClose(hfile);
获取和修改文件属性,包括获取文件大小,获取或修改文件指针的位置,获取或修改文件名,获取或修改文件属性(只读信息,隐藏信息),获取或修改文件创建,修改日期等。DDK提供了内核函数ZwSetInformationFile和ZwQueryInformationFile函数来获取和修改文件属性。
NTSTATUS ZwSetInformationFile( IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass );
NTSTATUS ZwQueryInformationFile( IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass );
IoStackBlock:返回设置状态
FileInformation:依据FileInformationClass不同而不同。作为输入信息
Length:FileInformation的长度
FileInformationClass:描述修改属性类型
下面代码演示如何使用ZwQueryInformationFile函数查询,修改文件属性
OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK iostatus; HANDLE hfile; UNICODE_STRING logFileUnicodeString; //初始化UNICODE_STRING字符串 RtlInitUnicodeString(&logFileUnicodeString, L"\\??\\C:\\1.log"); //初始化objectAttributes InitializeObjectAttributes(&objectAttributes, &logFileUnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL); //创建文件 NTSTATUS ntStatus = ZwCreateFile(&hfile, GENERIC_READ, &objectAttributes, &iostatus, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if (NT_SUCCESS(ntStatus)) { KdPrint(("open file successfully!\n")); } FILE_STANDARD_INFORMATION fsi; //读取文件长度 //读取文件长度 ntStatus = ZwQueryInformationFile(hfile, &iostatus, &fsi, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation); if (NT_SUCCESS(ntStatus)) { KdPrint(("file length:%u\n",fsi.EndOfFile.QuadPart)); } //修改当前文件指针 FILE_POSITION_INFORMATION fpi; fpi.CurrentByteOffset.QuadPart = 100i64; ntStatus = ZwSetInformationFile(hfile, &iostatus, &fpi, sizeof(FILE_POSITION_INFORMATION), FilePositionInformation); if (NT_SUCCESS(ntStatus)) { KdPrint(("update the file pointer successfully!\n")); } //关闭文件句柄 ZwClose(hfile);
DDK提供了文件写操作的内核函数,其声明如下:
NTSTATUS ZwWriteFile( IN HANDLE FileHandle, IN HANDLE Event OPTIONAL, IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, IN PVOID ApcContext OPTIONAL, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PVOID Buffer, IN ULONG Length, IN PLARGE_INTEGER ByteOffset OPTIONAL, IN PULONG Key OPTIONAL );
Event:很少用到,一般设置为NULL
ApcRountine:很少用到,一般设置为NULL
ApcContext:很少用到,一般设置为NULL
IoStackBlock:记录写操作的状态
Buffer:从这个缓冲区里开始写
Length:准备写多少字节
ByteOffset:从文件得多少偏移地址开始写
Key:很少用到,一般设置为NULL
下面代码演示如何进行文件写操作:
OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK iostatus; HANDLE hfile; UNICODE_STRING logFileUnicodeString; //初始化UNICODE_STRING字符串 RtlInitUnicodeString(&logFileUnicodeString, L"\\??\\C:\\1.log"); //初始化objectAttributes InitializeObjectAttributes(&objectAttributes, &logFileUnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL); //创建文件 NTSTATUS ntStatus = ZwCreateFile(&hfile, GENERIC_WRITE, &objectAttributes, &iostatus, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_WRITE, FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); #define BUFFER_SIZE 1024 PUCHAR pBuffer = (PUCHAR)ExAllocatePool(PagedPool,BUFFER_SIZE); //构造要填充的数据 RtlFillMemory(pBuffer,BUFFER_SIZE,0xAA); KdPrint(("The program will write %d bytes\n",BUFFER_SIZE)); //写文件 ZwWriteFile(hfile,NULL, NULL,NULL,&iostatus,pBuffer, BUFFER_SIZE,NULL,NULL); KdPrint(("The program really wrote %d bytes\n",iostatus.Information)); //构造要填充的数据 RtlFillMemory(pBuffer,BUFFER_SIZE,0xBB); KdPrint(("The program will append %d bytes\n",BUFFER_SIZE)); //追加数据 LARGE_INTEGER number; number.QuadPart = 1024i64;//设置文件指针 //对文件进行读写 ZwWriteFile(hfile,NULL,NULL, NULL,&iostatus,pBuffer, BUFFER_SIZE,&number,NULL); KdPrint(("The program really append %d bytes\n",iostatus.Information)); //关闭文件句柄 ZwClose(hfile); ExFreePool(pBuffer);
DDK提供了文件读操作的内核函数,其声明如下:
NTSTATUS ZwReadFile( 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 );
#pragma INITCODE VOID ReadFileTest() { OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK iostatus; HANDLE hfile; UNICODE_STRING logFileUnicodeString; //初始化UNICODE_STRING字符串 RtlInitUnicodeString(&logFileUnicodeString, L"\\??\\C:\\1.log"); //初始化objectAtrributes InitializeObjectAttributes(&objectAttributes, &logFileUnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL); //创建文件 NTSTATUS ntStatus = ZwCreateFile(&hfile, GENERIC_READ, &objectAttributes, &iostatus, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if (!NT_SUCCESS(ntStatus)) { KdPrint(("The file is not exist!\n")); return; } FILE_STANDARD_INFORMATION fsi; //读取文件长度 ntStatus = ZwQueryInformationFile(hfile, &iostatus, &fsi, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation); KdPrint(("The program want to read %d bytes\n",fsi.EndOfFile.QuadPart)); //为读取的文件分配缓冲区 PUCHAR pBuffer = (PUCHAR)ExAllocatePool(PagedPool, (LONG)fsi.EndOfFile.QuadPart); //读取文件 ZwReadFile(hfile,NULL, NULL,NULL, &iostatus, pBuffer, (LONG)fsi.EndOfFile.QuadPart, NULL,NULL); KdPrint(("The program really read %d bytes\n",iostatus.Information)); //关闭文件句柄 ZwClose(hfile); //释放缓冲区 ExFreePool(pBuffer); }