UAC関連設定とログインユーザー、起動方法により、起動したアプリの権限がどうなるか実験

もくじ
https://tera1707.com/entry/2022/02/06/144447

やりたいこと

アプリが管理者として起動しているかどうかを見て何かするような処理を実装したときに、 WindowsUAC(User Account Control。ユーザーアカウント制御)についての理解が足りないためにバグを入れたことがあった。

この際、WindowsUACを有効/無効すると、どういう動きをするのか、起動したアプリに、管理者権限がつくのか、つかないのか、実験/確認したい。

前提

実験には、下記の環境を使用した。

  • Windows10 home
  • 21H2

UACの設定

Windowsで、UAC関連の設定は下記で行う。

UAC 有効/無効

レジストリHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Systemキーの、 EnableLUAが、

  • 0:無効
  • 1:有効

になる。

ユーザーアカウント制御の設定

windowsの設定画面を開き、検索窓に「UAC」と入れると出てくる「ユーザーアカウント制御設定の変更」を押して出てくる下記画面で設定する。

この設定は、UACの有効無効を切り替えるものではなく、あくまでUACの通知のレベルを切り替えるもの。 スライダを一番下にしたからと言って、UACは無効にならない。有効無効は、上のレジストリでのみ切り替える。

※少なくとも試したWin10 21H2では。

但し、レジストリEnableLUAを0にしてUACを無効にすると、こちらのスライダは、自動で4(通知しない)になる。

UAC関連設定とログインユーザー、起動方法により、起動したアプリの権限がどうなるか

結論、下記のようになった。
(「GetTokenInformationの値」は、あとでそれを取れるサンプルコードを書く)

https://github.com/tera1707/Siryou/blob/master/UAC%E5%AE%9F%E9%A8%93.xlsx

  • UACを無効にしていると、ログイン中に起動させたアプリは、ユーザーの権限と同じ権限を持って、起動する。
    • 管理者ユーザーだと、管理者権限で起動して、管理者特権は「はい」になる
    • 一般ユーザーだと、一般権限で起動して、管理者特権は「いいえ」になる
  • GetTokenInformation関数の戻り値は、
    • UAC無効だと「TokenElevationTypeDefault」固定になる。
    • UAC有効だと、表のようになる。
      • 管理者ユーザーで通常起動すると、一般権限でアプリ起動し「TokenElevationTypeLimited」になる。(本当は管理者権限で起動するけど、UACのせいで「制限」がかかってる、という意味合いか)
      • 一般ユーザーで通常起動すると、「Default」になる。(一般ユーザーで普通に起動したから「普通=Default」だよ、ということか)
      • 管理者ユーザーでも一般ユーザーでも、右クリ>管理者として起動、をすると、「TokenElevationTypeFull」になる。(普通は一般ユーザーで起動するけど、管理者として起動を選んだから昇格してるよ、ということか。)

サンプルコード

「管理者特権」のありなしを取得するコード

下記サイトより。ありがとうございます。

https://dobon.net/vb/dotnet/system/isadmin.html

namespace IsAdministrator
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var isAdmin = IsAdministrator();

            Console.WriteLine($"isAdmin : {isAdmin}");

            Console.ReadLine();
        }

        public static bool IsAdministrator()
        {
            //現在のユーザーを表すWindowsIdentityオブジェクトを取得する
            System.Security.Principal.WindowsIdentity wi = System.Security.Principal.WindowsIdentity.GetCurrent();
            //WindowsPrincipalオブジェクトを作成する
            System.Security.Principal.WindowsPrincipal wp = new System.Security.Principal.WindowsPrincipal(wi);
            //Administratorsグループに属しているか調べる
            return wp.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator);
        }
    }
}

これで、「UAC関連設定とログインユーザー、起動方法により、起動したアプリの権限がどうなるか」の項目の表でいうところの「管理者特権」(=タスクマネージャーの詳細画面にある項目)が、「はい」なのか「いいえ」なのか、つまり、アプリが管理者で起動しているのかそうでないのかが取れる。

が、これだと、UACが無効が故の管理者特権ありなのか、UACは有効だけど右クリック>「管理者として起動」による管理者特権ありなのかが区別できない。

UACの有効無効を取得する

同じく下記サイトより。

https://dobon.net/vb/dotnet/system/isadmin.html

