IO Stack Location

本文详细介绍了IRP(I/O请求包)及其在驱动程序中的作用方式,特别是IO堆栈区的构建和使用。文章解释了IO管理器如何为每个驱动分配IO堆栈区,以及这些堆栈如何用于传递IO请求信息。此外,还探讨了不同类型的主功能代号和辅功能代号,以及它们在处理IO请求中的角色。
为了驱动的构建,在IRP建立时,IO管理器给每个驱动分配一个IO堆栈区,每个IO堆栈区由 IO_STACK_LOCATION 结构组成。
    IO管理器为每个IRP建立了一个IO堆栈序列,这个序列中每个IO堆栈可以给驱动使用。每个驱动拥有这个序列中的一个堆栈结构,并且
可以通过IoGetCurrentIrpStackLocation函数取得这个IO操作的详细信息。
    驱动程序可以通过调用IoGetNextIrpStackLocation函数来设置下一个IO堆栈,此时序列前面的IO堆栈也能被某些操作使用。所以我们
应该使用IoCompletion来完成最终的清除任理。
    这个“在每层驱动中处理IRP”的模型告诉我们最初的IRP包含了两个IO堆栈也就是两个驱动。一个是文件系统驱动、另一个是块存储设
备,已分配IRP的驱动在这个模型中并不拥有FSD堆栈,高层驱动为低层驱动分配IRP并决定低层驱动可以使用多少堆栈多少IRP,低层设备对
象可以根据StackSize的值得知。
    
    这个模型的IO堆栈通常还需要包含下面一些信息。
    ·主功能代号(IRP_MJ_XXX),标志着这个驱动程序的基本功能。
    ·辅功能代号(IRP_MN_XXX),高层SCSI驱动和所有的即插即用设备驱动中使用它们表示处理这些操作的子情况。
    ·设置操作细节的参数,例如 一个缓冲区的起始点和长度、向哪里输出或从哪里输入。
    ·一个已创建设备的指针,表示操作的目标(物理设备、逻辑设备或虚拟设备)。
    ·一个文件对象的指针,表示一个打开的文件、设备、目录或被看作文件的IO堆栈。驱动程序通常会忽略它。
    IRP使用的主功能代号和辅功能代号受驱动程序细节限制,不过低层驱动和中间层驱动(包含即插即用设备和过滤驱动)通常实现下面这
些基本功能:
    IRP_MJ_CREATE    打开一个设备对象,标志着引用并使用IO操作。
    IRP_MJ_READ    从设备中读取数据。
    IRP_MJ_WRITE    向设备中写入数据。
    IRP_MJ_DEVICE_CONTROL    建立(或重置)设备,依据系统依赖性和这类设备具体IO控制代号(IOCTL)。
    IRP_MJ_CLOSE    关闭这个设备对象。
    IRP_MJ_PNP    完成“插入并使用”操作。这个请求由即插即用设备管理器通过IO管理器发出。
    IRP_MJ_POWER    完成设备的电源操作。这个请求由电源管理器通过IO管理器发出。
    关于更多IRP主功能代号的信息请查阅“IRP Major Function Codes”。
    
    一般IO管理器发送的IRP至少带着两个堆栈。文件系统层是在驱动层之后,所以驱动层需要块存储设备来组织存储。IO管理器发送IRP到
最底层的驱动。
    无论如何,IO管理器都应该支持向驱动链中添加一个驱动程序。例如,一个镜像驱动器是己有硬盘分驱一部分数据的备份,就像一个文
件系统和底层驱动之间的上面所说的IRP模型。当新驱动把它自己添加到驱动堆栈时,IO管理器调整所有IRP的IO堆栈的数目然后通知文件系
统、镜像、和底层驱动。文件系统的每个IRP请求处理链中将包含这个IO堆栈就像添加一个新镜像。
    需要注意的是,这个添加驱动到现有驱动链的设计使应用到某些设备上将会受到一些约束。
    ·一个高层驱动在某些IRP情况下可以安全访问它自己拥有的低层IO堆栈。这样的驱动必须安装这个IO堆栈给给这IRP链上的下一层驱动
