Fun with AppContainers

AppContainers are the sanboxes typically used to run UWP processes (also known as metro, store, modern…). A process within an AppContainer runs with an Integrity Level of low, which effectively means it has no access to almost everything, as the default integrity level of objects (such as files) is Medium. This means code running inside an AppContainer can’t do any sigtnificant damage because of that lack of access. Furthermore, from an Object Manager perspective, named objects created by an AppContainer are stored under its own object manager directory, based on an identifier known as AppContainer SID. This means one AppContainer cannot interfere with another’s objects.

For example, if a process not in an AppContainer creates a mutex named “abc”, its full name is really “\Sessions\1\BaseNamedObjects\abc” (assuming the process runs in session 1). On the other hand, if AppContainer A creates a mutex named “abc”, its full name is something like “\Sessions\1\AppContainerNamedObjects\S-1-15-2-466767348-3739614953-2700836392-1801644223-4227750657-1087833535-2488631167\abc”, meaning it can nevr interfere with another AppContainer or any process running outside of an AppContainer.

Although AppContainers were created specifically for store apps, theye can also be used to execute “normal” applications, providing the same level of security and isolation. Let’s see how to do that.

First, we need to create the AppContainer and obtain an AppContainer SID. This SID is based on a hash of the container name. In the UWP world, this name is made up of the application package and the 13 digits of the signer’s hash. For normal applications, we can select any string; selecting the same string would yield the same SID – which means we can actually use it to “bundle” several processes into the same AppContainer.

The first step is to create an AppContainer profile (error handling ommitted):

PSID appContainerSid;
::CreateAppContainerProfile(containerName, containerName, containerName, nullptr, 0, &appContainerSid);

The containerName argument is the important one. If the function fails, it probably means the container profile exists already. In that case, we need to extract the SID from the existing profile:

::DeriveAppContainerSidFromAppContainerName(containerName, &appContainerSid);

The next step is prepare for process creation. The absolute minimum is to initialize a process attribute list with a SECURITY_CAPABILITIES structure to indicate we want the process to be created inside an AppContainer. As part of this, we can specify capabilities this AppContainer should have, such as internet access, access to the documents library and any other capabilities as defined by the Windows Runtime:

STARTUPINFOEX si = { sizeof(si) };
SIZE_T size;
sc.AppContainerSid = appContainerSid;

::InitializeProcThreadAttributeList(nullptr, 1, 0, &size); 
auto buffer = std::make_unique<BYTE[]>(size); 
si.lpAttributeList = reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(buffer.get()); 
::InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size)); 
::UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES, &sc, sizeof(sc), nullptr, nullptr));

We specified zero capabilities for now. Now we’re ready to create the process:

::CreateProcess(nullptr, exePath, nullptr, nullptr, FALSE,
        (LPSTARTUPINFO)&si, &pi);

We can try this with the usual first victim, Notepad. Notepad launches and everyhing seems OK. However, if we try to open almost any file by using Notepad’s File/Open menu item, we’ll see that notepad has no access to usual things, such as “my documents” or “my pictures”. This is because it’s runnign with Low Integrity Level and files are defaulted to Medium integrity level:

“AppContainer” in Process Explorer implies Low integirty level.

If we would want Notepad to have access to the user’s files, such as documents and pictures, we would have to set explict permissions on these objects allowing access to the AppContainer SID. Functions to use include SetNamedSecurityInfo (see the project on Github for the full code).

I’ve created a simple application to test these things. We can specify a container name, an executable path and click “Run” to execute in in AppContainer. We can add folders/files that would get full permissions:


Let’s now try a more interesting application – Windows Media Player (yes, I know, who uses the old Media Player these days? But it’s an interesting example). Windows Media Player has the (annoying?) feature where you can only run a single instance of it at any given time. The way this works is that WMP creates a mutex with a very specific name, “Microsoft_WMP_70_CheckForOtherInstanceMutex“, if it already exists, it sends a message to its buddy (a previous instance of WMP) and then terminates. A simple trick we can do with Process Explorer is to close that handle and then launching another WMP.

Let’s try something different: let’s run WMP in an AppContainer. Then let’s run another one in a different AppContainer. Will we get two instances?


Running WMP in this way popus up its helper, setup_wm.exe which asks for the initial settings for WMP. Clicking “Express Settings” closes the dialog but it then it comes up again! And again! You can’t get rid of it, unless you close the dialog and then WMP does not launch. Can you guess why is that?

