If you use \\?\ for the prefix but use slash in the rest of the path, Windows will not translate the slash to backslash for you:Breakpoint 0 hitntdll!RtlDosPathNameToRelativeNtPathName_U_WithStatus:00007ff9`d1fb5880 4883ec58 sub rsp,58h0:000> du @rcx0000005b`c2ffbf30 "\\?\C:/Temp/test.txt"0:000> r rdxrdx=0000005bc0b3f0680:000> ptntdll!RtlDosPathNameToRelativeNtPathName_U_WithStatus+0x66:00007ff9`d1fb58e6 c3 ret0:000> dS 5bc0b3f0680000005b`c3066d30 "\??\C:/Temp/test.txt"正斜杠是 NT 命名空间中的有效对象名称字符.它由 Microsoft 文件系统保留,但您可以在其他命名内核对象中使用正斜杠,这些对象存储在 \BaseNamedObjects 或 \Sessions\[session number]\BaseNamedObjects 中.此外,我认为 I/O 管理器不会对设备和文件名中的保留字符执行策略.这取决于设备.也许有人在那里有一个 Windows 设备,它实现了一个允许名称中的正斜杠的命名空间.至少您可以创建包含正斜杠的 DOS 设备名称.例如:Forward slash is a valid object name character in the NT namespace. It's reserved by Microsoft filesystems, but you can use a forward slash in other named kernel objects, which get stored in \BaseNamedObjects or \Sessions\[session number]\BaseNamedObjects. Also, I don't think the I/O manager enforces the policy on reserved characters in device and filenames. It's up to the device. Maybe someone out there has a Windows device that implements a namespace that allows forward slash in names. At the very least you can create DOS device names that contain a forward slash. For example:>>> kernel32 = ctypes.WinDLL('kernel32')>>> kernel32.DefineDosDeviceW(0, u'My/Device', u'C:\\Temp')>>> os.path.exists(u'\\\\?\\My/Device\\test.txt')True您可能想知道 \?? 是什么意思.这曾经是对象命名空间中 DOS 设备链接的实际目录,但从 NT 5(或 NT 4 w/终端服务)开始,它变成了一个虚拟前缀.对象管理器通过首先检查 \Sessions\0\DosDevices\[LOGON_SESSION_ID] 目录中的登录会话的 DOS 设备链接,然后检查 目录中的系统范围的 DOS 设备链接来处理这个前缀.\Global?? 目录.You may be wondering what \?? signifies. This used to be an actual directory for DOS device links in the object namespace, but starting with NT 5 (or NT 4 w/ Terminal Services) this became a virtual prefix. The object manager handles this prefix by first checking the logon session's DOS device links in the directory \Sessions\0\DosDevices\[LOGON_SESSION_ID] and then checking the system-wide DOS device links in the \Global?? directory.请注意,前者是登录会话,而不是 Windows 会话.登录会话目录都在 Windows 会话 0(即 Vista+ 中的服务会话)的 DosDevices 目录下.因此,如果您有用于非提升登录的映射驱动器,您会发现它在提升的命令提示符中不可用,因为您提升的令牌实际上用于不同的登录会话.Note that the former is a logon session, not a Windows session. The logon session directories are all under the DosDevices directory of Windows session 0 (i.e. the services session in Vista+). Thus if you have a mapped drive for a non-elevated logon, you'll discover that it's not available in an elevated command prompt, because your elevated token is actually for a different logon session.DOS 设备链接的一个例子是 \Global??\C: => \Device\HarddiskVolume2.在这种情况下,DOS C: 驱动器实际上是到 HarddiskVolume2 设备的符号链接.An example of a DOS device link is \Global??\C: => \Device\HarddiskVolume2. In this case the DOS C: drive is actually a symbolic link to the HarddiskVolume2 device.这里简要概述了系统如何处理解析路径以打开文件.鉴于我们正在调用 WinAPI CreateFile,它将翻译后的 NT UNICODE_STRING 存储在 OBJECT_ATTRIBUTES 结构并调用系统函数NtCreateFile.Here's a brief overview of how the system handles parsing a path to open a file. Given we're calling WinAPI CreateFile, it stores the translated NT UNICODE_STRING in an OBJECT_ATTRIBUTES structure and calls the system function NtCreateFile.0:000> gBreakpoint 1 hitntdll!NtCreateFile:00007ff9`d2023d70 4c8bd1 mov r10,rcx0:000> !obja @r8Obja +000000b450f9ec58 at 000000b450f9ec58: Name is \??\C:\Temp\test.txt OBJ_CASE_INSENSITIVENtCreateFile 调用 I/O 管理器函数 IoCreateFile,它依次调用未记录的对象管理器 API ObOpenObjectByName.这完成了解析路径的工作.对象管理器以 \??\C:\Temp\test.txt 开头.然后它用 \Global??\C:Temp\test.txt 替换它.接下来,它解析到 C: 符号链接,并且必须重新开始(重新解析)最终路径 \Device\HarddiskVolume2\Temp\test.txt.NtCreateFile calls the I/O manager function IoCreateFile, which in turn calls the undocumented object manager API ObOpenObjectByName. This does the work of parsing the path. The object manager starts with \??\C:\Temp\test.txt. Then it replaces that with \Global??\C:Temp\test.txt. Next it parses up to the C: symbolic link and has to start over (reparse) the final path \Device\HarddiskVolume2\Temp\test.txt.一旦对象管理器获取到 HarddiskVolume2 设备对象,解析就交给 I/O 管理器,它实现了 Device 对象类型.I/O Device 的 ParseProcedure 创建 File 对象和 I/O 请求数据包 (IRP) 与 主要函数代码 IRP_MJ_CREATE(打开/创建操作)由设备堆栈处理.这通过 IoCallDriver 发送到设备驱动程序.如果设备实现了重解析点(例如连接挂载点、符号链接等)并且路径包含重解析点,则必须将解析的路径重新提交给对象管理器以从头开始解析.Once the object manager gets to the HarddiskVolume2 device object, parsing is handed off to the I/O manager, which implements the Device object type. The ParseProcedure of an I/O Device creates the File object and an I/O Request Packet (IRP) with the major function code IRP_MJ_CREATE (an open/create operation) to be processed by the device stack. This is sent to the device driver via IoCallDriver. If the device implements reparse points (e.g. junction mountpoints, symbolic links, etc) and the path contains a reparse point, then the resolved path has to be resubmitted to the object manager to be parsed from the start.设备驱动程序将使用进程令牌(或模拟线程)的 SeChangeNotifyPrivilege(几乎总是存在并启用)在遍历目录时绕过访问检查.但是,最终访问设备和目标文件必须由安全描述符允许,通过 SeAccessCheck.除了简单的文件系统如 FAT32 不支持文件安全.The device driver will use the SeChangeNotifyPrivilege (almost always present and enabled) of the process token (or thread if impersonating) to bypass access checks while traversing directories. However, ultimately access to the device and target file has to be allowed by a security descriptor, which is verified via SeAccessCheck. Except simple filesystems such as FAT32 don't support file security. 这篇关于路径名太长打不开?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
07-18 09:48
查看更多