首页 > 解决方案 > 使用 Pinvoke 调用 AppContainer 安全功能的 UpdateProcThreadAttribute 时失败

问题描述

我正在尝试使用 C# 和 pinvoke 启动一个 appcontainer,并通过 UpdateProcThreadAttribute() 将安全功能设置到属性列表中。

GetLastError() 返回

87 - 无效参数

本文中类似的 c++ 代码(底部的 github 链接https://scorpiosoftware.net/2019/01/15/fun-with-appcontainers/)运行良好。

代码:(下面的 pinvoke 结构/枚举/外部)

        public bool testAppContainer()
        {
            const uint SE_GROUP_ENABLED = 0x00000004;
            const int ProcThreadAttributeSecurityCapabilities = 0x00020009;
            STARTUPINFOEX startupInfoEx = new STARTUPINFOEX();
            PROCESSINFO pInfo = new PROCESSINFO();
            SECURITY_CAPABILITIES sc = new SECURITY_CAPABILITIES();
            IntPtr pSidInternetClientServer = IntPtr.Zero;

            startupInfoEx.StartupInfo.cb = Marshal.SizeOf(startupInfoEx);

            string appContainerName = "Test.AppContainer";

            try
            {

                //get the size, then the sid
                IntPtr clientServerSid = IntPtr.Zero;  uint cbSid = 0;
                SecurityNative.CreateWellKnownSid(SecurityNative.WELL_KNOWN_SID_TYPE.WinCapabilityInternetClientServerSid, clientServerSid, pSidInternetClientServer, ref cbSid);
                pSidInternetClientServer = Marshal.AllocCoTaskMem(Convert.ToInt32(cbSid));
                if (!CreateWellKnownSid(WELL_KNOWN_SID_TYPE.WinCapabilityInternetClientServerSid, clientServerSid, pSidInternetClientServer, ref cbSid))
                {
                    throw new ApplicationException($"Unable to create well known Client Server capability sid!");
                }

                //create an array of one capability
                SID_AND_ATTRIBUTES[] sidAndAttributes = new SID_AND_ATTRIBUTES[1];
                sidAndAttributes[0].Sid = pSidInternetClientServer;
                sidAndAttributes[0].Attributes = SE_GROUP_ENABLED;
                sc.Capabilities = sidAndAttributes;
                sc.CapabilityCount = 1;

                IntPtr appConSid = IntPtr.Zero;

                int hResult = AppContainerNative.DeriveAppContainerSidFromAppContainerName(appContainerName, out appConSid);
                if (hResult < 0)
                {
                    throw new ApplicationException($"Application container {appContainerName} was not found on the machine (err code {hResult})");
                }

                //security capabilities for existing app container
                sc.AppContainerSid = appConSid;

                const int reserved = 0; var size = IntPtr.Zero; int attributeCount = 1;

                bool alreadyInit = ProcessNative.InitializeProcThreadAttributeList(IntPtr.Zero, attributeCount, reserved, ref size);
                if (alreadyInit || size == IntPtr.Zero)
                {
                    throw new Exception(string.Format("Couldn't get the size of the attribute list for {0} attributes", attributeCount));
                }

                startupInfoEx.lpAttributeList = Marshal.AllocHGlobal(size);
                if (startupInfoEx.lpAttributeList == IntPtr.Zero)
                {
                    throw new Exception("Couldn't reserve space for a new attribute list");
                }

                bool initAttributeList = ProcessNative.InitializeProcThreadAttributeList(startupInfoEx.lpAttributeList, attributeCount, reserved, ref size);
                if (!initAttributeList )
                {
                    throw new Exception("Couldn't create new attribute list");
                }
            //also tried this (pass in unmanagedAddr instead of ref sc)
            //    IntPtr unmanagedAddr = Marshal.AllocHGlobal(Marshal.SizeOf(sc));
             //   Marshal.StructureToPtr(sc, unmanagedAddr, true);

                bool success = UpdateProcThreadAttribute(startupInfoEx.lpAttributeList, reserved, (IntPtr)ProcThreadAttributeSecurityCapabilities,
                    ref sc, (IntPtr)Marshal.SizeOf(sc), IntPtr.Zero, IntPtr.Zero);

             //   Marshal.FreeHGlobal(unmanagedAddr);
             //   unmanagedAddr = IntPtr.Zero;

                if (!success)
                {
                    throw new Exception($"Error adding security capabilities to process launch. Error Code: {Marshal.GetLastWin32Error()}");
                }

                var pSec = new SECURITY_ATTRIBUTES(); pSec.nLength = Marshal.SizeOf(pSec);
                var tSec = new SECURITY_ATTRIBUTES(); tSec.nLength = Marshal.SizeOf(tSec);

                success = CreateProcess(null, @"c:\windows\notepad.exe", ref pSec, ref tSec, false, 
                    (uint)ProcessNative.CreateProcessFlags.EXTENDED_STARTUPINFO_PRESENT, IntPtr.Zero, null, ref startupInfoEx, out pInfo);

                if (success)
                {
                    System.Diagnostics.Debug.WriteLine($"Created new app container process {pInfo.dwProcessId}!");
                    return true;
                }
            }
            finally
            {
                // Free the attribute list
                if (startupInfoEx.lpAttributeList != IntPtr.Zero)
                {
                    ProcessNative.DeleteProcThreadAttributeList(startupInfoEx.lpAttributeList);
                    Marshal.FreeHGlobal(startupInfoEx.lpAttributeList);
                }

                // Close process and thread handles
                if (pInfo.hProcess != IntPtr.Zero)
                {
                    ProcessNative.CloseHandle(pInfo.hProcess);
                }
                if (pInfo.hThread != IntPtr.Zero)
                {
                    ProcessNative.CloseHandle(pInfo.hThread);
                }
                Marshal.FreeHGlobal(startupInfoEx.lpAttributeList);

                if (pSidInternetClientServer != IntPtr.Zero)
                    Marshal.FreeCoTaskMem(pSidInternetClientServer);
            }
            return true;
        }



        [StructLayout(LayoutKind.Sequential)]
        public struct SECURITY_CAPABILITIES
        {
            public IntPtr AppContainerSid;
            [MarshalAs(UnmanagedType.ByValArray)]
            public SID_AND_ATTRIBUTES[] Capabilities;
            public uint CapabilityCount;
            public uint Reserved;
        }

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

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        internal struct PROCESSINFO
        {
            public IntPtr hProcess;
            public IntPtr hThread;
            public Int32 dwProcessId;
            public Int32 dwThreadId;
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        internal struct STARTUPINFO
        {
            public Int32 cb;
            public string lpReserved;
            public string lpDesktop;
            public string lpTitle;
            public Int32 dwX;
            public Int32 dwY;
            public Int32 dwXSize;
            public Int32 dwYSize;
            public Int32 dwXCountChars;
            public Int32 dwYCountChars;
            public Int32 dwFillAttribute;
            public Int32 dwFlags;
            public Int16 wShowWindow;
            public Int16 cbReserved2;
            public IntPtr lpReserved2;
            public IntPtr hStdInput;
            public IntPtr hStdOutput;
            public IntPtr hStdError;
        }
        [StructLayout(LayoutKind.Sequential)]
        public struct SECURITY_ATTRIBUTES
        {
            public int nLength;
            public IntPtr lpSecurityDescriptor;
            public int bInheritHandle;
        }
        public enum WELL_KNOWN_SID_TYPE
        {
            WinNullSid,
            WinWorldSid,
            WinLocalSid,
            WinCreatorOwnerSid,
            WinCreatorGroupSid,
            WinCreatorOwnerServerSid,
            WinCreatorGroupServerSid,
            WinNtAuthoritySid,
            WinDialupSid,
            WinNetworkSid,
            WinBatchSid,
            WinInteractiveSid,
            WinServiceSid,
            WinAnonymousSid,
            WinProxySid,
            WinEnterpriseControllersSid,
            WinSelfSid,
            WinAuthenticatedUserSid,
            WinRestrictedCodeSid,
            WinTerminalServerSid,
            WinRemoteLogonIdSid,
            WinLogonIdsSid,
            WinLocalSystemSid,
            WinLocalServiceSid,
            WinNetworkServiceSid,
            WinBuiltinDomainSid,
            WinBuiltinAdministratorsSid,
            WinBuiltinUsersSid,
            WinBuiltinGuestsSid,
            WinBuiltinPowerUsersSid,
            WinBuiltinAccountOperatorsSid,
            WinBuiltinSystemOperatorsSid,
            WinBuiltinPrintOperatorsSid,
            WinBuiltinBackupOperatorsSid,
            WinBuiltinReplicatorSid,
            WinBuiltinPreWindows2000CompatibleAccessSid,
            WinBuiltinRemoteDesktopUsersSid,
            WinBuiltinNetworkConfigurationOperatorsSid,
            WinAccountAdministratorSid,
            WinAccountGuestSid,
            WinAccountKrbtgtSid,
            WinAccountDomainAdminsSid,
            WinAccountDomainUsersSid,
            WinAccountDomainGuestsSid,
            WinAccountComputersSid,
            WinAccountControllersSid,
            WinAccountCertAdminsSid,
            WinAccountSchemaAdminsSid,
            WinAccountEnterpriseAdminsSid,
            WinAccountPolicyAdminsSid,
            WinAccountRasAndIasServersSid,
            WinNTLMAuthenticationSid,
            WinDigestAuthenticationSid,
            WinSChannelAuthenticationSid,
            WinThisOrganizationSid,
            WinOtherOrganizationSid,
            WinBuiltinIncomingForestTrustBuildersSid,
            WinBuiltinPerfMonitoringUsersSid,
            WinBuiltinPerfLoggingUsersSid,
            WinBuiltinAuthorizationAccessSid,
            WinBuiltinTerminalServerLicenseServersSid,
            WinBuiltinDCOMUsersSid,
            WinBuiltinIUsersSid,
            WinIUserSid,
            WinBuiltinCryptoOperatorsSid,
            WinUntrustedLabelSid,
            WinLowLabelSid,
            WinMediumLabelSid,
            WinHighLabelSid,
            WinSystemLabelSid,
            WinWriteRestrictedCodeSid,
            WinCreatorOwnerRightsSid,
            WinCacheablePrincipalsGroupSid,
            WinNonCacheablePrincipalsGroupSid,
            WinEnterpriseReadonlyControllersSid,
            WinAccountReadonlyControllersSid,
            WinBuiltinEventLogReadersGroup,
            WinNewEnterpriseReadonlyControllersSid,
            WinBuiltinCertSvcDComAccessGroup,
            WinMediumPlusLabelSid,
            WinLocalLogonSid,
            WinConsoleLogonSid,
            WinThisOrganizationCertificateSid,
            WinApplicationPackageAuthoritySid,
            WinBuiltinAnyPackageSid,
            WinCapabilityInternetClientSid,
            WinCapabilityInternetClientServerSid,
            WinCapabilityPrivateNetworkClientServerSid,
            WinCapabilityPicturesLibrarySid,
            WinCapabilityVideosLibrarySid,
            WinCapabilityMusicLibrarySid,
            WinCapabilityDocumentsLibrarySid,
            WinCapabilitySharedUserCertificatesSid,
            WinCapabilityEnterpriseAuthenticationSid,
            WinCapabilityRemovableStorageSid,
            WinBuiltinRDSRemoteAccessServersSid,
            WinBuiltinRDSEndpointServersSid,
            WinBuiltinRDSManagementServersSid,
            WinUserModeDriversSid,
            WinBuiltinHyperVAdminsSid,
            WinAccountCloneableControllersSid,
            WinBuiltinAccessControlAssistanceOperatorsSid,
            WinBuiltinRemoteManagementUsersSid,
            WinAuthenticationAuthorityAssertedSid,
            WinAuthenticationServiceAssertedSid,
            WinLocalAccountSid,
            WinLocalAccountAndAdministratorSid,
            WinAccountProtectedUsersSid,
            WinCapabilityAppointmentsSid,
            WinCapabilityContactsSid,
            WinAccountDefaultSystemManagedSid,
            WinBuiltinDefaultSystemManagedGroupSid,
            WinBuiltinStorageReplicaAdminsSid,
            WinAccountKeyAdminsSid,
            WinAccountEnterpriseKeyAdminsSid,
            WinAuthenticationKeyTrustSid,
            WinAuthenticationKeyPropertyMFASid,
            WinAuthenticationKeyPropertyAttestationSid,
            WinAuthenticationFreshKeyAuthSid,
            WinBuiltinDeviceOwnersSid
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        internal struct STARTUPINFOEX
        {
            public STARTUPINFO StartupInfo;
            public IntPtr lpAttributeList;
        }
        [DllImport("advapi32.dll", SetLastError = true)]
        internal static extern bool CreateWellKnownSid(WELL_KNOWN_SID_TYPE WellKnownSidType, IntPtr DomainSid, IntPtr pSid, ref uint cbSid);

        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool CreateProcess(string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, 
            ref SECURITY_ATTRIBUTES lpThreadAttributes, 
            bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment,  
            string lpCurrentDirectory, [In] ref STARTUPINFOEX lpStartupInfo, out PROCESSINFO lpProcessInformation);

        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool InitializeProcThreadAttributeList(IntPtr lpAttributeList, int dwAttributeCount, int dwFlags, ref IntPtr lpSize);

        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool UpdateProcThreadAttribute(IntPtr lpAttributeList, uint dwFlags, IntPtr Attribute, [MarshalAs(UnmanagedType.Struct), In] ref SECURITY_CAPABILITIES caps, IntPtr cbSize, IntPtr lpPreviousValue, IntPtr lpReturnSize);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern void DeleteProcThreadAttributeList(IntPtr lpAttributeList);



标签: c#pinvoke

解决方案


感谢您的答复!我确实让这个工作。你的建议确实有帮助。这确实会在具有两个功能的应用容器中启动 notepad.exe。这是所有想要尝试这个的元帅的代码。我的目标是将我们用来保护服务器的一些程序容器化。

    [StructLayout(LayoutKind.Sequential)]
    public struct SECURITY_CAPABILITIES
    {
        public IntPtr AppContainerSid;

        public IntPtr Capabilities;
        public int CapabilityCount;
        public int Reserved;
    }

     private void AddDefaultCapabilitiesSid(ref SECURITY_CAPABILITIES sc)
    {
        //get the size, then the sid
        IntPtr mem = IntPtr.Zero;
        IntPtr clientServerSid = IntPtr.Zero;
        IntPtr privateNetworkSid = IntPtr.Zero;
        IntPtr pSid = IntPtr.Zero;
        uint cbSid = 0;

        //get the size, then the sid
        SecurityNative.CreateWellKnownSid(SecurityNative.WELL_KNOWN_SID_TYPE.WinCapabilityInternetClientServerSid, pSid, clientServerSid, ref cbSid);
        clientServerSid = Marshal.AllocCoTaskMem(Convert.ToInt32(cbSid));
        if (!SecurityNative.CreateWellKnownSid(SecurityNative.WELL_KNOWN_SID_TYPE.WinCapabilityInternetClientServerSid, pSid, clientServerSid, ref cbSid))
        {
            throw new ApplicationException($"Unable to create well known Client Server capability sid!");
        }

    
        //get the size, then the sid
        SecurityNative.CreateWellKnownSid(SecurityNative.WELL_KNOWN_SID_TYPE.WinCapabilityPrivateNetworkClientServerSid, pSid, privateNetworkSid, ref cbSid);
        privateNetworkSid = Marshal.AllocCoTaskMem(Convert.ToInt32(cbSid));
        if (!SecurityNative.CreateWellKnownSid(SecurityNative.WELL_KNOWN_SID_TYPE.WinCapabilityPrivateNetworkClientServerSid, pSid, privateNetworkSid, ref cbSid))
        {
            throw new ApplicationException($"Unable to create well known Client Server capability sid!");
        }

        SecurityNative.SID_AND_ATTRIBUTES[] sidAndAttributes = new SecurityNative.SID_AND_ATTRIBUTES[2];
        sidAndAttributes[0].Sid = clientServerSid;
        sidAndAttributes[0].Attributes = SE_GROUP_ENABLED;
        sidAndAttributes[1].Sid = privateNetworkSid;
        sidAndAttributes[1].Attributes = SE_GROUP_ENABLED;


        int arraySize = sidAndAttributes.Length;
        int elemSize = Marshal.SizeOf(typeof(SecurityNative.SID_AND_ATTRIBUTES));
        IntPtr result = Marshal.AllocHGlobal(elemSize * arraySize);
        mem = new IntPtr(result.ToInt64());
        for (int i = 0; i < arraySize; i++)
        {
            IntPtr ptr = new IntPtr(result.ToInt64() + elemSize * i);
            Marshal.StructureToPtr(sidAndAttributes[i], ptr, false);

            MemToFree.Add(ptr); //free this mem later
        }
        sc.Capabilities = mem;
        sc.CapabilityCount = arraySize;
    }

推荐阅读