ZwReadFile routine

ZwReadFile routine

ZwReadFile 从一个打开的文件中读取内容

Syntax

 

NTSTATUS ZwReadFile(
  _In_     HANDLE           FileHandle,
  _In_opt_ HANDLE           Event,
  _In_opt_ PIO_APC_ROUTINE  ApcRoutine,
  _In_opt_ PVOID            ApcContext,
  _Out_    PIO_STATUS_BLOCK IoStatusBlock,
  _Out_    PVOID            Buffer,
  _In_     ULONG            Length,
  _In_opt_ PLARGE_INTEGER   ByteOffset,
  _In_opt_ PULONG           Key
);


 

Parameters

FileHandle [in]

ZwCreateFile or ZwOpenFile调用成功后返回的句柄

Event [in, optional]

可选的一个事件对象的句柄,用于当读文件操作完成后设置这个句柄的信号状态设备和中间层驱动应当设置这个参数为NULL。

ApcRoutine [in, optional]

保留,设备和中间层驱动应当设置这个参数为NULL。

ApcContext [in, optional]

保留,设备和中间层驱动应当设置这个参数为NULL。

IoStatusBlock [out]

指向IO_STATUS_BLOCK 结构体的指针用于接收最终完成状态和与读请求有关的信息。 Information 成员接收从文件中读取的实际大小。

Buffer [out]

指向调用者申请的用于接收从文件中所读取数据的缓冲区。

Length [in]

以字节为单位的Buffer指向的缓冲区的大小。

ByteOffset [in, optional]

指向一个变量的指针,该指针指定文件读操作在文件中的开始位置。如果试图在文件结尾之后读取数据ZwReadFile 返回一个错误。

如果 ZwCreateFile 设置了CreateOptions 参数为FILE_SYNCHRONOUS_IO_ALERT 或是 FILE_SYNCHRONOUS_IO_NONALERT之一I/O管理器保管当前的文件位置,如果这样,ZwReadFile 的调用者可以指定当前使用的文件位置而不通过显式传入一个ByteOffset值。这个规范设置可以使用下列方法之一:

· 

1、指定一个指向LARGE_INTEGER值得指针,其HighPart 设置为-1,LowPart 设置为系统定义的值FILE_USE_FILE_POINTER_POSITION

· 

· 

2、传递一个NULL 指针给 ByteOffset参数。

· 

如果I/O管理器保管着当前文件位置,ZwReadFile 通过在完成读取操作时增加读取的字节数更新当前文件的位置。即使I/O管理器保管着当前的文件位置,调用者亦可通过调用ZwReadFile并传递一个显式的ByteOffset重设这个位置。通过这样子做自动改变当前的文件位置到ByteOffset 执行读操作,然后根据实际读取的字节数更新文件位置。这种技术授予调用着自动的seek-and-read服务。

Key [in, optional]

设备和中间层驱动应设置这个指针为NULL。

Return value

ZwReadFile 返回STATUS_SUCCESS 或是一个合适的NTSTATUS 错误码。

Remarks

ZwReadFile 的调用者必须已经设置调用ZwCreateFile 的参数DesiredAccessparameterFILE_READ_DATA 或者 GENERIC_READ如果之前的ZwCreateFile 调用设置了CreateOptions 包括FILE_NO_INTERMEDIATE_BUFFERING ZwReadFile Length ByteOffset 参数必须是sector size的整数倍。更多信息详见 ZwCreateFile

ZwReadFile 从给定的ByteOffset 参数或者是当前文件位置开始读取文件到指定的缓冲区。读操作在以下条件下将被结束:

· 

由于已经读取了Length 参数指定大小的字节数,导致目标缓冲区已经满了。因此无法在不溢出的情况下继续放入更多数据到缓冲区中。

· 

读操作已经到了文件的结尾处,因此没有更多的文件数据可以被传输的缓冲区中。

· 

如果调用者打开文件时在DesiredAccess参数中指定了SYNCHRONIZE标志 调用线程可以通过在文件句柄FileHandle上等待来同步一个读操作的完成。句柄每次在发布的I/O操作完成后变成signaled,然而调用者不可以在一个为同步文件访问(FILE_SYNCHRONOUS_IO_NONALERT or FILE_SYNCHRONOUS_IO_ALERT)而打开的句柄上等待 在这种情况下, ZwReadFile waits on behalf of the caller 并且直到读操作完成才返回。调用者只有在满足以下三种条件后才能安全地等待一个文件句柄:

· 

句柄为异步访问打开。 (指定FILE_SYNCHRONOUS_IO_XXX)

· 

句柄一次只执行一个I/O操作。

· 

ZwReadFile 返回 STATUS_PENDING.

 

在以下任意情况下,驱动文件应当在系统进程的上下文中调用 ZwReadFile 

· 

是驱动创建了传给ZwReadFile的文件句柄

· 

ZwReadFile 将通过一个驱动创建的事件通知驱动I/O的完成。

· 

ZwReadFile 将通过驱动传递给ZwReadFile的一个APC回调同事驱动I/O的完成。

· 

文件和事件句柄仅在创建它们的进程上下文中有效。因此为了避免安全漏洞驱动应当在系统进程的上下文中创建文件或者事件句柄而不是驱动所在的进程上下文中。

同样 ZwReadFile 如果通过APC来通知驱动I/O的完成,ZwReadFile 应当在系统进程的上下文中调用。这是因为APC们中是在发布I/O请求的线程上下文中被引发。如果驱动在不是系统进程的进程的上下文中调用了 ZwReadFile , APC可能被无限期延迟,或者根本不会引发这个APC调用。

