WoW64环境下NtQuerySystemInformation的SystemSessionProcessInformation接口是否异常?
WoW64环境下NtQuerySystemInformation获取SystemSessionProcessInformation时ReturnLength始终为0的问题
问题背景
我通过NtQuerySystemInformation接口获取三类系统信息:SystemProcessInformation、SystemExtendedProcessInformation和SystemSessionProcessInformation。常规循环逻辑(检查STATUS_INFO_LENGTH_MISMATCH状态,根据ReturnLength返回值调整缓冲大小)在前两类信息的获取中运行正常,但针对SystemSessionProcessInformation时出现异常:
- 该信息需通过
SYSTEM_SESSION_PROCESS_INFORMATION结构的二级缓冲获取数据,微调后的逻辑在原生架构(32位进程运行在32位系统、64位进程运行在64位系统)下可正常工作; - 在WoW64环境(32位进程运行在64位系统)中,当返回
STATUS_INFO_LENGTH_MISMATCH时,ReturnLength始终为0,导致常规的缓冲调整逻辑失效,只能通过持续增大缓冲大小直至函数返回STATUS_SUCCESS或非STATUS_INFO_LENGTH_MISMATCH状态。
想确认这是微软WoW64层的兼容性疏漏,还是我对接口的理解存在误区?
可复现代码
SYSTEM_SESSION_PROCESS_INFORMATION SessionInfo = { 0 }; SessionInfo.SessionId = 1; NTSTATUS Status = STATUS_SUCCESS; PVOID Info = NULL; ULONG InfoLength = 0; for (;;) { Status = NtQuerySystemInformation(SystemSessionProcessInformation, &SessionInfo, sizeof(SessionInfo), &InfoLength); if (Status != STATUS_INFO_LENGTH_MISMATCH) { break; } // NOTE: InfoLength is always 0 here // only workaround is to continually increase buffer size and try again // e.g. InfoLength += 0x1000 SessionInfo.Buffer = malloc(InfoLength); SessionInfo.SizeOfBuf = InfoLength; }
原因分析
这属于WoW64层的兼容性疏漏,并非你的理解错误。
核心原因在于:SystemSessionProcessInformation这类依赖二级缓冲的信息类型,WoW64层在处理STATUS_INFO_LENGTH_MISMATCH返回时,没有正确将64位系统侧计算出的所需缓冲长度回传给32位进程的ReturnLength参数。而SystemProcessInformation、SystemExtendedProcessInformation这类直接返回单缓冲数据的信息类型,WoW64层的长度回传逻辑是正常的。
解决方案
既然无法依赖ReturnLength获取准确的所需缓冲大小,只能采用逐步扩容重试的方案:
- 初始设置一个合理的缓冲大小(如0x1000字节);
- 每次遇到
STATUS_INFO_LENGTH_MISMATCH时,按固定增量(如0x1000或0x4000字节)增大缓冲; - 循环直到函数返回
STATUS_SUCCESS或非STATUS_INFO_LENGTH_MISMATCH的错误状态; - 注意在循环中释放之前分配的旧缓冲,避免内存泄漏。
调整后的示例代码:
SYSTEM_SESSION_PROCESS_INFORMATION SessionInfo = { 0 }; SessionInfo.SessionId = 1; NTSTATUS Status = STATUS_SUCCESS; ULONG InfoLength = 0x1000; // 初始缓冲大小 PVOID OldBuffer = NULL; for (;;) { // 释放上一次分配的旧缓冲 if (OldBuffer != NULL) { free(OldBuffer); OldBuffer = NULL; } SessionInfo.Buffer = malloc(InfoLength); SessionInfo.SizeOfBuf = InfoLength; OldBuffer = SessionInfo.Buffer; Status = NtQuerySystemInformation(SystemSessionProcessInformation, &SessionInfo, sizeof(SessionInfo), &InfoLength); if (Status != STATUS_INFO_LENGTH_MISMATCH) { break; } // 按固定增量扩容,可根据实际场景调整大小 InfoLength += 0x1000; } // 使用完毕后释放缓冲 if (SessionInfo.Buffer != NULL) { free(SessionInfo.Buffer); }
内容的提问来源于stack exchange,提问作者Luke
相关产品推荐
相关产品推荐

