以管理员身份运行时,如何获取IEnumMoniker.Next返回别名?

时间:2019-04-02 03:19:51

标签: c# uac running-object-table

此代码在实用程序中可以正常运行多年。我们最近更新了该程序以实施UAC,但我们发现此代码仅在未以管理员身份运行时才有效;当以admin身份运行时,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为什么在提升的进程中运行时不返回任何名字对象,而在不以管理员身份运行时返回一个列表有何想法?

1 个答案:

答案 0 :(得分:0)

我在Microsoft开了张票。它升级了,我终于得到了答案:它按设计工作。这是相关的对话:

Microsoft支持:

  

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

我:

  

您能给我发送一个链接到此文档的链接吗?具有“提升的”特权应该使用户可以访问更多而不是更少的对象。您所描述的似乎类似于简单地以其他用户身份登录。

Microsoft支持:

  

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

我:

  

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

Microsoft支持:

  

因为那是产品组做出的设计决定。关于他们为什么要这么做的原因,我没有进一步的信息。

我:

  

这听起来像是我的错误,还是设计错误。有没有办法将其放在产品小组的雷达上?

Microsoft支持:

  

很遗憾,在这一方面没有任何改变。