using System.Runtime.InteropServices;

namespace IsAdministrator
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var isAdmin = GetTokenElevationType();

            Console.WriteLine($"TokenElevationType : {GetTokenElevationType()}");

            Console.ReadLine();
        }

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

        public enum TOKEN_INFORMATION_CLASS
        {
            TokenUser = 1,
            TokenGroups,
            TokenPrivileges,
            TokenOwner,
            TokenPrimaryGroup,
            TokenDefaultDacl,
            TokenSource,
            TokenType,
            TokenImpersonationLevel,
            TokenStatistics,
            TokenRestrictedSids,
            TokenSessionId,
            TokenGroupsAndPrivileges,
            TokenSessionReference,
            TokenSandBoxInert,
            TokenAuditPolicy,
            TokenOrigin,
            TokenElevationType,
            TokenLinkedToken,
            TokenElevation,
            TokenHasRestrictions,
            TokenAccessInformation,
            TokenVirtualizationAllowed,
            TokenVirtualizationEnabled,
            TokenIntegrityLevel,
            TokenUIAccess,
            TokenMandatoryPolicy,
            TokenLogonSid,
            MaxTokenInfoClass
        }

        public enum TOKEN_ELEVATION_TYPE
        {
            TokenElevationTypeDefault = 1,  // UACが無効になっているか、標準ユーザーです
            TokenElevationTypeFull,         // UACが有効になっており、昇格しています
            TokenElevationTypeLimited       // UACが有効になっており、昇格していません
        }

        /// <summary>
        /// 昇格トークンの種類を取得する
        /// </summary>
        /// <returns>昇格トークンの種類を示すTOKEN_ELEVATION_TYPE。
        /// 取得に失敗した時でもTokenElevationTypeDefaultを返す。</returns>
        public static TOKEN_ELEVATION_TYPE GetTokenElevationType()
        {
            TOKEN_ELEVATION_TYPE returnValue =
                TOKEN_ELEVATION_TYPE.TokenElevationTypeDefault;

            //Windows Vista以上か確認
            if (Environment.OSVersion.Platform != PlatformID.Win32NT ||
                Environment.OSVersion.Version.Major < 6)
            {
                return returnValue;
            }

            TOKEN_ELEVATION_TYPE tet =
                TOKEN_ELEVATION_TYPE.TokenElevationTypeDefault;
            uint returnLength = 0;
            uint tetSize = (uint)Marshal.SizeOf((int)tet);
            IntPtr tetPtr = Marshal.AllocHGlobal((int)tetSize);
            try
            {
                //アクセストークンに関する情報を取得
                if (GetTokenInformation(System.Security.Principal.WindowsIdentity.GetCurrent().Token, TOKEN_INFORMATION_CLASS.TokenElevationType, tetPtr, tetSize, out returnLength))
                {
                    //結果を取得
                    returnValue = (TOKEN_ELEVATION_TYPE)Marshal.ReadInt32(tetPtr);
                }
            }
            finally
            {
                //解放する
                Marshal.FreeHGlobal(tetPtr);
            }

            return returnValue;
        }
    }
}

こちらだと、上の表のとおりにGetTokenElevationType()が値を返すので、その表のとおりに判別できる。

戻り値がTokenElevationTypeDefaultかどうか、でUACが有効かどうかの判別にはならないが、ユーザーが操作したことによる(右クリック>管理者として起動など)、アプリの管理者権限かどうかは判別できそう。

単に、UACが有効かどうかを調べる

こちらは、下記のサイトにあるように、単に上に挙げたレジストリHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Systemキーの、 EnableLUAが、0か1かで調べられそう。

https://dobon.net/vb/dotnet/system/isuacenabled.html

public static bool IsUacEnabled()
{
    //キーを開く
    var regKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System");
    //キーが見つからない時はUACが有効ではない
    if (regKey == null)
        return false;

    var val = (int)regKey.GetValue("EnableLUA", 0);
    //0以外の時はUACが有効
    return val != 0;
}

参考

dobon.net
UACが有効か調べる

https://dobon.net/vb/dotnet/system/isuacenabled.html

現在のユーザーが管理者か調べる
UACが有効で、管理者に昇格しているか調べる

https://dobon.net/vb/dotnet/system/isadmin.html