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

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

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

在概述中提到过,目录遍历的核心是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代表是目录,反之则是文件,实现目录文件遍历完整代码如下所示;

// 署名权
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: me@lyshark.com
#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.com \n");

	// 遍历文件夹和文件
	UNICODE_STRING ustrQueryFile;
	RtlInitUnicodeString(&ustrQueryFile, L"\\??\\C:\\Windows");
	MyQueryFileAndFileFolder(ustrQueryFile);

	DbgPrint("驱动加载成功 \n");
	Driver->DriverUnload = UnDriver;
	return STATUS_SUCCESS;
}

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java蓝桥杯

目录 往年真题 题目分类 搜索 动态规划 并查集 贪心算法 二分查找 输入输出 图论 其他 往年真题 2022年第十三届蓝桥杯大赛软件类决赛Java研究生组真题 - 题库 - C语言网 2021年蓝桥杯第十二届省赛及国赛真题 - 题库 - C语言网 2020年蓝桥杯第十一届省赛及国赛真题…

Nginx网站服务

文章目录 Nginx网站服务一.Nginx服务基础1.关于Nginx2.Nginx和Apache的差异&#xff1a;3.编译安装Nginx服务(1)关闭防火墙(2)安装依赖包(3)创建运行用户、组&#xff08;Nginx服务程序默认以nobody身份运行&#xff0c;建议为其创建专门的用户账号&#xff0c;以便更准确地控制…

深眸科技专注机器视觉的研发与创新,开启工业自动化、智能化进程

在智能制造、工业效能提升的社会背景之下&#xff0c;中国制造2025战略持续落实&#xff0c;工业制造业转型升级加速&#xff0c;作为人工智能领域重要技术之一的机器视觉&#xff0c;凭借着高精度、高准确度等优势检测能力&#xff0c;不断渗透进工业领域&#xff0c;并呈现出…

oVirt 4.4.10三节点超融合集群安装配置及集群扩容(三)

本篇主要记录安装及使用过程中遇到的问题<包含4.4.x, 4.5.x> 设置engine管理页面可以通过IP访问ssh连接engine服务器并在/etc/ovirt-engine/engine.conf.d新建99-custom-sso-setup.conf,添加engine节点的IP或出口IPSSO_ALTERNATE_ENGINE_FQDNS="engine103.cluster.…

day54_spring整合mybatis

SpringMybatis整合【重点】 Spring学完了,主要学习Spring两个内容:IOCAOP 利用这两个知识来完成spring和mybatis的整合 IOC: 控制反转,用来创建对象 XxxService通过数据源创建数据库连接创建SqlSessionFactory创建SqlSession获得XxxMapper代理对象 AOP: 面向切面 控制事务 具体…

STM32——08-STM32感应开关盖垃圾桶

项目二&#xff1a;感应开关盖垃圾桶 项目需求 检测靠近时&#xff0c;垃圾桶自动开盖并伴随滴一声&#xff0c; 2 秒后关盖 发生震动时&#xff0c;垃圾桶自动开盖并伴随滴一声&#xff0c; 2 秒后关盖 按下按键时&#xff0c;垃圾桶自动开盖并伴随滴一声&#xff0c; 2 秒后…

插件化工程R文件瘦身技术方案 | 京东云技术团队

随着业务的发展及版本迭代&#xff0c;客户端工程中不断增加新的业务逻辑、引入新的资源&#xff0c;随之而来的问题就是安装包体积变大&#xff0c;前期各个业务模块通过无用资源删减、大图压缩或转上云、AB实验业务逻辑下线或其他手段在降低包体积上取得了一定的成果。 在瘦…

【2023年最新】提高分类模型指标的六大方案详解

文章目录 数据增强特征选择调整模型参数模型集成迁移学习模型解释完结 当今&#xff0c;机器学习模型得到了广泛的应用&#xff0c;其中分类模型是其中最常见和重要的一种。在实际应用中&#xff0c;如何提高分类模型的指标&#xff0c;使其在不同场景下表现更佳并且具有更好的…

Vue中如何进行音频可视化与音频频谱展示

Vue中如何进行音频可视化与音频频谱展示 随着音频应用程序的不断发展&#xff0c;音频可视化和音频频谱展示成为了重要的功能。在Vue应用程序中实现音频可视化和音频频谱展示可以帮助用户更好地了解音频文件的内容和特征。本文将介绍如何在Vue应用程序中实现音频可视化和音频频…

