我不太确定,所以我很愿意接受评论,但我猜:
ReadFileEx
实现使用NtReadFile
(或多或少它只是围绕它的一个薄包装)。NtReadFile
做了很多事情,但它使用IoBuildAsynchronousFsdRequest
(或IoBuildSynchronousFsdRequest
)来执行它的任务。从这篇文章我们知道:
如果目标设备对象设置为直接 i/o (DO_DIRECT_IO),则 IoBuildAsynchronousFsdRequest 创建一个 MDL 来描述缓冲区并锁定页面。
(重点是我的)
然后我猜他们MmProbeAndLockPages
用调用IoWriteAccess
,这是由内核模式下的驱动程序完成的,然后用户提供的缓冲区(在用户模式下)甚至无法访问以进行读取。
我不知道如果你这样做会发生什么,可能会抛出一个 SEH 异常并且你的代码会失败。
编辑
正如已编辑问题中所指出的那样,即使该ReadFile
函数也禁止用户从缓冲区中读取,直到操作完成并且它可能会返回ERROR_NOT_ENOUGH_QUOTA
:
ReadFile 函数可能会因 ERROR_NOT_ENOUGH_QUOTA 而失败,这意味着调用进程的缓冲区无法被页面锁定。
至少这清楚地表明ReadFile
(缓冲区不是由用户提供的)将分配一个页面并将其锁定(好的,我在链接的文章中也说过......)。用户定义的缓冲区是否也会发生损坏(如果有的话,我非常同意@David),还有待了解(如@Ben 所指出的,页面上的锁定在大多数情况下是不可能的)。
我不认为它使用页面错误来检测缓冲区溢出仅仅是因为它在调用之前知道所需的数据量然后它可以分配一次。
那么为什么数据会被破坏呢?
毕竟这里的一切都可能是由于错误而不是数据损坏。这是一个很大的猜测,但有一个已知问题MmProbeAndLockPages
:
由于内存管理器中的争用条件,会出现此问题。当驱动程序调用 MmProbeAndLockPages 例程时,此例程可能会读取一些正在被另一个线程修改的数据。因此,会发生数据损坏。根据损坏数据的使用方式,应用程序或系统可能会崩溃。
很难说这个问题是否已经在非常低的水平上得到解决,或者如果应用程序做了一些奇怪的事情是否仍然可以利用......