Created
December 20, 2025 03:33
-
-
Save ynkdir/e77928bbd48e4bf5e6ee1f582d710f89 to your computer and use it in GitHub Desktop.
"runFullTrust" and "systemAIModels" seems not supported in CreateAppContainerProfile()
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # "runFullTrust" and "systemAIModels" seems not supported in CreateAppContainerProfile(). | |
| # | |
| # > .\python.exe .\appcontainer.py | |
| # appcontainer.py: 24996 | |
| # systemAIModels: 0 | |
| # runFullTrust: 4 | |
| # Failed to find real location of C:\Users\yukih\work\py-win32more\unapp\unapp\python.exe | |
| # appcontainer.py: 10140 | |
| # systemAIModels: 0 | |
| # runFullTrust: 4 | |
| # | |
| # ///script | |
| # dependencies = ["win32more"] | |
| # /// | |
| # [Launch an AppContainer](https://learn.microsoft.com/en-us/windows/win32/secauthz/implementing-an-appcontainer) | |
| # | |
| # [icalcs](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/icacls) | |
| # S-1-15-2-1: SID of ALL APPLICATION PACKAGES | |
| # OI: Object inherit | |
| # CI: Container inherit | |
| # RX: Read and execute access | |
| # icacls.exe appfolder /grant "*S-1-15-2-1:(OI)(CI)(RX)" | |
| import asyncio | |
| import sys | |
| from contextlib import contextmanager | |
| from ctypes import POINTER, Array, cast, pointer, sizeof | |
| from win32more import FAILED, Byte, UInt32, UIntPtr, WinError | |
| from win32more.Windows.Security.Authorization.AppCapabilityAccess import AppCapability | |
| from win32more.Windows.Win32.Foundation import ERROR_INSUFFICIENT_BUFFER, PWSTR, GetLastError, LocalFree | |
| from win32more.Windows.Win32.Security import ( | |
| PSID, | |
| SECURITY_CAPABILITIES, | |
| SID_AND_ATTRIBUTES, | |
| DeriveCapabilitySidsFromName, | |
| ) | |
| from win32more.Windows.Win32.Security.Authorization import ConvertSidToStringSid | |
| from win32more.Windows.Win32.Security.Isolation import CreateAppContainerProfile, DeleteAppContainerProfile | |
| from win32more.Windows.Win32.System.SystemServices import SE_GROUP_ENABLED | |
| from win32more.Windows.Win32.System.Threading import ( | |
| EXTENDED_STARTUPINFO_PRESENT, | |
| LPPROC_THREAD_ATTRIBUTE_LIST, | |
| PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES, | |
| PROCESS_INFORMATION, | |
| STARTUPINFO, | |
| STARTUPINFOEX, | |
| CreateProcess, | |
| DeleteProcThreadAttributeList, | |
| GetCurrentProcessId, | |
| InitializeProcThreadAttributeList, | |
| UpdateProcThreadAttribute, | |
| ) | |
| def get_capability_sid_from_name(capability_name: str) -> PSID: | |
| group_sids = POINTER(PSID)() | |
| group_sid_count = UInt32() | |
| sids = POINTER(PSID)() | |
| sid_count = UInt32() | |
| succeeded = DeriveCapabilitySidsFromName(capability_name, group_sids, group_sid_count, sids, sid_count) | |
| if not succeeded: | |
| raise WinError() | |
| try: | |
| return sids[0] | |
| finally: | |
| LocalFree(group_sids[0]) | |
| LocalFree(group_sids) | |
| LocalFree(sids) | |
| def convert_sid_to_string_sid(sid: PSID) -> str: | |
| string_sid = PWSTR() | |
| succeeded = ConvertSidToStringSid(sid, string_sid) | |
| if not succeeded: | |
| raise WinError() | |
| try: | |
| return string_sid.value | |
| finally: | |
| LocalFree(string_sid) | |
| def build_app_container_capabilities(capability_names: list[str]) -> Array[SID_AND_ATTRIBUTES]: | |
| capabilities = (SID_AND_ATTRIBUTES * len(capability_names))() | |
| for i, name in enumerate(capability_names): | |
| capabilities[i].Sid = get_capability_sid_from_name(name) | |
| capabilities[i].Attributes = SE_GROUP_ENABLED | |
| return capabilities | |
| @contextmanager | |
| def create_app_container_profile( | |
| app_container_name: str, display_name: str, description: str, capabilities: Array[SID_AND_ATTRIBUTES] | |
| ) -> PSID: | |
| app_container_sid = PSID() | |
| hr = CreateAppContainerProfile( | |
| app_container_name, display_name, description, capabilities, len(capabilities), app_container_sid | |
| ) | |
| if FAILED(hr): | |
| raise WinError() | |
| try: | |
| yield app_container_sid | |
| finally: | |
| DeleteAppContainerProfile(app_container_name) | |
| @contextmanager | |
| def proc_thread_attribute_list( | |
| app_container_sid: PSID, capabilities: Array[SID_AND_ATTRIBUTES] | |
| ) -> LPPROC_THREAD_ATTRIBUTE_LIST: | |
| attribute_list = initialize_proc_thread_attribute_list(1) | |
| _sc = update_proc_thread_attribute_security_capabilities(app_container_sid, attribute_list, capabilities) | |
| try: | |
| yield attribute_list | |
| finally: | |
| DeleteProcThreadAttributeList(attribute_list) | |
| def initialize_proc_thread_attribute_list(attribute_count: int) -> LPPROC_THREAD_ATTRIBUTE_LIST: | |
| attribute_list_size = UIntPtr() | |
| succeeded = InitializeProcThreadAttributeList(None, attribute_count, 0, attribute_list_size) | |
| if succeeded or GetLastError() != ERROR_INSUFFICIENT_BUFFER: | |
| raise WinError() | |
| attribute_list_buffer = (Byte * attribute_list_size.value)() | |
| succeeded = InitializeProcThreadAttributeList(attribute_list_buffer, attribute_count, 0, attribute_list_size) | |
| if not succeeded: | |
| raise WinError() | |
| return cast(pointer(attribute_list_buffer), LPPROC_THREAD_ATTRIBUTE_LIST) | |
| def update_proc_thread_attribute_security_capabilities( | |
| app_container_sid: PSID, attribute_list: LPPROC_THREAD_ATTRIBUTE_LIST, capabilities: Array[SID_AND_ATTRIBUTES] | |
| ) -> None: | |
| sc = SECURITY_CAPABILITIES() | |
| sc.AppContainerSid = app_container_sid | |
| sc.Capabilities = capabilities | |
| sc.CapabilityCount = len(capabilities) | |
| succeeded = UpdateProcThreadAttribute( | |
| attribute_list, 0, PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES, pointer(sc), sizeof(sc), None, None | |
| ) | |
| if not succeeded: | |
| raise WinError() | |
| # Caller should keep sc until DeleteProcThreadAttributeList(). | |
| return sc | |
| def create_process(cmdline: str, attribute_list: LPPROC_THREAD_ATTRIBUTE_LIST) -> None: | |
| si = STARTUPINFOEX() | |
| si.StartupInfo.cb = sizeof(si) | |
| si.lpAttributeList = attribute_list | |
| pi = PROCESS_INFORMATION() | |
| succeeded = CreateProcess( | |
| None, | |
| cmdline, | |
| None, | |
| None, | |
| False, | |
| EXTENDED_STARTUPINFO_PRESENT, | |
| None, | |
| None, | |
| cast(pointer(si), POINTER(STARTUPINFO)), | |
| pi, | |
| ) | |
| if not succeeded: | |
| raise WinError() | |
| async def check_capability(capability_name): | |
| cap = AppCapability.Create(capability_name) | |
| return await cap.RequestAccessAsync() | |
| async def main(): | |
| print("appcontainer.py: ", GetCurrentProcessId()) | |
| print("systemAIModels: ", await check_capability("systemAIModels")) | |
| print("runFullTrust: ", await check_capability("runFullTrust")) | |
| if "--app" not in sys.argv: | |
| capabilities = build_app_container_capabilities(["runFullTrust", "systemAIModels"]) | |
| with create_app_container_profile( | |
| "MySandboxApp", "MySandboxApp", "Description", capabilities | |
| ) as app_container_sid: | |
| with proc_thread_attribute_list(app_container_sid, capabilities) as attribute_list: | |
| create_process(f'"{sys.executable}" "{__file__}" --app', attribute_list) | |
| return | |
| if __name__ == "__main__": | |
| asyncio.run(main()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment