#include <windef.h>
#define TAG 'tset' //test
/*
文件名:ZwQueryDirectoryFile.C
功能:在驱动中遍历/枚举文件。
看似一个简单不值一看的功能,花费了我一天的时间,也许我太笨,所以有此记录。
made by correy
made at 2014.06.04
homepage:http://correy.webs.com
*/
DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{
}
NTSTATUS ZwEnumerateFile1(IN UNICODE_STRING * directory)// ,FILE_INFORMATION_CLASS fic
/*
功能:枚举目录下的文件。没有递归。
输入参数:可以是路径,句柄,文件对象,这个可以修改,但不能是文件路径。
路径的格式最好是:L"\\??\\C:\\Windows");或者"\Device\HarddiskVolume1\XXX \\DosDevices\\C:\\,不然还得转换,结构最好用的UNICODE_STRING,这样安全。
这个方法的思路是一下读取了一个目录下的所有信息。优缺点是不言而喻的,就是所需的内存的大小,你知道吗?
其实,ZwEnumerateFile这个函数没有获取所需的内存的大小的功能,一个思路是结构的大小加路径的大小。
*/
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
OBJECT_ATTRIBUTES ob;
HANDLE FileHandle = 0;
IO_STATUS_BLOCK IoStatusBlock = {0};
PVOID FileInformation = 0;
ULONG Length = sizeof (FILE_DIRECTORY_INFORMATION);//这个数设置的太小会导致ZwQueryDirectoryFile蓝屏。
FILE_DIRECTORY_INFORMATION * fibdi = 0;
InitializeObjectAttributes(&ob, directory, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0);
status = ZwOpenFile(&FileHandle, GENERIC_READ | SYNCHRONIZE, &ob, &IoStatusBlock, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
if (!NT_SUCCESS (status))
{
KdPrint(("ZwOpenFile fail with 0x%x.\n", status));
if ( status == STATUS_OBJECT_NAME_NOT_FOUND || IoStatusBlock.Information == FILE_DOES_NOT_EXIST) {
KdPrint(("file does not exist\n"));
}
return status;
}
do
{
if (FileInformation)
{
ExFreePoolWithTag(FileInformation, TAG);
FileInformation = NULL;
}
FileInformation = ExAllocatePoolWithTag(NonPagedPool, Length, TAG);
if (FileInformation == NULL) {
status = STATUS_UNSUCCESSFUL;
DbgPrint("发生错误的文件为:%s, 代码行为:%d\n", __FILE__, __LINE__);
ZwClose(FileHandle);
return status;
}
RtlZeroMemory(FileInformation, Length);
status = ZwQueryDirectoryFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, FileInformation, Length, FileDirectoryInformation, FALSE, NULL, TRUE);
if (!NT_SUCCESS (status))
{
KdPrint(("ZwQueryDirectoryFile fail with 0x%x.\n", status));//STATUS_BUFFER_TOO_SMALL == C0000023
//return status;
}
Length *= 2;
} while (!NT_SUCCESS (status));
for (fibdi = FileInformation ; ; fibdi = (FILE_DIRECTORY_INFORMATION *)((char *)fibdi + fibdi->NextEntryOffset))
{
UNICODE_STRING FileName ={0};
if (FILE_ATTRIBUTE_DIRECTORY == fibdi->FileAttributes)
{
//这里可以考虑递归。这里放弃了文件夹的显示。
continue;
}
FileName.Buffer = fibdi->FileName;
FileName.Length = (USHORT)fibdi->FileNameLength;
FileName.MaximumLength = FileName.Length + 2;
KdPrint(("FileName %wZ\n", &FileName));
if (fibdi->NextEntryOffset == 0)
{
break;
}
}
if (FileInformation)
{
ExFreePoolWithTag(FileInformation, TAG);
FileInformation = NULL;
}
ZwClose(FileHandle);
return status;
}
NTSTATUS ZwEnumerateFile2(IN UNICODE_STRING * directory)// ,FILE_INFORMATION_CLASS fic
/*
功能:枚举目录下的文件。没有递归。
输入参数:可以是路径,句柄,文件对象,这个可以修改,但不能是文件路径。
路径的格式最好是:L"\\??\\C:\\Windows");或者"\Device\HarddiskVolume1\XXX \\DosDevices\\C:\\,不然还得转换,结构最好用的UNICODE_STRING,这样安全。
这个是改进版。
因为上面的函数,不可能确定目录下有多少目录,如系统目录下有几千个文件。
这个办法是一个一个来的,参考了KMDKIT的第十一章教程。
*/
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
OBJECT_ATTRIBUTES ob;
HANDLE FileHandle = 0;
IO_STATUS_BLOCK IoStatusBlock = {0};
PVOID FileInformation = 0;
ULONG Length = sizeof (FILE_DIRECTORY_INFORMATION);//这个数设置的太小会导致ZwQueryDirectoryFile蓝屏。
InitializeObjectAttributes(&ob, directory, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, 0);
status = ZwOpenFile(&FileHandle, GENERIC_READ | SYNCHRONIZE, &ob, &IoStatusBlock, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE);
if (!NT_SUCCESS (status))
{
KdPrint(("ZwOpenFile fail with 0x%x.\n", status));
if ( status == STATUS_OBJECT_NAME_NOT_FOUND || IoStatusBlock.Information == FILE_DOES_NOT_EXIST) {
KdPrint(("file does not exist\n"));
}
return status;
}
Length = Length + 520;//为何加这个数字,请看ZwEnumerateFile1的说明。
FileInformation = ExAllocatePoolWithTag(NonPagedPool, Length, TAG);
if (FileInformation == NULL) {
status = STATUS_UNSUCCESSFUL;
DbgPrint("发生错误的文件为:%s, 代码行为:%d\n", __FILE__, __LINE__);
ZwClose(FileHandle);
return status;
}
RtlZeroMemory(FileInformation, Length);
status = ZwQueryDirectoryFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, FileInformation, Length, FileDirectoryInformation, TRUE, NULL, TRUE);
if (!NT_SUCCESS (status))
{
KdPrint(("ZwQueryDirectoryFile fail with 0x%x.\n", status));//STATUS_BUFFER_TOO_SMALL == C0000023
ExFreePoolWithTag(FileInformation, TAG);
ZwClose(FileHandle);
return status;
}
do
{
UNICODE_STRING FileName ={0};
FILE_DIRECTORY_INFORMATION * fibdi = 0;
status = ZwQueryDirectoryFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, FileInformation, Length, FileDirectoryInformation, TRUE, NULL, FALSE);
if (status != STATUS_NO_MORE_FILES && status != STATUS_SUCCESS)
{
break;//这里好像没有走过。
}
fibdi = FileInformation;
if (FILE_ATTRIBUTE_DIRECTORY == fibdi->FileAttributes)
{
//这里可以考虑递归。这里放弃了文件夹的显示。
continue;
}
FileName.Buffer = fibdi->FileName;
FileName.Length = (USHORT)fibdi->FileNameLength;
FileName.MaximumLength = FileName.Length + 2;
KdPrint(("FileName %wZ\n", &FileName));
} while (status != STATUS_NO_MORE_FILES);
if (FileInformation)
{
ExFreePoolWithTag(FileInformation, TAG);
FileInformation = NULL;
}
ZwClose(FileHandle);
return status;
}
#pragma INITCODE
DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT * DriverObject, __in PUNICODE_STRING RegistryPath)
{
//经测试,这三种类型的路径都是可以的。
UNICODE_STRING directory = RTL_CONSTANT_STRING(L"\\??\\C:\\test");
//UNICODE_STRING directory = RTL_CONSTANT_STRING(L"\\DosDevices\\C:\\test");
//UNICODE_STRING directory = RTL_CONSTANT_STRING(L"\\Device\\HarddiskVolume1\\test");
/*
注意:
\\Device\\HarddiskVolume1\\是可以的;
\\Device\\HarddiskVolume1是不可以的。
*/
KdBreakPoint();
DriverObject->DriverUnload = Unload;
return ZwEnumerateFile2(&directory);//, FileIdBothDirectoryInformation
}
没有评论:
发表评论