托管到非托管代码调用有时会导致访问冲突...

发布于 2024-09-11 15:39:28 字数 3356 浏览 2 评论 0原文

此代码有时会导致以下异常:

“试图读或写受保护的 记忆。这通常是一个迹象 其他内存已损坏”

private static TOKEN_GROUPS GetTokenGroups(IntPtr tokenHandle)
{
    var groups = new TOKEN_GROUPS();
    uint tokenInfoLength = 0;
    uint returnLength;

    var res = GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenGroups, IntPtr.Zero,
                                  tokenInfoLength, out returnLength);

    if (!res && returnLength > 0)
    {
        tokenInfoLength = returnLength;
        var tokenInfo = Marshal.AllocHGlobal((int) tokenInfoLength);
        res = GetTokenInformation(tokenHandle,
                                  TOKEN_INFORMATION_CLASS.TokenGroups,
                                  tokenInfo,
                                  tokenInfoLength,
                                  out returnLength);
        if(res)
        {
            groups = (TOKEN_GROUPS)Marshal.PtrToStructure(tokenInfo, typeof (TOKEN_GROUPS));
        }

        Marshal.FreeHGlobal(tokenInfo);
        CloseHandle(tokenHandle);
    }
    else
    {
        var error = new Win32Exception(Marshal.GetLastWin32Error());
        _log.WarnFormat("Failed evaluate the call to get process token information. {0}", error.Message);
    }
    return groups;
}

失败的行是 groups = (TOKEN_GROUPS)Marshal.PtrToStructure(tokenInfo, typeof (TOKEN_GROUPS)); 我想说异常发生在 1 中,并且每 20 次调用此方法一旦开始发生,之后的每个调用都会引发异常,

IntPtr tokenHandle 的结果是:

var processId = GetCurrentProcess();

            _log.InfoFormat("Process ID [{0}]", processId.ToString());

            if (processId != IntPtr.Zero)
            {
                IntPtr tokenHandle;
                if (OpenProcessToken(processId, TOKEN_READ, out tokenHandle))
                {
                    groups = GetTokenGroups(tokenHandle);
                }

编辑希望这不是。信息过载,但这是 pinvoke 声明:

     struct TOKEN_GROUPS
    {
        public uint GroupCount;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4000)]
        public SID_AND_ATTRIBUTES[] Groups;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct SID_AND_ATTRIBUTES
    {
        public IntPtr SID;
        public uint Attributes;
    }

    [DllImport("advapi32.dll", SetLastError = true)]
    static extern bool GetTokenInformation(
        IntPtr TokenHandle,
        TOKEN_INFORMATION_CLASS TokenInformationClass,
        IntPtr TokenInformation,
        uint TokenInformationLength,
        out uint ReturnLength);

    [DllImport("advapi32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool OpenProcessToken(IntPtr ProcessHandle,
        UInt32 DesiredAccess, out IntPtr TokenHandle);

    [DllImport("kernel32.dll")]
    static extern IntPtr GetCurrentProcess();

    enum TOKEN_INFORMATION_CLASS
    {
        TokenUser = 1,
        TokenGroups,
        TokenPrivileges,
        TokenOwner,
        TokenPrimaryGroup,
        TokenDefaultDacl,
        TokenSource,
        TokenType,
        TokenImpersonationLevel,
        TokenStatistics,
        TokenRestrictedSids,
        TokenSessionId,
        TokenGroupsAndPrivileges,
        TokenSessionReference,
        TokenSandBoxInert,
        TokenAuditPolicy,
        TokenOrigin
    }

This code causes the following exception, sometimes:

"Attempted to read or write protected
memory. This is often an indication
that other memory is corrupt"

private static TOKEN_GROUPS GetTokenGroups(IntPtr tokenHandle)
{
    var groups = new TOKEN_GROUPS();
    uint tokenInfoLength = 0;
    uint returnLength;

    var res = GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenGroups, IntPtr.Zero,
                                  tokenInfoLength, out returnLength);

    if (!res && returnLength > 0)
    {
        tokenInfoLength = returnLength;
        var tokenInfo = Marshal.AllocHGlobal((int) tokenInfoLength);
        res = GetTokenInformation(tokenHandle,
                                  TOKEN_INFORMATION_CLASS.TokenGroups,
                                  tokenInfo,
                                  tokenInfoLength,
                                  out returnLength);
        if(res)
        {
            groups = (TOKEN_GROUPS)Marshal.PtrToStructure(tokenInfo, typeof (TOKEN_GROUPS));
        }

        Marshal.FreeHGlobal(tokenInfo);
        CloseHandle(tokenHandle);
    }
    else
    {
        var error = new Win32Exception(Marshal.GetLastWin32Error());
        _log.WarnFormat("Failed evaluate the call to get process token information. {0}", error.Message);
    }
    return groups;
}

