使用Pinvoke调用AppContainer安全功能的UpdateProcThreadAttribute时失败

问题描述

我正在尝试使用C#启动一个应用程序容器,并调用pinvoke,并试图通过UpdateProcThreadAttribute()将安全功能设置为属性列表。

GetLastError()返回

87-无效参数

本文类似的c ++代码底部https://scorpiosoftware.net/2019/01/15/fun-with-appcontainers/的github链接效果很好。

代码:(下面是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,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,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,(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,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);



解决方法

哇,首先,这是一项很棒的工作,我很好奇您是如何利用它的(CICD?安全性?)。作为一个挑战,我试用了代码,并注意到您对SECURITY_CAPABILITIES结构的声明与Microsoft文档不匹配。他们将Capabilities成员列出为指向SID_AND_ATTRIBUTES结构的指针,而不是结构本身的指针。因此,我将其更改为IntPtr,以使其成为……

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

我不确定如何将结构数组编组为IntPtr,因此现在我下面的示例是您列出的单个功能。

           //create one capability
            SID_AND_ATTRIBUTES sidAndAttributes = new SID_AND_ATTRIBUTES();
            sidAndAttributes.Sid = pSidInternetClientServer;
            sidAndAttributes.Attributes = SE_GROUP_ENABLED;
            IntPtr sidAndAttributesPtr = Marshal.AllocHGlobal(Marshal.SizeOf(sidAndAttributes));
            Marshal.StructureToPtr(sidAndAttributes,sidAndAttributesPtr,false);
            sc.Capabilities = sidAndAttributesPtr;
            sc.CapabilityCount = 1;

这允许notepad.exe以AppContainer的完整性启动并包含您指定的功能标志。

,

感谢您的回复!我确实得到了这个工作。您的建议确实有帮助。实际上,这确实在具有两个功能的应用程序容器中启动了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,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,privateNetworkSid,ref cbSid);
        privateNetworkSid = Marshal.AllocCoTaskMem(Convert.ToInt32(cbSid));
        if (!SecurityNative.CreateWellKnownSid(SecurityNative.WELL_KNOWN_SID_TYPE.WinCapabilityPrivateNetworkClientServerSid,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;
    }