Top / .NET備忘録 / 99.小ネタ / 21.特権を有効にする

MSDN フォーラムのスレッドで特権についてやりとりし、質問された方に特権を有効にするサンプルを作っていただきました。

C# にコンバートして改造したのが以下のソースです。

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;

namespace Sample.AcceessControl
{
    public class Privirage
    {
        private NativeMethods.LUID Luid;

        public Privirage(PrivirageNames name) {
            if (!NativeMethods.LookupPrivilegeValue(
                            null, name.ToString(), ref Luid)) {
                throw new Win32Exception();
            }
        }

        public void Enable() {
            ModifyState(true);
        }

        public void Revert() {
            ModifyState(false);
        }

        private void ModifyState(bool enable) {
            using (var tokenHandle = new SafeCurrentProcessTokenHandle(
                                        NativeMethods.TOKEN_ADJUST_PRIVILEGES)) {
                var privilages = new NativeMethods.TOKEN_PRIVILEGES(Luid, enable);
                NativeMethods.AdjustTokenPrivileges(
                                    tokenHandle,
                                    false,
                                    privilages,
                                    0,
                                    IntPtr.Zero,
                                    IntPtr.Zero);
                int errorCode = Marshal.GetLastWin32Error();
                if (errorCode != NativeMethods.ERROR_SUCCESS) {
                    throw new Win32Exception(errorCode);
                }
            }
        }
    }

    internal static class ExternalDll
    {
        public const string Advapi32 = "advapi32.dll";
        public const string Kernel32 = "kernel32.dll";
    }

    internal static class NativeMethods
    {
        public const int ERROR_SUCCESS = 0;
        public const int TOKEN_ADJUST_PRIVILEGES = 0x20;
        public const int SE_PRIVILEGE_DISABLED = 0;
        public const int SE_PRIVILEGE_ENABLED = 2;

        [DllImport(ExternalDll.Kernel32, CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr GetCurrentProcess();

        [DllImport(ExternalDll.Advapi32, CharSet = CharSet.None, ExactSpelling = false, SetLastError = true)]
        public static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, out IntPtr TokenHandle);

        [DllImport(ExternalDll.Advapi32, CharSet = CharSet.None, ExactSpelling = false, SetLastError = true)]
        public static extern bool AdjustTokenPrivileges(SafeHandle TokenHandle, bool DisableAllPrivileges,
                TOKEN_PRIVILEGES NewState, int BufferLength, IntPtr PreviousState, IntPtr ReturnLength);

        [DllImport(ExternalDll.Advapi32, CharSet = CharSet.None, ExactSpelling = false, SetLastError = true)]
        public static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, ref LUID lpLuid);

        [DllImport(ExternalDll.Kernel32, CharSet = CharSet.None, ExactSpelling = false, SetLastError = true)]
        public static extern bool CloseHandle(IntPtr hObject);

        [StructLayout(LayoutKind.Sequential)]
        public struct LUID
        {
            public int LowPart;
            public int HighPart;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct LUID_AND_ATTRIBUTES
        {
            public LUID Luid;
            public int Attributes;
        }

        [StructLayout(LayoutKind.Sequential)]
        public class TOKEN_PRIVILEGES
        {
            private readonly int PrivilegeCount;
            private LUID_AND_ATTRIBUTES Privilege;

            public TOKEN_PRIVILEGES(LUID luid, bool enabled) {
                PrivilegeCount = 1;
                Privilege = new LUID_AND_ATTRIBUTES {
                    Luid = luid,
                    Attributes = enabled ? SE_PRIVILEGE_ENABLED : SE_PRIVILEGE_DISABLED
                };
            }
        }

        public enum SE_OBJECT_TYPE : uint
        {
            SE_UNKNOWN_OBJECT_TYPE,
            SE_FILE_OBJECT,
            SE_SERVICE,
            SE_PRINTER,
            SE_REGISTRY_KEY,
            SE_LMSHARE,
            SE_KERNEL_OBJECT,
            SE_WINDOW_OBJECT,
            SE_DS_OBJECT,
            SE_DS_OBJECT_ALL,
            SE_PROVIDER_DEFINED_OBJECT
        }

        [Flags]
        public enum SECURITY_INFORMATION : uint
        {
            OWNER_SECURITY_INFORMATION = 0x001,
            GROUP_SECURITY_INFORMATION = 0x002,
            DACL_SECURITY_INFORMATION = 0x004,
            SACL_SECURITY_INFORMATION = 0x008,
            PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000,
            PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000,
            UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000,
            UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000,
        }