If you guessed “permissions” – you are correct. Running Process Monitor when this dialog comes up and filtering for “ACCESS DENIED” shows something like this:


Clearly, some keys need access so the settings can be saved. The tool allows adding these keys and setting full permissions for them:


Now we can run WMP in two different containers (change the container name and re-run) and they both run just fine. That’s becuase each mutex now has a unique name prefixed with the AppContainer SID of the relevant AppContainer:


The code can be found at


Silent Process Exit – Is It Really?

While working on my GflagsX tool, there was yet another feature the tool was missing compared to the classic GFlags tool – Silent Process Exit support. But what is Silent Process Exit?

According to the documentation there are two scenarios that trigger Silent Process Exit:

  • Self exiting – one of the threads in the process calls ExitProcess.
  • A TerminateProcess call is issued from another (or the same process).

The documentation states that if a process exits because all threads terminate normally, then Silent Process Exit is not in effect. (also if kernel code kills a process, Silent Process Exit is not invoked).

The documentation may lead us to belive that if a process exits normally (no abnormal termination or exception) then Silent Process Exit will not be invoked. Let’s test that theory.

First, let’s configure Silent Process Exit with GFlags. (GFlagsX support is on its way). Run GFlags and select the Silent Process Exit tab:


Let’s test it with notepad. Type notepad.exe in the Image text box and press Tab. Some of the options light up. Let’s try something simple – generating a dump file when notepad terminates. Check Enable Silent Process Exit Monitoring and then set a dump folder location and dump type, like so:


Click Apply to apply the settings. Now launch Notepad. If you terminate it using (say) Task Manager, you’ll find a subfolder under the configured Dump Folder Location named Notepad.exe-(PID xxxx)-yyyyyyyy where xxxx is the terminating process ID and yyyyyy is the value returned from GetTickCount at the time of the exit (the number of milliseconds elapsed since Windows booted). Inside the folder you’ll find the dump file itself.

However, if you launch notepad again and just close its main window, you’ll find, perhaps surprisingly, that yet another folder was created with a new dump file. But why? Isn’t this a normal process termination?

Since we can be pretty sure no process (including notepad) called TerminateProcess, this means notepad called ExitProcess. Is this “normal”? Are there processes that terminate by just ending all their threads?

Let’s launch another notepad instance and attach WinDbg to it. Break into the debugger and add a breakpoint for ExitProcess:

0:000> x kernel32!ExitProcess*
00007ffe`1509b190 KERNEL32!ExitProcessImplementation (<no parameter info>)
0:000> bp KERNEL32!ExitProcessImplementation

Now let the process go and close notepad’s window. The breakpoint should hit:

Breakpoint 0 hit
00007ffe`1509b190 4883ec28 sub rsp,28h

Let’s look at the call stack:

0:000> k
# Child-SP RetAddr Call Site
00 000000a1`4294f718 00007ffe`17119ce5 KERNEL32!ExitProcessImplementation
01 000000a1`4294f720 00007ffe`1711a345 msvcrt!_crtExitProcess+0x15
02 000000a1`4294f750 00007ff7`ffef934a msvcrt!doexit+0x171
03 000000a1`4294f7c0 00007ffe`15093034 notepad!__mainCRTStartup+0x1b6
04 000000a1`4294f880 00007ffe`17281461 KERNEL32!BaseThreadInitThunk+0x14
05 000000a1`4294f8b0 00000000`00000000 ntdll!RtlUserThreadStart+0x21

Now it seems clear: when the first (“main”) thread of notepad returns from its main function, the C-runtime library calls ExitProcess explicitly. And in fact this is what you’ll find with most executables. This is why when the main thread exits in a C/C++ application, the process ends wven if other threads still exist and executing. From the Windows kernel’s perspective, there is no “main” thread – all threads are equal.

Silent Exit Process support is part of NTDLL and the Windows Error Reporting Service. This is in contrast to tools such as ProcDump from Sysinternals that attaches a debugger to the monitored process and creates a dump file when it exits. To set it up, the global flag with the value 0x200 (512) must be set in the “Image File Execution Options” (IFEO) subkey (just like all other global flags). However, once the bit is set, the actual details need to be written into the key HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\notepad.exe. This is done on an image name basis just as with the IFEO key. Here is the example for notepad just shown:


