2

多年来,此代码在实用程序中运行良好。我们最近更新了程序以强制执行 UAC,但我们发现此代码仅在不以管理员身份运行时才有效;当以管理员身份运行时,while 循环内的代码永远不会执行,但相同的代码在未提升运行时返回一个名字对象名称列表。

using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;

namespace ROTExplorer
{
    class Program
    {
    [DllImport("ole32.dll")]
    static extern int GetRunningObjectTable(uint reserved, out IRunningObjectTable rot);

    [DllImport("Ole32.Dll")]
    static extern int CreateBindCtx(int reserved, out IBindCtx bindCtx);

    static void Main(string[] args)
    {
        FindEntryInROT();
        Console.WriteLine("Press any key to continue.");
        Console.ReadKey();
    }

    private static string FindEntryInROT()
    {
        IRunningObjectTable rot = null;
        IBindCtx bindCtx = null;
        IEnumMoniker enumMoniker = null;
        IMoniker[] monikers = new IMoniker[1];
        string displayName = null;
        try
        {
            GetRunningObjectTable(0, out rot);
            CreateBindCtx(0, out bindCtx);
            rot.EnumRunning(out enumMoniker);
            IntPtr fetched = IntPtr.Zero;
            while (enumMoniker.Next(1, monikers, fetched) == 0)
            {
                string tempName;
                monikers[0].GetDisplayName(bindCtx, null, out tempName);
                Marshal.ReleaseComObject(monikers[0]);
                monikers[0] = null;
                try
                {
                    Console.WriteLine(tempName);
                }
                catch
                {
                    Console.WriteLine("Bad string");
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Failure while examining ROT: " + ex.Message);
        }
        finally
        {
            ReleaseCOMObject(monikers[0]);
            ReleaseCOMObject(enumMoniker);
            ReleaseCOMObject(bindCtx);
            ReleaseCOMObject(rot);
        }
        Console.WriteLine(displayName);
        return displayName;
    }

    private static void ReleaseCOMObject(object comObject)
    {
        if (comObject != null)
        {
            Marshal.ReleaseComObject(comObject);
            comObject = null;
        }
    }

}

我已经在 2 台机器上试过了。其他人可以试试这个并确认此代码仅在不以管理员身份运行时返回名字对象列表。

是否有人对为什么 IEnumMoniker 在提升的进程中运行时不返回名字对象但在不以管理员身份运行时返回列表有任何想法?

4

1 回答 1

3

我向微软开了一张票。它被升级了,我终于得到了答案:它按设计工作。以下是相关对话:

微软支持:

SCM/RPCSS 服务是运行对象表所在的位置。枚举表时,服务会进行多次检查。其中一项检查是专门将客户端令牌的提升级别与令牌条目的提升级别相匹配。如果不匹配,则不会返回条目。您看到的行为是设计使然。

我:

你能给我一个链接到哪里记录这个吗?拥有“提升”的权限应该让用户可以访问更多的对象,而不是更少。您所描述的似乎类似于简单地以其他用户身份登录。

微软支持:

它没有直接记录在案。
在某些方面,您的最后陈述是正确的。管理员用户有两个安全令牌,一个用于正常操作,一个用于提升。它们从不同时使用。https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/how-user-account-control-works 当管理员登录时,会为用户:标准用户访问令牌和管理员访问令牌。标准用户访问令牌包含与管理员访问令牌相同的用户特定信息,但删除了管理 Windows 权限和 SID。我相信所有这一切背后的原因都与安全相关,但我无法很好地解释这一点。

我:

管理员令牌可以访问标准用户的文件;为什么用户的 COM 对象与用户的文件对象不同?

微软支持:

因为这是产品组做出的设计决定。我没有进一步的信息来说明他们为什么会这样。

我:

对我来说,这听起来真的像是一个错误,或者是一个错误的设计。有没有办法把它放在产品组的雷达上?

微软支持:

不幸的是,在这方面没有任何改变的筹码。

于 2019-04-24T22:19:04.400 回答