,无论如何在设计这样的高层驱动,你不能预料到新驱动是不是会或者什么时候安装驱动链下面的位置中。
    所以,你应该假设以后添加的驱动将会处理相同的IRP主功能代号(IRP_MJ_XXX)取代你所要处理的硬件设备。
    ·在某些IRP情况下低层驱动可以安全访问它自己拥有的IO堆栈。当设计驱动时,你不能预知是否或何时新驱动安装在更高层,。
    在设计低层驱动时,应假设新驱动能够使用你的驱动的IO堆栈中的信息继续处理,而无论新驱动的来源或是有多少层。
/* File Kmd.cpp By WzrterFX */ #include "Kmd.h" namespace Kmd { NTSTATUS Kmd::Create(PDRIVER_OBJECT driverObject) { NTSTATUS status = STATUS_UNSUCCESSFUL; UNICODE_STRING deviceName { }; RtlInitUnicodeString(&deviceName, L"\\Device\\Kmd"); status = IoCreateDevice( driverObject, NULL, &deviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &_deviceObject ); if (!NT_SUCCESS(status)) { DbgPrintEx(0, 0, "Fatal, failed to create driver device.\n" ); return status; } UNICODE_STRING symbolicLink { }; RtlInitUnicodeString(&symbolicLink, L"\\DosDevices\\Kmd"); status = IoCreateSymbolicLink(&symbolicLink, &deviceName); if (!NT_SUCCESS(status)) { DbgPrintEx(0, 0, "Fatal, failed to establish driver link.\n" ); IoDeleteDevice(_deviceObject); return status; } SetFlag(_deviceObject->Flags, DO_BUFFERED_IO); driverObject->MajorFunction[IRP_MJ_CREATE] = [](PDEVICE_OBJECT, PIRP io) -> NTSTATUS { IoCompleteRequest(io, IO_NO_INCREMENT); return io->IoStatus.Status; }; driverObject->MajorFunction[IRP_MJ_CLOSE] = [](PDEVICE_OBJECT, PIRP io) -> NTSTATUS { IoCompleteRequest(io, IO_NO_INCREMENT); return io->IoStatus.Status; }; driverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = &this->KmdControl; ClearFlag(_deviceObject->Flags, DO_DEVICE_INITIALIZING); return STATUS_SUCCESS; } NTSTATUS Kmd::KmdControl(PDEVICE_OBJECT, PIRP io) { NTSTATUS status = STATUS_UNSUCCESSFUL; PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(io); if (!stack) { IoCompleteRequest(io, IO_NO_INCREMENT); DbgPrintEx(0, 0, "Fatal, missing driver stack location.\n" ); return status; } PKmdRequest request = reinterpret_cast<PKmdRequest>(io->AssociatedIrp.SystemBuffer); if (!request) { IoCompleteRequest(io, IO_NO_INCREMENT); DbgPrintEx(0, 0, "Fatal, missing driver associated request.\n" ); return status; } static PEPROCESS process { }; static SIZE_T reserved { }; switch (stack->Parameters.DeviceIoControl.IoControlCode) { case ::Kmd::_IoCtls::attach: { status = ::Kmd::_NtifsApi::PsLookupProcessByProcessId( request->attachRequest.process, &process ); break; } case ::Kmd::_IoCtls::read: { if (process) { status = ::Kmd::_NtifsApi::MmCopyVirtualMemory( process, request->copyMemoryRequest.from, PsGetCurrentProcess(), request->copyMemoryRequest.to, request->copyMemoryRequest.requested, MODE::KernelMode, &reserved ); } break; } case ::Kmd::_IoCtls::write: { if (process) { status = ::Kmd::_NtifsApi::MmCopyVirtualMemory( PsGetCurrentProcess(), request->copyMemoryRequest.to, process, request->copyMemoryRequest.from, request->copyMemoryRequest.requested, MODE::KernelMode, &reserved ); } break; } default: { status = STATUS_INVALID_DEVICE_REQUEST; break; } } io->IoStatus.Status = status; io->IoStatus.Information = sizeof(KmdRequest); IoCompleteRequest(io, IO_NO_INCREMENT); return status; } }帮我全部加上注释
03-22
<think>好的,我现在需要帮用户给提供的C++内核模式驱动代码添加注释。首先,我要仔细阅读并理解这段代码的结构和功能。代码位于Kmd.cpp文件中,属于Kmd命名空间,包含Kmd类的Create和KmdControl两个方法。 首先看Create方法。这个方法的作用应该是初始化驱动程序,创建设备对象和符号链接。用户可能不太熟悉Windows内核驱动的结构,所以我需要解释每个关键函数的作用,比如IoCreateDevice、IoCreateSymbolicLink,以及设置DO_BUFFERED_IO标志的意义。还要注意Lambda表达式处理IRP_MJ_CREATE和IRP_MJ_CLOSE的情况,以及将IRP_MJ_DEVICE_CONTROL指向KmdControl方法。 接下来是KmdControl方法,处理设备控制请求。这里需要解释IO控制码的分发,比如attach、read、write操作。特别是PsLookupProcessByProcessId和MmCopyVirtualMemory这些内核API的作用,以及它们如何实现进程内存的读写。同时,需要注意静态变量process和reserved的作用,可能用于跨请求保持进程状态。 用户可能希望注释详细但不过于冗长,所以每个关键步骤和函数调用都需要简明扼要的解释。还需要注意代码中的错误处理部分,比如NTSTATUS状态检查,设备对象删除等,说明为什么这些步骤是必要的。 另外,要确保注释符合代码规范,使用中文,并且遵循用户提供的系统级指令,比如数学表达式的格式,但这段代码中没有数学内容,所以可能不需要。注释需要结构清晰,分块解释,帮助用户逐步理解代码的功能和实现细节。 最后,检查是否有遗漏的部分,比如命名空间、头文件包含、宏定义等,确保注释覆盖所有重要部分,帮助用户全面理解这段内核驱动代码的工作原理。</think>以下是为代码添加的中文注释,按照功能模块分块解释: ```cpp /* File Kmd.cpp By WzrterFX */ #include "Kmd.h" namespace Kmd { /* 驱动创建入口函数 */ NTSTATUS Kmd::Create(PDRIVER_OBJECT driverObject) { NTSTATUS status = STATUS_UNSUCCESSFUL; // 创建设备对象 UNICODE_STRING deviceName { }; RtlInitUnicodeString(&deviceName, L"\\Device\\Kmd"); // 初始化设备名 status = IoCreateDevice( driverObject, // 所属驱动对象 NULL, // 无扩展信息 &deviceName, // 设备名称 FILE_DEVICE_UNKNOWN, // 设备类型 FILE_DEVICE_SECURE_OPEN, // 安全设置 FALSE, // 非独占设备 &_deviceObject // 输出设备对象指针 ); if (!NT_SUCCESS(status)) { // 创建设备失败处理 DbgPrintEx(0, 0, "Fatal, failed to create driver device.\n"); return status; } // 创建符号链接(用户态可访问) UNICODE_STRING symbolicLink { }; RtlInitUnicodeString(&symbolicLink, L"\\DosDevices\\Kmd"); status = IoCreateSymbolicLink(&symbolicLink, &deviceName); if (!NT_SUCCESS(status)) { // 创建链接失败处理 DbgPrintEx(0, 0, "Fatal, failed to establish driver link.\n"); IoDeleteDevice(_deviceObject); // 回滚操作:删除已创建的设备 return status; } // 设置设备标志(使用缓冲I/O) SetFlag(_deviceObject->Flags, DO_BUFFERED_IO); // 设置IRP处理函数(使用Lambda表达式) driverObject->MajorFunction[IRP_MJ_CREATE] = [](PDEVICE_OBJECT, PIRP io) -> NTSTATUS { IoCompleteRequest(io, IO_NO_INCREMENT); // 立即完成请求 return io->IoStatus.Status; }; driverObject->MajorFunction[IRP_MJ_CLOSE] = [](PDEVICE_OBJECT, PIRP io) -> NTSTATUS { IoCompleteRequest(io, IO_NO_INCREMENT); return io->IoStatus.Status; }; // 设置设备控制处理函数 driverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = &this->KmdControl; // 清除设备初始化标志(允许接收请求) ClearFlag(_deviceObject->Flags, DO_DEVICE_INITIALIZING); return STATUS_SUCCESS; } /* 设备控制请求处理函数 */ NTSTATUS Kmd::KmdControl(PDEVICE_OBJECT, PIRP io) { NTSTATUS status = STATUS_UNSUCCESSFUL; // 获取当前IRP栈 PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(io); if (!stack) { // 栈位置验证 IoCompleteRequest(io, IO_NO_INCREMENT); DbgPrintEx(0, 0, "Fatal, missing driver stack location.\n"); return status; } // 获取用户请求缓冲区 PKmdRequest request = reinterpret_cast<PKmdRequest>(io->AssociatedIrp.SystemBuffer); if (!request) { // 缓冲区验证 IoCompleteRequest(io, IO_NO_INCREMENT); DbgPrintEx(0, 0, "Fatal, missing driver associated request.\n"); return status; } // 静态变量保持进程状态(跨请求) static PEPROCESS process { }; static SIZE_T reserved { }; // 根据控制码分发操作 switch (stack->Parameters.DeviceIoControl.IoControlCode) { case ::Kmd::_IoCtls::attach: { // 附加进程 status = ::Kmd::_NtifsApi::PsLookupProcessByProcessId( request->attachRequest.process, // 目标进程ID &process // 输出进程对象 ); break; } case ::Kmd::_IoCtls::read: { // 读取进程内存 if (process) { status = ::Kmd::_NtifsApi::MmCopyVirtualMemory( process, request->copyMemoryRequest.from, // 源进程地址 PsGetCurrentProcess(), request->copyMemoryRequest.to, // 目标进程地址(当前进程) request->copyMemoryRequest.requested, // 读取大小 MODE::KernelMode, &reserved // 内核模式访问 ); } break; } case ::Kmd::_IoCtls::write: { // 写入进程内存 if (process) { status = ::Kmd::_NtifsApi::MmCopyVirtualMemory( PsGetCurrentProcess(), request->copyMemoryRequest.to, // 源进程地址(当前进程) process, request->copyMemoryRequest.from, // 目标进程地址 request->copyMemoryRequest.requested, MODE::KernelMode, &reserved ); } break; } default: { // 无效请求处理 status = STATUS_INVALID_DEVICE_REQUEST; break; } } // 设置返回状态 io->IoStatus.Status = status; io->IoStatus.Information = sizeof(KmdRequest); // 返回数据大小 // 完成请求 IoCompleteRequest(io, IO_NO_INCREMENT); return status; } } ``` 代码功能总结: 1. **驱动初始化**:创建`\Device\Kmd`设备对象和`\DosDevices\Kmd`符号链接,设置缓冲I/O模式 2. **IRP处理**: - 基础请求:直接完成`CREATE`/`CLOSE`请求 - 设备控制:通过`KmdControl`处理核心逻辑 3. **内存操作**: - `attach`:通过进程ID获取进程对象 - `read`:从目标进程读取内存到当前进程 - `write`:从当前进程写入内存到目标进程 4. **安全机制**: - 使用`MmCopyVirtualMemory`进行安全内存拷贝 - 内核模式访问验证 - 严格的参数有效性检查
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值