Stay tuned for more info on Silent Process Exit support in GFlagsX!


Public Remote Windows Internals Training

  • Public 5-day remote class
  • Dates: November 5, 7, 8, 14, 15
  • Time: 8 hours / day. Exact hours TBD
  • Price: 2250 USD
  • Register by emailing and specifying “Windows Internals Training” in the title
    • Provide names of participants (discount available for multiple participants from the same company), company name and time zone.
    • You’ll receive instructions for payment and other details
  • Virtual space is limited!


Objectives: Understand the Windows system architecture

Explore the internal workings of process, threads, jobs, virtual memory, the I/O system and other mechanisms fundamental to the way Windows works

Write a simple software device driver to access/modify information not available from user mode

Target Audience: Experienced windows programmers in user mode or kernel mode, interested in writing better programs, by getting a deeper understanding of the internal mechanisms of the windows operating system.

Security researchers interested in gaining a deeper understanding of Windows mechanisms (security or otherwise), allowing for more productive research

Pre-Requisites: Basic knowledge of OS concepts and architecture.

Power user level working with Windows

Practical experience developing windows applications is an advantage

C/C++ knowledge is an advantage


  • Module 1: System Architecture
    • Brief Windows NT History
    • Windows Versions
    • Windows 10 and Future versions
    • Tools: Windows, Sysinternals, Debugging Tools for Windows
    • Processes and Threads
    • Virtual Memory
    • User mode vs. Kernel mode
    • Objects and Handles
    • Architecture Overview
    • Key Components
    • User/kernel transitions
    • APIs: Win32, Native, .NET, COM, WinRT
    • Introduction to WinDbg
    • Lab: Task manager, Process Explorer, WinDbg


  • Module 2: Processes & Jobs
    • Process basics
    • Creating and terminating processes
    • Process Internals & Data Structures
    • The loader
    • DLL explicit and implicit linking
    • Process and thread attributes
    • Protected processes and PPL
    • UWP Processes
    • Minimal and Pico processes
    • Jobs
    • Nested jobs
    • Introduction to Silos
    • Lab: viewing process and job information; creating processes; setting job limits


  • Module 3: Threads
    • Thread basics
    • Creating and terminating threads
    • Processor Groups
    • Thread Priorities
    • Thread Scheduling
    • Thread Stacks
    • Thread States
    • CPU Sets
    • Thread Synchronization
    • Lab: creating threads; thread synchronization; viewing thread information; CPU sets


  • Module 4: Kernel Mechanisms
    • Trap Dispatching
    • Interrupts & Exceptions
    • System Crash
    • Object Management
    • Objects and Handles
    • Sharing Objects
    • Synchronization
    • Synchronization Primitives
    • Signaled vs. Non-Signaled
    • Windows Global Flags
    • Kernel Event Tracing
    • Wow64
    • Lab: Viewing Handles, Interrupts; creating maximum handles


  • Module 5: Memory Management
    • Overview
    • Small, large and huge pages
    • Page states
    • Address Space Layout
    • Address Translation Mechanisms
    • Heaps
    • APIs in User mode and Kernel mode
    • Page Faults
    • Page Files
    • Commit Size and Commit Limit
    • Workings Sets
    • Memory Mapped Files (Sections)
    • Page Frame Database
    • Other memory management features
    • Lab: committing & reserving memory; using shared memory; viewing memory related information


  • Module 6: Management Mechanisms
    • The Registry
    • Services
    • Starting and controlling services
    • Windows Management Instrumentation
    • Lab: Viewing and configuring services; Process Monitor

  • Module 7: I/O System
    • I/O System overview
    • Device Drivers
    • The Windows Driver Model (WDM)
    • The Windows Driver Foundation (WDF)
    • WDF: KMDF and UMDF
    • I/O Processing and Data Flow
    • IRPs
    • Plug & Play
    • Power Management
    • Driver Verifier
    • Writing a Software Driver
    • Labs: viewing driver and device information; writing a software driver


  • Module 8: Security
    • Security Components
    • Virtualization Based Security
    • Protecting objects
    • SIDs
    • Tokens
    • ACLs
    • Privileges
    • Access checks
    • AppContainers
    • Logon
    • User Access Control (UAC)
    • Process mitigations
    • Lab: viewing security information