M2Team / Privexec

Run the program with the specified permission level (C++20 required)
MIT License
319 stars 52 forks source link

Windows.Storage.StorageFile GetFileFromPathAsync E_ACCESSDENIED within AppContainer #36

Closed dkattan closed 2 years ago

dkattan commented 3 years ago

I'm not sure if this is really an issue with Privexec but I figured if anybody had any clue what was going on here it'd be @WildByDesign @fcharlie or @forderud

I'm trying to write a PowerShell script that can use the Windows.Networking.BackgroundTransfer.BackgroundDownloader class from WinRT.

However, this class appear to only be accessible from within an App Container

If you run the following code from a normal PowerShell window

[Windows.Networking.BackgroundTransfer, Windows.Networking.BackgroundTransfer.BackgroundDownloader, ContentType=WindowsRuntime] | Out-Null
[Windows.Networking.BackgroundTransfer.BackgroundDownloader]::new() 

you get

Exception calling ".ctor" with "0" argument(s): "This operation is only valid in the context of an app container. (Exception from 
HRESULT: 0x8007109A)"
At C:\Users\DKattan\Immense Networks\Immense Networks Intranet - Powershell Scripts\Test-DeliveryOptimizationMinimal.ps1:2 char:1   
+ [Windows.Networking.BackgroundTransfer.BackgroundDownloader]::new()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : Exception

If I use Privexec to spawn Powershell it constructs the object

FailureToastNotification : 
SuccessTileNotification  : 
SuccessToastNotification : 
TransferGroup            : 
FailureTileNotification  : 
CompletionGroup          : 
CostPolicy               : Default
Group                    : 
Method                   : 
ProxyCredential          : 
ServerCredential         : 

Naturally the next thing I need to do is give the class I constructed a Windows.Storage.StorageFile object that points to the download destination.

I do this with the following code, which works as expected from within normal PowerShell

Add-Type -AssemblyName System.Runtime.WindowsRuntime
[Windows.Storage.StorageFile,Windows.Storage,ContentType=WindowsRuntime] | Out-Null
$asTaskGeneric = ([System.WindowsRuntimeSystemExtensions].GetMethods() | ? { $_.Name -eq 'AsTask' -and $_.GetParameters().Count -eq 1 -and $_.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperation`1' })[0]
Function Await($WinRtTask, $ResultType) {
    $asTask = $asTaskGeneric.MakeGenericMethod($ResultType)
    $netTask = $asTask.Invoke($null, @($WinRtTask))
    try
    {
        $netTask.Wait(-1)
    }
    catch
    {
        Write-Error ($_.Exception.InnerException.InnerException)
    }
    $netTask.Result
}
Await ([Windows.Storage.StorageFile]::GetFileFromPathAsync("C:\temp\test.ps1")) ([Windows.Storage.StorageFile])

However, it seems like no matter what path I specify or what capabilities I give the App Container, I always get

Await : System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
At line:17 char:1
+ Await ([Windows.Storage.StorageFile]::GetFileFromPathAsync("C:\temp\t ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Await

Things I've tried:

When I run Procmon, no activity is generated when it fails in the AppContainer.

I know Procmon is working because I see lots of activity when I run the same code in normal PowerShell.

My speculation is that this is one of the WinRT APIs that requires an Appx package manifest in addition to being run in an App Container. However I find it odd that the code works fine outside of an AppContainer.

I'm hoping there's something obvious I'm missing.

fcharlie commented 3 years ago

Reference: https://github.com/M2Team/Privexec/issues/31