You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 01:12:06