提示:原创不易,未经允许,不可擅自转载
前言
有时候当我们不想用windbg、dbgview等工具查看驱动信息,又想知道一些关键的数据时,我们就可以新建一个log日志用来查看当前驱动的运行状况了。
一、创建日志文件
驱动中创建文件一般会用到NtCreateFile、ZwCreateFile、IoCreateFile这几个函数。这里用ZwCreateFile来举例。
ZwCreateFile函数原型如下:
NTSYSAPI NTSTATUS ZwCreateFile(
[out] PHANDLE FileHandle,
[in] ACCESS_MASK DesiredAccess,
[in] POBJECT_ATTRIBUTES ObjectAttributes,
[out] PIO_STATUS_BLOCK IoStatusBlock,
[in, optional] PLARGE_INTEGER AllocationSize,
[in] ULONG FileAttributes,
[in] ULONG ShareAccess,
[in] ULONG CreateDisposition,
[in] ULONG CreateOptions,
[in, optional] PVOID EaBuffer,
[in] ULONG EaLength
);
代码如下(示例):
RtlInitUnicodeString(&FileName, L"\\??\\C:\\test.log");
InitializeObjectAttributes(&ObjectAttributes, &FileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
Status = ZwCreateFile(
&FileHandle,
GENERIC_WRITE | GENERIC_READ,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN_IF,
FILE_NON_DIRECTORY_FILE | FILE_RANDOM_ACCESS | FILE_SYNCHRONOUS_IO_ALERT,
NULL,
0);
if (!NT_SUCCESS(Status)) {
// Handle error.
KdPrint(("Test: Failed to ZwCreateFile file.\n"));
goto done;
}
需要注意的是,这里的文件名要以符号链接名(“\??\C:\test.log”)的形式,即在C盘目录下创建名为test.log的日志文件。还需要将该文件置为内核模式,即设置OBJ_KERNEL_HANDLE。参数CreateOptions也会影响到文件创建成功与否。
二、写入日志文件
驱动中创建文件一般会用到NtWriteFile、ZwWriteFile、IoWriteFile这几个函数。这里用ZwWriteFile来举例。
ZwWriteFile函数原型如下:
NTSYSAPI NTSTATUS ZwWriteFile(
[in] HANDLE FileHandle,
[in, optional] HANDLE Event,
[in, optional] PIO_APC_ROUTINE ApcRoutine,
[in, optional] PVOID ApcContext,
[out] PIO_STATUS_BLOCK IoStatusBlock,
[in] PVOID Buffer,
[in] ULONG Length,
[in, optional] PLARGE_INTEGER ByteOffset,
[in, optional] PULONG Key
);
代码如下(示例):
Status = ZwWriteFile(
FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
WriteBuffer,
BufferLen,
&Offset,
NULL);
if (!NT_SUCCESS(Status)) {
// Handle error.
KdPrint(("Test: Failed to ZwWriteFile file.\n"));
goto done;
}
WriteBuffer字符串数据,要写入test.log中的文本信息;BufferLen字符串数据大小;Offset偏移量,即是写入文本中的位置。
三、读取日志文件
驱动中创建文件一般会用到NtReadFile、ZwReadFile、IoReadFile这几个函数。这里用ZwReadFile来举例。
ZwReadFile函数原型如下:
NTSYSAPI NTSTATUS ZwReadFile(
[in] HANDLE FileHandle,
[in, optional] HANDLE Event,
[in, optional] PIO_APC_ROUTINE ApcRoutine,
[in, optional] PVOID ApcContext,
[out] PIO_STATUS_BLOCK IoStatusBlock,
[out] PVOID Buffer,
[in] ULONG Length,
[in, optional] PLARGE_INTEGER ByteOffset,
[in, optional] PULONG Key
);
代码如下(示例):
Status = ZwReadFile(
FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
ReadBuffer,
BufferLen,
NULL,
NULL
);
if (!NT_SUCCESS(Status)) {
// Handle error.
KdPrint(("Test: Failed to ZwReadFile file.\n"));
goto done;
}
KdPrint(("Test: read buffer: %s.\n", ReadBuffer));
ReadBuffer字符串数据,从test.log中读取的文本信息会被保存到该变量中;BufferLen指定读取字符串数据的大小;ByteOffset为null,表示从内容首行开始读取。
全部代码
代码如下(示例):
NTSTATUS Status;
HANDLE FileHandle = NULL;
IO_STATUS_BLOCK IoStatusBlock;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING FileName;
LARGE_INTEGER Offset;
CHAR WriteBuffer[1024];
CHAR ReadBuffer[1024];
ULONG BufferLen;
RtlInitUnicodeString(&FileName, L"\\??\\C:\\test2.log");
InitializeObjectAttributes(&ObjectAttributes, &FileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
Status = ZwCreateFile(
&FileHandle,
GENERIC_WRITE | GENERIC_READ,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN_IF,
FILE_NON_DIRECTORY_FILE | FILE_RANDOM_ACCESS | FILE_SYNCHRONOUS_IO_ALERT,
NULL,
0);
if (!NT_SUCCESS(Status)) {
// Handle error.
KdPrint(("Test: Failed to ZwCreateFile file.\n"));
goto done;
}
Offset.HighPart = -1;
Offset.LowPart = FILE_WRITE_TO_END_OF_FILE;// | FILE_USE_FILE_POINTER_POSITION;
BufferLen = sizeof("Hello World!");
RtlCopyMemoryNonTemporal(WriteBuffer, "Hello World!\r\n", BufferLen);
Status = ZwWriteFile(
FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
WriteBuffer,
BufferLen,
&Offset,
NULL);
if (!NT_SUCCESS(Status)) {
// Handle error.
KdPrint(("Test: Failed to ZwWriteFile file.\n"));
goto done;
}
Status = ZwReadFile(
FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
ReadBuffer,
BufferLen,
NULL,
NULL
);
if (!NT_SUCCESS(Status)) {
// Handle error.
KdPrint(("Test: Failed to ZwReadFile file.\n"));
goto done;
}
KdPrint(("Test: read buffer: %s.\n", ReadBuffer));
ZwClose(FileHandle);
done:
if (NT_SUCCESS(Status)) {
KdPrint(("Test: File created successfully.\n"));
}
else {
KdPrint(("Test: Failed to create file. Status = 0x%08X\n", Status));
}
return Status;
总结
以上只是对Zw库的对文件操作的API的简单使用,实际驱动开发会更为复杂,应根据实际项目需要选择合适的API。
参考
【1】ZwCreateFile 函数 (wdm.h)
【2】ZwWriteFile 函数 (wdm.h)
【3】ZwReadFile 函数 (wdm.h)