The line that fails is groups = (TOKEN_GROUPS)Marshal.PtrToStructure(tokenInfo, typeof (TOKEN_GROUPS)); I would say the exception happens in 1 and every 20 calls to this method. Once it begins happening every call afterwards will throw the exception. Restarting the process causes the error to go away.

IntPtr tokenHandle is the result of:

var processId = GetCurrentProcess();

            _log.InfoFormat("Process ID [{0}]", processId.ToString());

            if (processId != IntPtr.Zero)
            {
                IntPtr tokenHandle;
                if (OpenProcessToken(processId, TOKEN_READ, out tokenHandle))
                {
                    groups = GetTokenGroups(tokenHandle);
                }

EDIT Hopefully this isn't information overload but here's the pinvoke declarations:

     struct TOKEN_GROUPS
    {
        public uint GroupCount;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4000)]
        public SID_AND_ATTRIBUTES[] Groups;
    }

    [StructLayout(LayoutKind.Sequential)]
    struct SID_AND_ATTRIBUTES
    {
        public IntPtr SID;
        public uint Attributes;
    }

    [DllImport("advapi32.dll", SetLastError = true)]
    static extern bool GetTokenInformation(
        IntPtr TokenHandle,
        TOKEN_INFORMATION_CLASS TokenInformationClass,
        IntPtr TokenInformation,
        uint TokenInformationLength,
        out uint ReturnLength);

    [DllImport("advapi32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool OpenProcessToken(IntPtr ProcessHandle,
        UInt32 DesiredAccess, out IntPtr TokenHandle);

    [DllImport("kernel32.dll")]
    static extern IntPtr GetCurrentProcess();

    enum TOKEN_INFORMATION_CLASS
    {
        TokenUser = 1,
        TokenGroups,
        TokenPrivileges,
        TokenOwner,
        TokenPrimaryGroup,
        TokenDefaultDacl,
        TokenSource,
        TokenType,
        TokenImpersonationLevel,
        TokenStatistics,
        TokenRestrictedSids,
        TokenSessionId,
        TokenGroupsAndPrivileges,
        TokenSessionReference,
        TokenSandBoxInert,
        TokenAuditPolicy,
        TokenOrigin
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

烟─花易冷 2024-09-18 15:39:29

我的猜测是,该错误是由于未正确释放资源造成的,就像您的情况一样。我的原因可能是错误的,但包装 FreeHGlobalCloseHandle 位于 finally 中,以确保正确清理。

如果错误仍然存​​在,则可能是其他原因(结构错误或 数据布局错误声明TOKEN_GROUPS的LayoutKind错误?)或者错误地使用了这个特定的 API(我不太熟悉)。

编辑(编辑后)

问题很可能出在必要的 SizeConst 属性参数上。请考虑以下情况:GetTokenInformation 已给出 tokeInfoLength 中返回的大小。你分配这个。此大小可能不等于 SizeConst 值。如果 SizeConst 大于所需的大小,Marshal.PtrToStructure 将进一步访问您分配的长度,因为它只知道 SizeConst,这个内存可能是可访问的,也可能是不可访问的。

要解决此问题,请确保 AllocHGlobal 调用至少为编组的整个结构的大小。例如,尝试添加 4000 并查看错误是否返回(存在其他更简洁的解决方案,但让我们暂时保持简单)。

My guess is that the error is a result of not correctly freeing up resources, as is the case in your situation. I may be wrong in it being the cause, but it's probably a good idea to wrap the FreeHGlobal and CloseHandle in a finally block, to ensure proper cleaning up.

If the error then persists, it might be something else (wrong structure or wrong data layout in the declaration or wrong LayoutKind for TOKEN_GROUPS?) or wrong use of this particular API (which I'm not too familiar with).

Edit (after your edit)

The problem may very well lay in the necessary SizeConst attribute parameter. Consider the following: the GetTokenInformation has given the size returned in tokeInfoLength. You allocate this. This size is not likely equal to the SizeConst value. If SizeConst is larger than the required size, the Marshal.PtrToStructure will access further then the length that you allocated, because it knows only SizeConst, and this memory may be accessible, and may be not.

To resolve this issue, make sure that the AllocHGlobal call is at least the size of the whole structure as marshalled. Try, for instance, to add 4000 and see if the error returns (other, neater solutions exist, but let's keep it simple for a moment).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文