8.3 Windows驱动开发:内核遍历文件或目录

在笔者前一篇文章《内核文件读写系列函数》简单的介绍了内核中如何对文件进行基本的读写操作,本章我们将实现内核下遍历文件或目录这一功能,该功能的实现需要依赖于ZwQueryDirectoryFile这个内核API函数来实现,该函数可返回给定文件句柄指定的目录中文件的各种信息,此类信息会保存在PFILE_BOTH_DIR_INFORMATION结构下,通过遍历该目录即可获取到文件的详细参数,如下将具体分析并实现遍历目录功能。

该功能也是ARK工具的最基本功能,如下图是一款通用ARK工具的文件遍历功能的实现效果;

在概述中提到过,目录遍历的核心是ZwQueryDirectoryFile()系列函数,该函数可返回给定文件句柄指定的目录中文件的各种信息,其微软官方定义如下;

ZwQueryDirectoryFile是Windows操作系统中的一个系统调用函数,用于查询目录中的文件信息。具体而言,它可以用来枚举一个目录中的所有文件,并返回每个文件的名称、属性、时间戳等信息。

调用ZwQueryDirectoryFile函数需要指定以下参数:

  • 目录句柄:表示要查询的目录的句柄,可以通过调用ZwOpenFile函数打开目录获取。
  • 文件信息类:表示要返回的文件信息的类型,如文件名、文件大小、文件时间戳等。
  • 文件信息缓冲区:表示存放返回文件信息的缓冲区,其大小必须足够大以容纳查询结果。
  • 缓冲区大小:表示文件信息缓冲区的大小。
  • 是否遍历子目录:指定是否遍历目录中的子目录。
  • 文件名匹配模式:指定查询的文件名模式,支持通配符。
  • 是否返回长文件名:指定是否返回长文件名。
  • 函数执行成功时,将返回STATUS_SUCCESS,同时将文件信息写入文件信息缓冲区中。当返回STATUS_NO_MORE_FILES时,表示目录中没有更多的文件需要枚举。

需要注意的是,使用ZwQueryDirectoryFile函数需要具有足够的权限,并且应该对返回的文件信息进行适当的处理,以避免潜在的安全问题。

NTSYSAPI NTSTATUS ZwQueryDirectoryFile([in]           HANDLE                 FileHandle,            // 返回的文件对象的句柄,表示要为其请求信息的目录。[in, optional] HANDLE                 Event,                 // 调用方创建的事件的可选句柄。 [in, optional] PIO_APC_ROUTINE        ApcRoutine,            // 请求的操作完成时要调用的可选调用方提供的 APC 例程的地址。[in, optional] PVOID                  ApcContext,            // 如果调用方提供 APC 或 I/O 完成对象与文件对象关联,则为调用方确定的上下文区域的可选指针。[out]          PIO_STATUS_BLOCK       IoStatusBlock,         // 指向 IO_STATUS_BLOCK 结构的指针,该结构接收最终完成状态和有关操作的信息。[out]          PVOID                  FileInformation,       // 指向接收有关文件的所需信息的输出缓冲区的指针。[in]           ULONG                  Length,                // FileInformation 指向的缓冲区的大小(以字节为单位)。[in]           FILE_INFORMATION_CLASS FileInformationClass,  // 要返回的有关目录中文件的信息类型。[in]           BOOLEAN                ReturnSingleEntry,     // 如果只应返回单个条目,则设置为 TRUE ,否则为 FALSE 。[in, optional] PUNICODE_STRING        FileName,              // 文件路径[in]           BOOLEAN                RestartScan            // 如果扫描是在目录中的第一个条目开始,则设置为 TRUE 。
);

该函数我们需要注意FileInformation参数,在本例中它被设定为了PFILE_BOTH_DIR_INFORMATION用于存储当前节点下文件或目录的一些属性,如文件名,文件时间,文件状态等,其次FileInformationClass参数也是有多种选择的,本例中我们需要遍历文件或目录则设置成FileBothDirectoryInformation就可以,在循环遍历文件时需要将当前目录.以及上一级目录…排除,而pDir->FileAttributes则用于判断当前节点是文件还是目录,属性FILE_ATTRIBUTE_DIRECTORY代表是目录,反之则是文件,实现目录文件遍历完整代码如下所示;

