<学习笔记>Windows驱动开发技术详解__Windows内核函数

这篇文章主要复习Windows内核中字符串处理函数,文件读写函数,注册表读写函数。


内核模式下的字符串操作:


1.ASCII字符串和宽字符串

在应用程序中,往往使用两种字符:一种是char型字符串,负责记录ANSI字符集。它是指向一个char数组的指针,每个char型变量的大小为一个字节,字符串是以0标志结尾。还有一种是wchar_t型的宽字符,负责描述unicode字符集的字符串,他是一个指向wchar_t数组的指针,wchar_t字符串大小为两个字节字符串以0标志字符串结束。

ANSI字符串构造如下:

char * str1 = "abc";

UNICODE字符串的构造如下:

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;

这个数据结构对ASCII字符串进行了封装:

Length:字符串的长度

MaximumLength:整个字符串缓冲区的最大长度

Buffer:缓冲区的指针。


与ANSI_STRING相对应,DDK将宽字符封装成UNICODE_STRING数据结构:

typedef struct _UNICODE_STRING
{
	USHORT Length;
	USHORT MaximumLength;
	PWSTR Buffer;
}UNICODE_STRING;

KdPrint函数提供了打印log方法
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
	);

DestinationString:要初始化的UNICODE_STRING字符串

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

(2)另一种方法是程序员自己申请内存,并初始化内存,当不用字符串时,需要回收字符串占用的内存

//程序员自己初始化字符串
#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;

4.字符串复制

DDK提供了针对ANSI_STRING和UNICODE_STRING字符串的复制字符串命令,分别是:

ANSI_STRING:

VOID
 RtlCopyString(
                 IN PSTRING DestinationString,
		 IN PSTRING SourceString 
		);


UNICODE_STRING:

VOID 
 RtlCopyUnicodeString(
          IN PUNICODE_STRING DestinationString, 
	  IN PUNICODE_STRING SourceString
	 );

DestinationString:目的字符串

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

5.字符串的比较

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"));
	}

6.字符串转化成大写

DDK提供了对ANSI_STRING和UNICODE_STRING字符串的相关字符串大小写转化的函数。

(1)ANSI_STRING字符串转化成大写

VOID  
  RtlUpperString( 
       OUT  PSTRING DestinationString,
       OUT  PSTRING SourceString
	);

DestinationString:目的字符串

SourceString:源字符串


(2)UNICODE_STRING字符串转化成大写

NTSTATUS 
  RtlUpcaseUnicodeString(
           IN OUT PUNICODE_STRING DestinationString,
	   IN PCUNICODE_STRING SourceString,
	   IN BOOLEAN AllocateDestinationString 
	 );

DestinationString:目的字符串

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

7.字符串与整形数字相互转换

DDK提供了UNICODE_STRING字符串与整数相互转换的内核函数。

(1)将UNICODE_STRING字符串转换成整数

这个函数是RtlUnicodeStringToInteger,其声明是:

NTSTATUS
 RtlUnicodeStringToInteger(
             IN PUNICODE_STRING String, 
	     IN ULONG Base, 
	     OUT PULONG Value 
	);

String:需要转换的字符串

Base:转换的数的进制

Vlaue:需要转换的数字

返回值:指明是否转换成功


(2)将整数转换成UNICODE_STRING字符串

这个函数RtlIntegerToUnicodeString,其声明时:

NTSTATUS
 RtlIntegerToUnicodeString( 
           IN ULONG Value,
	   IN ULONG Base, 
	   IN OUT PUNICODE_STRING String 
		);

Value:需要转换的数字

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

ANSI_STRING字符串和UNICODE_STRING字符串相互转换

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

DestinationString:需要被转换的字符串

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:是否需要对被转换字符分配内存

返回值:指明是否分配成功


下面代码演示了ANSI_STRING和UNICODE_STRING之间是如何转换的:

//将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
	);

FileHanlde:返回打开文件的句柄

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

InitializedAttributes:返回OBJECT_ATTRIBUTES结构

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

(2)打开文件
#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 
	 );

FileHandle:返回打开文件的句柄

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

3.获取或修改文件的属性

获取和修改文件属性,包括获取文件大小,获取或修改文件指针的位置,获取或修改文件名,获取或修改文件属性(只读信息,隐藏信息),获取或修改文件创建,修改日期等。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
  );


FileHandle:文件句柄

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

4.文件的写操作

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

FileHandle:文件打开句柄

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

5文件的读操作:

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


}




你可能感兴趣的:(windows,String,File,null,buffer,attributes)