《嵌入式系统》知识总结10:使用位带操作操纵GPIO

位操作 汇编层面 外设控制常要针对字中某个位&#xff08;Bit&#xff09;操作 以字节编址的存储器地址空间中&#xff0c;需要3步骤&#xff08;读出-修改-写回&#xff09; 1.&#xff08;从外设&#xff09;读取包含该位的字节数据 2. 设置该位为0或1、同时屏蔽其他位&am…

POI in Action

1 POI 组件依赖 按需引入对应依赖 (给出官方的指引) 组件作用Maven依赖POIFSOLE2 FilesystempoiHPSFOLE2 Property SetspoiHSSFExcel XLSpoiHSLFPowerPoint PPTpoi-scratchpadHWPFWord DOCpoi-scratchpadHDGFVisio VSDpoi-scratchpadHPBFPublisher PUBpoi-scratchpadHSMFOutl…

【gitflow】 概念基本介绍

gitflow 简介 什么是gitflow&#xff1f; 我们大家都很会用git&#xff0c;但是我们很少去关心我们要怎么用branch和版本控制。 只知道master是第一个主分支&#xff0c;其他分支都是次要分支&#xff0c; 那你知道如下的问题如何回答吗&#xff1f; 如何保证主分支的稳定…

【哈佛积极心理学笔记】第22讲 自尊与自我实现

第22讲 自尊与自我实现 Unconditional self-esteem is the highest level, the level that Maslow would talk about “the self-actualization”, what David Schnarch talks about as “differentiated” or at the level of being known rather than desiring to be valida…

C语言复合类型之结构(struct)篇(结构指针)

结构相关知识总结 什么是结构&#xff1f;结构的声明与简单使用结构的初始化结构中成员变量的访问结构的初始化器结构数组结构数组的声明结构数组的成员标识 结构的嵌套结构指针结构作为参数在函数中传递将结构成员作为参数进行传递将结构地址(指向结构的指针)作为参数进行传递…

C语言进阶--指针(C语言灵魂)

目录 1.字符指针 2.指针数组 3.数组指针 4.数组参数与指针参数 4.1.一维数组传参 4.2.二维数组传参 4.3.一级指针传参 4.4.二级指针传参 5.函数指针 6.函数指针数组 7.指向函数指针数组的指针 8.回调函数 qsort函数 9.指针和数组笔试题 10.指针笔试题 前期要点回…

Linux学习[16]bash学习深入2---别名设置alias---history指令---环境配置相关

文章目录 前言1. alias2. history3. 环境配置相关总结 前言 linux学习15里面简单提了一下alias指令&#xff0c;就表明它是一个别名的作用&#xff0c;这节就展开来写一下。 同时上一节一笔带过的history指令&#xff0c;这一节也进行例子的演示记录。 最后是环境相关的配置&a…

常用API(String,ArrayList)

1:String类概述 String是字符串类型&#xff0c;可以定义字符串变量指向字符串对象String是不可变字符串的原因&#xff1f;1.String变量每次的修改都是产生并指向新的字符串对象。2.原来的字符串对象都是没有改变的&#xff0c;所以称不可变字符串。 2&#xff1a;String创建…

八股文总结

文章目录 项目介绍1.不动产项目项目难点机器学习算法调研图像提取算法调研数据集-ImageNetXceptionVGGInceptionDensenetMobilenet 系统流程图 2.图书项目技术栈ShiroMybatisMyBatis:Mybatis Plus: 面试问题 Java基础基本数据类型反射接口和抽象类异常代理模式1. 静态代理2. 动…

『DevOps最佳实践』使用Jenkins和Harbor进行持续集成和交付的解决方案

&#x1f4e3;读完这篇文章里你能收获到 全文采用图文形式讲解学会使用Harbor配置项目学会在Jenkins中配置Harbor推送权限使用Jenkins和Harbor进行持续集成的实践感谢点赞收藏&#xff0c;避免下次找不到~ 文章目录 一、准备工作1. 环境准备2. 修改Docker配置文件3. Docker登陆…

【SpringCloud】三、Nacos服务注册+配置管理+集群搭建

文章目录 一、认识Nacos1、安装2、服务注册和发现3、服务分级存储模型4、负载均衡策略--NacosRule5、服务实例的权重设置5、环境隔离namespace6、Eureka和Nacos的区别 二、Nacos配置管理1、统一配置管理2、微服务配置拉取3、配置热更新4、多环境配置共享 三、Nacos集群搭建1、初…