#include <ntifs.h>
#include <ntstatus.h>// 遍历文件夹和文件
BOOLEAN MyQueryFileAndFileFolder(UNICODE_STRING ustrPath)
{HANDLE hFile = NULL;OBJECT_ATTRIBUTES objectAttributes = { 0 };IO_STATUS_BLOCK iosb = { 0 };NTSTATUS status = STATUS_SUCCESS;// 初始化结构InitializeObjectAttributes(&objectAttributes, &ustrPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);// 打开文件得到句柄status = ZwCreateFile(&hFile, FILE_LIST_DIRECTORY | SYNCHRONIZE | FILE_ANY_ACCESS,&objectAttributes, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE,FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,NULL, 0);if (!NT_SUCCESS(status)){return FALSE;}// 为节点分配足够的空间ULONG ulLength = (2 * 4096 + sizeof(FILE_BOTH_DIR_INFORMATION)) * 0x2000;PFILE_BOTH_DIR_INFORMATION pDir = ExAllocatePool(PagedPool, ulLength);// 保存pDir的首地址PFILE_BOTH_DIR_INFORMATION pBeginAddr = pDir;// 获取信息,返回给定文件句柄指定的目录中文件的各种信息status = ZwQueryDirectoryFile(hFile, NULL, NULL, NULL, &iosb, pDir, ulLength, FileBothDirectoryInformation, FALSE, NULL, FALSE);if (!NT_SUCCESS(status)){ExFreePool(pDir);ZwClose(hFile);return FALSE;}// 遍历UNICODE_STRING ustrTemp;UNICODE_STRING ustrOne;UNICODE_STRING ustrTwo;RtlInitUnicodeString(&ustrOne, L".");RtlInitUnicodeString(&ustrTwo, L"..");WCHAR wcFileName[1024] = { 0 };while (TRUE){// 判断是否是..上级目录或是.本目录RtlZeroMemory(wcFileName, 1024);RtlCopyMemory(wcFileName, pDir->FileName, pDir->FileNameLength);RtlInitUnicodeString(&ustrTemp, wcFileName);// 是否是.或者是..目录if ((0 != RtlCompareUnicodeString(&ustrTemp, &ustrOne, TRUE)) && (0 != RtlCompareUnicodeString(&ustrTemp, &ustrTwo, TRUE))){// 判断是文件还是目录if (pDir->FileAttributes & FILE_ATTRIBUTE_DIRECTORY){// 目录DbgPrint("[目录] 创建时间: %u | 改变时间: %u 目录名: %wZ \n", pDir->CreationTime, &pDir->ChangeTime, &ustrTemp);}else{// 文件DbgPrint("[文件] 创建时间: %u | 改变时间: %u | 文件名: %wZ \n", pDir->CreationTime, &pDir->ChangeTime, &ustrTemp);}}// 遍历完毕直接跳出循环if (0 == pDir->NextEntryOffset){break;}// 每次都要将pDir指向新的地址pDir = (PFILE_BOTH_DIR_INFORMATION)((PUCHAR)pDir + pDir->NextEntryOffset);}// 释放内存并关闭句柄ExFreePool(pBeginAddr);ZwClose(hFile);return TRUE;
}VOID UnDriver(PDRIVER_OBJECT driver)
{DbgPrint("驱动卸载成功 \n");
}NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{DbgPrint("Hello lyshark \n");// 遍历文件夹和文件UNICODE_STRING ustrQueryFile;RtlInitUnicodeString(&ustrQueryFile, L"\\??\\C:\\Windows");MyQueryFileAndFileFolder(ustrQueryFile);DbgPrint("驱动加载成功 \n");Driver->DriverUnload = UnDriver;return STATUS_SUCCESS;
}

编译如上驱动程序并运行,则会输出C:\\Windows目录下的所有文件和目录,以及创建时间和修改时间,输出效果如下图所示;

你是否会觉得很失望,为什么不是递归枚举,这里为大家解释一下,通常情况下ARK工具并不会在内核层实现目录与文件的递归操作,而是将递归过程搬到了应用层,当用户点击一个新目录时,在应用层只需要拼接新的路径再次发送给驱动程序让其重新遍历一份即可,这样不仅可以提高效率而且还降低了蓝屏的风险,显然在应用层遍历是更合理的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/231011.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MyBatis使用教程详解<下>

