I just recently had two reasons to act as TrustedInstaller. I wanted to test to change the executable that is started when you press the <Ctrl>-<+> shortcut that usually starts the magnifier accessibility tool. I wanted to make it start a command window instead. It would be started as the logged in user if you press the shortcut while logged in on the desktop, but as NT AUTHORITY\SYSTEM if pressed on the secure desktop (“Do you want to allow this app to make changes to your device?”)(“Run as Administrator…”) or the login screen. Neither useful nor secure but sort of interesting.
I also found a bug in the PowerShell DeliveryOptimization module (build 19041.84 (“C:\Windows\System32\WindowsPowerShell\v1.0\Modules\DeliveryOptimization\DeliveryOptimizationStatus.psm1“), The command Get-DOPercentageMaxBackgroundBandwidth defined its output type as the non-existent [uint8], so that function could not be used nor the module imported by the command browser in e.g. PowerShell ISE (what was why I wanted the import to work, the commands I wanted to execute worked fine without explicitly import the module) . The module folder/files were also owned and writable only by TrustedInstaller. The function Get-DOPercentageMinBackgroundBandwidth defined in the same module file had its output type set to [uint32] though so the fix was trivial. Accessing the file was not.
One of the easiest solutions is to use a program like Process Hacker 2, find a process that has TI access, select it and “Run as this user…”. An easy way to to find such a process is to start the TrustedInstaller/”Windows Module Installer”-service and TrustedInstaller.exe will run long enough for us to have time to find it in the process list and to impersonate it or use it as a parent process for say a new powershell.exe instance.
I read this excellent article (one among many on that site) from which I’ve pretty much stolen the rest of this post.
The Art of Becoming TrustedInstaller
You’ll need his excellent NtObjectManager powershell module. Then you can for example start a new powershell process with TrustedInstaller as parent;
Start-Service TrustedInstaller $p = Get-NtProcess -Name TrustedInstaller.exe -FilterScript { -not $_.IsDeleting } | Sort-Object ProcessId -Descending $proc = New-Win32Process powershell.exe -CreationFlags NewConsole -ParentProcess $p[0]
Or change the current thread to impersonate it (not opening a new powershell console window):
Start-Service TrustedInstaller $p = Get-NtProcess -Name TrustedInstaller.exe -FilterScript { -not $_.IsDeleting } | Sort-Object ProcessId -Descending $th = $p[0].GetFirstThread() $current = Get-NtThread -Current -PseudoHandle $imper = $current.ImpersonateThread($th)
Now we can change those files and registry keys without first having to take ownership of them and give our user write permissions, and then try to restore the original permissions and owner (a bit tricky as some special permissions doesn’t seem to to have arithmetically combined human-readable aliases but only have numerical representations).
An example of restoring the magnifier accessibility start executable after trying it as cmd.exe for a while. First just using an administrative shell, then after impersonating a TrustedInstaller.exe thread.
# BEFORE # PS C:\WINDOWS\system32> (Get-NtToken -Effective).User # # Name Attributes # ---- ---------- # PERSEPHONEWL\mignon None # # # PS C:\WINDOWS\system32> (Get-NtToken -Effective).Groups | ft -AutoSize # # Name Attributes # ---- ---------- # Mandatory Label\High Mandatory Level Integrity, IntegrityEnabled # Everyone Mandatory, EnabledByDefault, Enabled # NT AUTHORITY\Local account and member of Administrators group Mandatory, EnabledByDefault, Enabled # PERSEPHONEWL\Ssh Users Mandatory, EnabledByDefault, Enabled # BUILTIN\Administrators Mandatory, EnabledByDefault, Enabled, Owner # BUILTIN\Performance Log Users Mandatory, EnabledByDefault, Enabled # BUILTIN\Users Mandatory, EnabledByDefault, Enabled # NT AUTHORITY\INTERACTIVE Mandatory, EnabledByDefault, Enabled # CONSOLE LOGON Mandatory, EnabledByDefault, Enabled # NT AUTHORITY\Authenticated Users Mandatory, EnabledByDefault, Enabled # NT AUTHORITY\This Organization Mandatory, EnabledByDefault, Enabled # MicrosoftAccount\xxxxxxxxxxxxxxxxx Mandatory, EnabledByDefault, Enabled # NT AUTHORITY\Local account Mandatory, EnabledByDefault, Enabled # NT AUTHORITY\LogonSessionId_0_467797 Mandatory, EnabledByDefault, Enabled, LogonId # LOCAL Mandatory, EnabledByDefault, Enabled # NT AUTHORITY\Cloud Account Authentication Mandatory, EnabledByDefault, Enabled # AFTER # PS C:\Users\mignon> (Get-NtToken -Effective).User | ft -AutoSize # # Name Attributes # ---- ---------- # NT AUTHORITY\SYSTEM None # # # PS C:\Users\mignon> (Get-NtToken -Effective).EnabledGroups | ft -AutoSize # # Name Attributes # ---- ---------- # Everyone Mandatory, EnabledByDefault, Enabled # BUILTIN\Users Mandatory, EnabledByDefault, Enabled # NT AUTHORITY\SERVICE Mandatory, EnabledByDefault, Enabled # CONSOLE LOGON Mandatory, EnabledByDefault, Enabled # NT AUTHORITY\Authenticated Users Mandatory, EnabledByDefault, Enabled # NT AUTHORITY\This Organization Mandatory, EnabledByDefault, Enabled # NT SERVICE\TrustedInstaller EnabledByDefault, Enabled, Owner <-- Should be "Enabled" # NT AUTHORITY\LogonSessionId_0_64740669 Mandatory, EnabledByDefault, Enabled, Owner, LogonId # LOCAL Mandatory, EnabledByDefault, Enabled # BUILTIN\Administrators EnabledByDefault, Enabled, Owner