這篇文章主要複習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
);
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:是否需要對被轉換字符分配內存
返回值:指明是否分配成功
//將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);
}