必须添加 FILE_FLAG_BACKUP_SEMANTICS 标志并启用 SE_BACKUP_NAME 特权才能用 CreateFile 打开系统隐藏文件,否则返回 ERROR_ACCESS_DENIED;还需确保缓冲区 512 字节对齐、正确处理句柄类型及共享模式。

用 CreateFile 打开系统隐藏文件必须加 FILE_FLAG_BACKUP_SEMANTICS
Windows 下,系统隐藏文件(比如卷影副本、USN 日志、某些备份元数据)默认被 CreateFile 拒绝访问,报错 ERROR_ACCESS_DENIED。这不是权限问题,而是内核对“非普通文件语义”的保护机制。绕过它的唯一合法方式,就是在调用 CreateFile 时显式传入 FILE_FLAG_BACKUP_SEMANTICS 标志——它告诉系统:“我要以备份/恢复上下文访问这个句柄”,从而绕过常规 ACL 和属性检查。
注意:这个标志本身不赋予任何权限,它只是切换访问语义;你仍需确保进程有 SE_BACKUP_NAME 或 SE_RESTORE_NAME 特权(通常管理员进程默认持有),否则依然失败。
-
FILE_FLAG_BACKUP_SEMANTICS必须和GENERIC_READ(或GENERIC_WRITE)一起用,单独加没意义 - 不能和
FILE_ATTRIBUTE_NORMAL冲突——打开前别自己清除文件的FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN - 该标志会让
CreateFile允许打开目录(即使没指定FILE_FLAG_OPEN_REPARSE_POINT),所以后续操作前务必用GetFileType或GetFileInformationByHandle确认类型
OpenProcessToken + AdjustTokenPrivileges 是启用备份特权的必要步骤
哪怕你是管理员,SE_BACKUP_NAME 特权默认是“禁用”状态,不显式启用就等于没有。跳过这步,CreateFile 会静默失败(返回 INVALID_HANDLE_VALUE,GetLastError() 是 ERROR_PRIVILEGE_NOT_HELD)。
- 先用
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)获取当前进程令牌 - 再调用
LookupPrivilegeValue(NULL, SE_BACKUP_NAME, &luid)获取特权 LUID - 构造
TOKEN_PRIVILEGES结构,把Attributes设为SE_PRIVILEGE_ENABLED,再传给AdjustTokenPrivileges - 别忽略
AdjustTokenPrivileges的返回值——它可能成功但部分特权未生效(比如没权限启 SE_RESTORE_NAME),要用GetLastError()判断
读取内容本身和普通文件没区别,但要注意句柄类型和缓冲区对齐
拿到有效句柄后,ReadFile 行为完全一致。真正容易出错的是前置判断和内存准备:
立即学习“C++免费学习笔记(深入)”;
- 用
GetFileType(hFile)区分是FILE_TYPE_DISK还是FILE_TYPE_UNKNOWN(后者可能是命名管道或设备,不能直接ReadFile) - 某些系统隐藏文件(如
System Volume Information下的{3808876b-c176-4e48-b3ae-41006a62f5c4})要求读取缓冲区地址按 512 字节对齐,否则ReadFile返回ERROR_INVALID_PARAMETER;可用_aligned_malloc(size, 512)分配 - 不要假设文件大小可查:
GetFileSize对很多系统文件返回INVALID_FILE_SIZE,且GetFileInformationByHandle的nFileSizeHigh/Low可能全零——得靠实际读取循环 +GetLastError() == ERROR_HANDLE_EOF判定结束
常见错误现象和对应检查点
遇到打不开、读不出、崩掉,优先按顺序核对这几项:
-
ERROR_ACCESS_DENIED→ 检查是否漏了FILE_FLAG_BACKUP_SEMANTICS,或AdjustTokenPrivileges调用失败/未启用SE_BACKUP_NAME -
ERROR_INVALID_PARAMETER(ReadFile)→ 检查缓冲区地址是否对齐(尤其读取 USN 日志或卷影副本时),以及lpNumberOfBytesRead是否非空指针 -
ERROR_SHARING_VIOLATION→ 系统隐藏文件常被卷影复制服务独占打开,尝试加FILE_SHARE_READ | FILE_SHARE_WRITE,但成功率取决于具体文件用途 - 读出来全是零或乱码 → 很可能句柄其实是目录(
GetFileType返回FILE_TYPE_DIRECTORY),却当成文件读了
系统隐藏文件的访问边界很模糊:有些能读,有些只能由特定驱动访问,有些路径本身就需要 \? 前缀绕过路径解析限制。别指望一个开关解决所有问题,每次换目标文件都得重新验证语义、特权、对齐、共享模式这四层。



