        [DllImport(ExternalDll.Advapi32, SetLastError = true)]
        public static extern uint SetNamedSecurityInfo(
            string pObjectName,
            SE_OBJECT_TYPE ObjectType,
            SECURITY_INFORMATION SecurityInfo,
            byte[] psidOwner,
            byte[] psidGroup,
            IntPtr pDacl,
            IntPtr pSacl
        );

        [DllImport(ExternalDll.Advapi32, CharSet = CharSet.Auto, SetLastError = true, BestFitMapping = false)]
        public static extern bool LookupAccountName(
                string machineName,
                string accountName,
                byte[] sid,
                ref int sidLen, 
                StringBuilder domainName, 
                ref int domainNameLen,
                ref int peUse);
    }

    public enum PrivirageNames
    {
        SeCreateTokenPrivilege,
        SeAssignPrimaryTokenPrivilege,
        SeLockMemoryPrivilege,
        SeIncreaseQuotaPrivilege,
        SeUnsolicitedInputPrivilege,
        SeMachineAccountPrivilege,
        SeTcbPrivilege,
        SeSecurityPrivilege,
        SeTakeOwnershipPrivilege,
        SeLoadDriverPrivilege,
        SeSystemProfilePrivilege,
        SeSystemtimePrivilege,
        SeProfileSingleProcessPrivilege,
        SeIncreaseBasePriorityPrivilege,
        SeCreatePagefilePrivilege,
        SeCreatePermanentPrivilege,
        SeBackupPrivilege,
        SeRestorePrivilege,
        SeShutdownPrivilege,
        SeDebugPrivilege,
        SeAuditPrivilege,
        SeSystemEnvironmentPrivilege,
        SeChangeNotifyPrivilege,
        SeRemoteShutdownPrivilege,
        SeUndockPrivilege,
        SeSyncAgentPrivilege,
        SeEnableDelegationPrivilege,
        SeManageVolumePrivilege,
        SeImpersonatePrivilege,
        SeCreateGlobalPrivilege,
        SeTrustedCredManAccessPrivilege,
        SeReserveProcessorPrivilege,
        SeRelabelPrivilege
    }

    internal class SafeProcessTokenHandle : SafeHandle
    {
        public SafeProcessTokenHandle(IntPtr processHandle, int desiredAccess)
            : base(IntPtr.Zero, true) {
            if (NativeMethods.OpenProcessToken(
                                processHandle,
                                desiredAccess,
                                out IntPtr hToken)) {
                SetHandle(hToken);
            } else {
                throw new Win32Exception();
            }
        }

        protected override bool ReleaseHandle() {
            return NativeMethods.CloseHandle(handle);
        }

        public override bool IsInvalid {
            get {
                return IntPtr.Zero == handle;
            }
        }
    }

    internal class SafeCurrentProcessTokenHandle : SafeProcessTokenHandle
    {
        public SafeCurrentProcessTokenHandle(int desiredAccess)
            : base(NativeMethods.GetCurrentProcess(), desiredAccess) {
        }
    }
}

このように使います。

・管理者権限で実行しないと動きません
・32bit/64bit に注意(64bit OS 上の 32bit プロセスでは System32 → SysWOW64 にリダイレクトされる)

using System;
using System.IO;
using System.Diagnostics;
using System.Security.Principal;
using Sample.AcceessControl;

namespace ConsoleApp5
{
    static class Program
    {
        [STAThread]
        static void Main() {
            var takeOwnerShip = new Privirage(PrivirageNames.SeTakeOwnershipPrivilege);
            takeOwnerShip.Enable();
            ProcessStartInfo psi = new ProcessStartInfo("whoami.exe", "/priv") {
                UseShellExecute = false
            };
            using (Process pprocess = Process.Start(psi)) {
                pprocess.WaitForExit();
            }
            var fileName = @"C:\WINDOWS\system32\cmd.exe";
            var fi = File.GetAccessControl(fileName);
            fi.SetOwner(new NTAccount("BUILTIN", "Administrators"));
            File.SetAccessControl(fileName, fi);
            takeOwnerShip.Revert();
            Console.ReadKey();
        }
    }
}
whoami.png
cmd.png



トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   最終更新のRSS
Last-modified: 2019-07-27 (土) 23:12:28 (140d)