回顾上一篇博文,我们讲了如何使用注解/XML的方式来操作数据库,实际上,一个Mapper接口的实现,这两种方式是可以并存的. 上一篇博文中,我们演示的都是比较简单的SQL语句,没有设计到复杂的逻辑,本篇博文会讲解复杂SQL的实现及一些细节处理.话不多说,让我们开始吧. 一. #{}和${} …

软文推广中什么样的热点值得追?

只要媒体存在一日&#xff0c;那世界上就不会缺热点&#xff0c;追热点应该是每个运营er的必备技能&#xff0c;但是市面上的热点层出不穷&#xff0c;什么样的热点才值得追呢&#xff1f;接下来媒介盒子就和大家聊聊&#xff1a;判断热点值不值得追的三大要素。 一、 事件属性…

竞赛选题 题目:基于深度学习的中文对话问答机器人

文章目录 0 简介1 项目架构2 项目的主要过程2.1 数据清洗、预处理2.2 分桶2.3 训练 3 项目的整体结构4 重要的API4.1 LSTM cells部分&#xff1a;4.2 损失函数&#xff1a;4.3 搭建seq2seq框架&#xff1a;4.4 测试部分&#xff1a;4.5 评价NLP测试效果&#xff1a;4.6 梯度截断…

视图层与模板层

视图层 1 视图函数 一个视图函数&#xff0c;简称视图&#xff0c;是一个简单的Python 函数&#xff0c;它接受Web请求并且返回Web响应。响应可以是一张网页的HTML内容&#xff0c;一个重定向&#xff0c;一个404错误&#xff0c;一个XML文档&#xff0c;或者一张图片. . . 是…

基于AOP的声明式事物控制

目录 Spring事务编程概述 基于xml声明式事务控制 事务属性 isolation timeout read-only propagation 全注解开发 Spring事务编程概述 事务是开发中必不可少的东西&#xff0c;使用JDBC开发时&#xff0c;我们使用connection对事务进行控制&#xff0c;使用MyBatis时&a…

接口测试【加密解密攻防完整版】实战教程详解

一、对称加密 对称加密算法是共享密钥加密算法&#xff0c;在加密解密过程中&#xff0c;使用的密钥只有一个。发送和接收双方事先都知道加密的密钥&#xff0c;均使用这个密钥对数据进行加密和解密。 数据加密&#xff1a;在对称加密算法中&#xff0c;数据发送方将明文 (原…

html5各行各业官网模板源码下载(1)

文章目录 1.来源2.源码模板2.1 HTML5白色简洁设计师网站模板 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/134682321 html5各行各业官网模板源码下载&#xff0c;这个主题覆盖各行业的html官网模板&#xff0c;效果模…

C++学习寄录(八.继承)

继承的语法&#xff1a;class 子类 : 继承方式 父类 class A : public B; A 类称为子类 或 派生类 B 类称为父类 或 基类 1.基本使用 未使用继承的代码比较冗余重复 #include <iostream> #include <fstream> #include <string> #include <chrono>…

【计算机网络】虚拟路由冗余(VRRP)协议原理与配置

目录 1、VRRP虚拟路由器冗余协议 1.1、协议作用 1.2、名词解释 1.3、简介 1.4、工作原理 1.5、应用实例 2、 VRRP配置 2.1、配置命令 1、VRRP虚拟路由器冗余协议 1.1、协议作用 虚拟路由冗余协议(Virtual Router Redundancy Protocol&#xff0c;简称VRRP)是由IETF…

ArkTS-DevEco Studio打开预览器报错

下载官网Codelab案例&#xff0c;打开预览器报错 Failed to start the service process. Make sure the path specified by nodejs.dir in the local.properties file is correct. 解决方案 在编辑器设置中找到node安装路径 将" local.properties"文件中的"nod…

python监测GPU使用

参考&#xff1a; https://stackoverflow.com/questions/67707828/how-to-get-every-seconds-gpu-usage-in-python 自己测试 import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim import numpy as np import matplotlib.pyplot…

如何设置Linux终端提示信息

如何设置Linux终端提示信息 1 方法一&#xff1a;只能在VSCode或者Pycharm终端显示提示信息2 方法二&#xff1a;只能在MobaXterm等远程软件上显示提示3 方法三&#xff1a;避免用户没看到上面的提示&#xff0c;上面两种都设置一下 在使用远程终端时&#xff0c;由于多用户使用…