NtQueryDirectoryFile在Windows触发访问违例但Wine正常的问题排查
问题分析
你遇到的核心问题是调用NtQueryDirectoryFile时R10寄存器被设为0,该寄存器在Windows x64系统调用中用于承载第一个参数(FileHandle)的副本。R10值取自TEB的保留区域gs:[0x188],说明代码大概率存在参数传递错误、调用约定不匹配或非法访问TEB的问题。
可能的原因及解决方法
函数调用约定错误
NtQueryDirectoryFile是ntdll导出的系统调用包装函数,必须使用NTAPI调用约定(x64下对应fastcall,参数依次通过RCX、RDX、R8、R9传递,剩余参数入栈)。若函数声明未使用NTAPI,会导致寄存器传递混乱。
正确的函数原型声明:typedef NTSTATUS (NTAPI *NtQueryDirectoryFilePtr)( HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID FileInformation, ULONG Length, FILE_INFORMATION_CLASS FileInformationClass, BOOLEAN ReturnSingleEntry, PUNICODE_STRING FileName, BOOLEAN RestartScan );非法访问TEB保留区域
若代码存在直接读取gs:[0x188]的逻辑,必须立即移除。Wine与Windows的TEB结构差异极大,Git的实现针对Wine设计,Windows下TEB的保留区域不允许用户态访问,强行读取会导致寄存器值异常。目录句柄无效
确认通过NtCreateFile打开目录时,已正确设置权限和选项:- 必须指定
FILE_LIST_DIRECTORY权限 - 打开选项需包含
FILE_DIRECTORY_FILE
如果句柄为0,系统调用时R10会被设为0,直接触发访问违例。
- 必须指定
缓冲区对齐与大小问题
虽然你尝试过LONGLONG对齐,但Windows部分文件信息结构(如FILE_FULL_DIR_INFORMATION)要求16字节对齐。建议使用_aligned_malloc分配缓冲区:PVOID buffer = _aligned_malloc(buffer_size, 16); // 使用后释放 _aligned_free(buffer);同时确保缓冲区大小足够容纳至少一个完整的文件信息条目,避免溢出导致的内存异常。
函数地址获取错误
确认通过GetProcAddress从ntdll.dll获取的函数地址正确:HMODULE ntdll = GetModuleHandleW(L"ntdll.dll"); NtQueryDirectoryFilePtr NtQueryDirectoryFile = (NtQueryDirectoryFilePtr)GetProcAddress(ntdll, "NtQueryDirectoryFile");若获取失败,会导致调用无效地址,引发访问违例。
调试建议
在Visual Studio中设置断点,在调用NtQueryDirectoryFile前检查:
- RCX寄存器的值(对应FileHandle)是否为有效句柄
- 所有参数的内存地址是否合法、对齐正确
- 函数指针本身是否指向ntdll中的有效地址
内容的提问来源于stack exchange,提问作者user23724043