对于文件操作的更多内容见: Using Files in a Driver.

ZwReadFile 调用者必须在 IRQL = PASSIVE_LEVEL 上并且 with special kernel APCs enabled.

Note  如果这个函数在用户模式下调用当使用名字"NtReadFile" 代替"ZwReadFile".

 

Requirements

Target platform

Universal

Version

Available starting with Windows 2000.

Header

Wdm.h (include Wdm.h, Ntddk.h, or Ntifs.h)

Library

NtosKrnl.lib

DLL

NtosKrnl.exe

IRQL

PASSIVE_LEVEL (see Remarks section)

DDI compliance rules

PowerIrpDDisBufAfterReqCompletedIntIoctlABufAfterReqCompletedIoctlABufAfterReqCompletedReadA,BufAfterReqCompletedWriteAHwStorPortProhibitedDDIs

See also

KeInitializeEvent

ZwCreateFile

ZwQueryInformationFile

ZwSetInformationFile

ZwWriteFile

.注入的基本原理是内存注入加执行shell code的方式。 2.通过找到重定位shell code的方式,实现注入。 01:52 内核 APC劫持 1.内核APC劫持是通过插一个内核APC来实现用户模式的执行。 2.内核APC在内核模式执行,可以修改RIP和RBP。 03:29 实验环境和兼容性说明 1.实验仅兼容Windows 10及以后版本,不支持Windows 7。 2.Windows 7不兼容的原因包括隐藏内存和导出函数的问题。 07:37 导入导出函数和日志记录 1.引入必要的头文件和导出函数。 2.使用log宏记录错误信息。 09:33 设置APC函数 1.设置APC函数,参数包括进程ID和注入路由。 2.函数内部实现包括获取线程、插入APC等步骤。 18:34 创建和插入APC 1.创建APC,使用no configure put和size of APC。 2.判断APC是否成功创建,并关闭句柄。1.成功执行内核APC,确认PID为5916,TID为4988。 2.通过主线程注入APC,验证内核APC的执行过程。 04:04 寻找KTRAP_FRAME的方法 1.利用堆栈布局寻找KTRAP_FRAME,确保全系统兼容性。 2.通过initial stack、TSS、KPCRB等方式寻找KTRAP_FRAME。 3.选择initial stack方法,因其位置偏移在所有系统上一致。 06:55 获取Initial Stack的方法 1.使用PsGetCurrentProcess()获取current process。 2.通过initial stack减去KTRAP_FRAME大小找到KTRAP_FRAME。 3.验证找到的KTRAP_FRAME是否正确,通过修改地址并断点验证。 11:06 蓝屏问题的解决 1.在尝试修改KTRAP_FRAME时遇到蓝屏问题。 2.通过调试确认蓝屏原因,发现RKL过高导致问题。 3.调整RKL值并重新测试,确认问题解决。.在驱动中申请内存,直接使用 ZwAllocateVirtualMemory 函数。 2.申请内存前需要隐藏 PID 和分配大小。 3.定义函数 Ta,传入 PID 和分配大小。 4.调用 PsLookupProcessById 和 ZwAllocateVirtualMemory。 06:34 读写文件操作 1.读写文件操作使用 ZwGetFileBuffer 函数。 2.传入文件名、二级指针和文件大小。 3.初始化 Unicode 字符串表示文件名。 4.使用 ZwCreateFile 创建文件句柄。 5.查询文件信息,获取文件大小。 6.根据文件大小申请内存,并读取文件内容到内存中。 7.使用 ZwReadFile 读取文件内容。 8.读取完成后,使用 ZwClose 和 ZwFlushBuffersFile 关闭文件并释放内存。该视频主要讲述了完善APC注入的shell code的过程。首先,复制了之前编写的shell code,并强调了其稳定性和参数填写的必要性。接着,提到了在使用share code时需要注意关闭一些安全检查和防护流保护,以确保代码能够正常生成。然后,复制了manual mapping data和函数指针,并补充了缺少的nt image和重定位标志。最后,通过复制和修改代码,解决了hit memory和文件映射的问题,完成了shell code的完善工作。 分段总结 00:12 ShellCode编写与K_routine修改实验完成 1.完善apc注入的shell code,通过复制已有的shell code作为基础。 2.介绍修改K_routine的步骤,包括关闭安全检查和防护流保护等。 3.通过链接器设置增量链接,确保shell code的正确生成和注入。 4.复制必要的函数指针和图像文件,以支持shell code的执行。 5.通过重定位和标志复制,完成shell code的最终准备。 08:17 ShellCode注入与测试 1.介绍注入shell code的过程,包括手动映射数据和设置APC。 2.提供注入参数的设置方法,包括调用名、路径、PID等。 3.通过复制和修改内核实验中的hit memory代码,实现内存注入申请。 4.详细讲解shell code的执行流程,包括寄存器保存、堆栈对齐和重定位数据的传递。 5.测试注入的shell code,确保其能在目标系统中正确执行。 28:22 ShellCode稳定性与商用考虑 1.讨论shell code的稳定性,以及在商用环境中的应用考虑。 2.建议在使用shell code后及时卸载,以避免被检测到使用过期签名。 3.介绍在商用环境中,通过事件和单对象等待函数来确保注入的稳定性和安全性。1.实验目的:实现无驱动附加的读写功能,验证无需读写技术的可行性。 2.实验原理:通过修改内存指令,实现无驱动的读写操作。 3.实验环境:Windows操作系统,WinDbg调试工具。这个是无驱注入。你看看能不能无驱
最新发布
07-22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值