现象及原因
像 ReadFile 和 ReadProcessMemory 这种需要缓冲区,并且通过 SysEnter 指令进入内核的,
在内核中向指定的缓冲区写入数据,使用硬件断点和内存断点设置内存写入断点是无效的。
主要是因为 Ring3
调试器无法接收内核中产生的异常。内核中产生的异常会被内核异常处理器处理,并以 API 的返回值作为错误码返回
#include <windows.h>
#include <iostream>
#include <string>
#include <vector>
#include <thread>
#include <atomic>void readFileWithReadFileEx(const std::string& fileName,char * fileBuffer) {HANDLE hFile = CreateFileA(fileName.c_str(),GENERIC_READ,FILE_SHARE_READ,nullptr,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,nullptr);if (hFile == INVALID_HANDLE_VALUE) {std::cerr << "无法打开文件: " << fileName << ", 错误码: " << GetLastError() << std::endl;return;}LARGE_INTEGER fileSize;if (!GetFileSizeEx(hFile, &fileSize)) {std::cerr << "获取文件大小失败, 错误码: " << GetLastError() << std::endl;CloseHandle(hFile);return;}OVERLAPPED overlapped = {};if (!ReadFileEx(hFile,fileBuffer,0x1000,&overlapped,0)) {std::cerr << "异步读取失败, 错误码: " << GetLastError() << std::endl;CloseHandle(hFile);return;}CloseHandle(hFile);
}int main() {std::string fileName = R"(D:\learn\kanxue.vmp\checkVM\ConsoleApplication5\example.txt)"; // 替换为你的文件名char fileBuffer[0x1000] = { 0, }; // 存储文件内容readFileWithReadFileEx(fileName, fileBuffer);// 打印文件内容std::cout << "文件内容:\n" << fileBuffer << std::endl;return 0;
}
在 fileBuffer
下硬件写入断点和内存写入断点是无法中断的。硬件写入断点会被内核忽略,而内存写入断点会造成 ReadFileEx
失败,返回错误码
微软官方的说明
数据断点在下列情况下无效:
- 将未经调试的进程写入内存位置。
- 在两个或多个进程间共享内存位置。
- 内存位置在内核内更新。例如,如果内存传递给 32 位 Windows ReadFile 函数,则内存将从内核模式进行更新,因此调试器不会在更新时中断。
- 其中,监视表达式在 32 位硬件上大于 4 字节,在 64 位硬件上大于 8 字节。这是 x 86 体系结构的一个限制。