C#获取令牌组SID字符串失败:Win11+Office365下ERROR_INVALID_SID问题
一段作为MS Access VBA COM组件使用多年的C#代码,在升级至Windows 11和Office 365后出现异常:调用IsValidSid返回false,ConvertSidToStringSid返回null,Marshal.GetLastWin32Error返回错误码1337(ERROR_INVALID_SID,安全ID结构无效)。但将代码编译为.exe运行时一切正常。已尝试x64、x86、Any CPU编译,以及改用ConvertSidToStringSidA,问题仍未解决。
日志片段
12:20: CheckForTokenGroup - InTokenInfo 12:20: CheckForTokenGroup - IsValidSid=False: 0 12:20: CheckForTokenGroup - error: 1337 12:20: CheckForTokenGroup - sidAsString:
相关代码
枚举与结构体定义
enum TOKEN_INFORMATION_CLASS { TokenUser = 1, TokenGroups, TokenPrivileges, TokenOwner, TokenPrimaryGroup, TokenDefaultDacl, TokenSource, TokenType, TokenImpersonationLevel, TokenStatistics, TokenRestrictedSids, TokenSessionId, TokenGroupsAndPrivileges, TokenSessionReference, TokenSandBoxInert, TokenAuditPolicy, TokenOrigin } [StructLayout(LayoutKind.Sequential)] public struct SID_AND_ATTRIBUTES { public IntPtr Sid; public UInt32 Attributes; } [StructLayout(LayoutKind.Sequential)] public struct TOKEN_GROUPS { public UInt32 GroupCount; // Followed by this: [MarshalAs(UnmanagedType.ByValArray)] public SID_AND_ATTRIBUTES[] Groups; }
Win32 API导入
[DllImport("advapi32.dll", SetLastError = true)] static extern int GetTokenInformation(IntPtr tokenHandle, TOKEN_INFORMATION_CLASS tokenInformationClass, IntPtr tokenInformation, int tokenInformationLength, ref int returnLength); const int GetTokenInformationFail = 0; [DllImport("advapi32.dll")] private static extern bool IsValidSid(IntPtr pSid); [DllImport("advapi32", CharSet = CharSet.Auto, SetLastError = true)] static extern bool ConvertSidToStringSid(IntPtr securityIdentifier, out string securityIdentifierName);
核心业务代码
var tokenInfo = Marshal.AllocHGlobal(length); if (GetTokenInformation(tokenHandler, TOKEN_INFORMATION_CLASS.TokenGroups, tokenInfo, length, ref length) != GetTokenInformationFail) { logText += AddLogText("CheckForTokenGroup - InTokenInfo"); int groupCount = Marshal.ReadInt32(tokenInfo); const int sizeDword = 4; var groupInfoAsPointer = tokenInfo + sizeDword; for (int i = 0; i < groupCount; i++) { var groupInfo = (SID_AND_ATTRIBUTES)Marshal.PtrToStructure((IntPtr)groupInfoAsPointer, typeof(SID_AND_ATTRIBUTES)); string sidAsString = string.Empty; if (!IsValidSid(groupInfo.Sid)) { int errorCode = Marshal.GetLastWin32Error(); logText += AddLogText("CheckForTokenGroup - IsValidSid=False: " + errorCode); } if (!ConvertSidToStringSid(groupInfo.Sid, out sidAsString)) { int errorCode = Marshal.GetLastWin32Error(); logText += AddLogText("CheckForTokenGroup - error: " + errorCode); } logText += AddLogText("CheckForTokenGroup - sidAsString: " + sidAsString); if (sidAsString == tokenGroupName) { Marshal.FreeHGlobal(tokenInfo); return true; } groupInfoAsPointer += Marshal.SizeOf(typeof(SID_AND_ATTRIBUTES)); } } else { logText += AddLogText("CheckForTokenGroup - Exception"); Marshal.FreeHGlobal(tokenInfo); throw new GetTokenInformationFailedException(Marshal.GetLastWin32Error()); }
修复结构体与指针计算逻辑
TOKEN_GROUPS结构体中的数组定义无法被Marshal正确解析,需移除数组声明,改为手动通过指针偏移遍历分组。同时,指针偏移需使用Marshal.SizeOf(typeof(UInt32))替代固定的4字节,适配64位环境:[StructLayout(LayoutKind.Sequential)] public struct TOKEN_GROUPS { public UInt32 GroupCount; } // 修改指针初始化代码 var groupInfoAsPointer = IntPtr.Add(tokenInfo, Marshal.SizeOf(typeof(UInt32)));修正
IsValidSid的错误码获取
给IsValidSid的DllImport添加SetLastError = true,确保能获取到正确的错误码:[DllImport("advapi32.dll", SetLastError = true)] private static extern bool IsValidSid(IntPtr pSid);严格匹配Office位数编译
Office 365默认64位,若Access运行在64位模式,COM组件必须编译为x64;若Access是32位,则组件必须编译为x86,禁止使用Any CPU,避免位数不匹配导致指针解析错乱。验证令牌上下文权限
Office 365在Windows 11下的COM运行上下文可能受限,需确保获取的令牌是当前用户的有效令牌,打开令牌时指定TokenAccessLevels.Query权限:// 示例:获取当前进程令牌 if (!OpenProcessToken(Process.GetCurrentProcess().Handle, TokenAccessLevels.Query, out IntPtr tokenHandler)) { // 处理令牌获取失败逻辑 }
内容的提问来源于stack exchange,提问作者Gener4tor

