Win32ModuleFunctions.ps1
# Copyright 2021 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. <# .SYNOPSIS Gets the executable manifest for a PE file. .DESCRIPTION This cmdlet extracts the manifes from a PE file and extracts basic information such as UIAccess setting or Auto Elevation. .PARAMETER Path Filename to get the executable manifest from. .INPUTS List of filenames .OUTPUTS NtApiDotNet.Win32.ExecutableManifest .EXAMPLE Get-ExecutableManifest abc.dll Gets manifest from file abc.dll. .EXAMPLE Get-ChildItem $env:windir\*.exe -Recurse | Get-ExecutableManifest Gets all manifests from EXE files, recursively under Windows. .EXAMPLE Get-ChildItem $env:windir\*.exe -Recurse | Get-ExecutableManifest | Where-Object AutoElevate | Select-Object FullPath Get the full path of all executables with Auto Elevate manifest configuration. #> function Get-ExecutableManifest { [CmdletBinding()] param ( [parameter(Mandatory, Position = 0, ValueFromPipeline)] [string]$Path ) PROCESS { $fullpath = Resolve-Path -LiteralPath $Path $manifest = [NtApiDotNet.Win32.ExecutableManifest]::GetManifests($fullpath) Write-Output $manifest } } <# .SYNOPSIS Loads a DLL into memory. .DESCRIPTION This cmdlet loads a DLL into memory with specified flags. .PARAMETER Path Specify the path to the DLL. .PARAMETER Flags Specify the flags for loading. .INPUTS None .OUTPUTS NtApiDotNet.Win32.SafeLoadLibraryHandle #> function Import-Win32Module { [CmdletBinding()] Param( [Parameter(Position = 0, Mandatory)] [string]$Path, [Parameter(Position = 1)] [NtApiDotNet.Win32.LoadLibraryFlags]$Flags = 0 ) if (Test-Path $Path) { $Path = Resolve-Path $Path } [NtApiDotNet.Win32.SafeLoadLibraryHandle]::LoadLibrary($Path, $Flags) | Write-Output } <# .SYNOPSIS Gets an existing DLL from memory. .DESCRIPTION This cmdlet finds an existing DLL from memory. .PARAMETER Path Specify the path to the DLL. .PARAMETER Address Specify the address of the module. .INPUTS None .OUTPUTS NtApiDotNet.Win32.SafeLoadLibraryHandle #> function Get-Win32Module { [CmdletBinding(DefaultParameterSetName = "FromPath")] Param( [Parameter(Position = 0, Mandatory, ParameterSetName = "FromPath")] [string]$Path, [Parameter(Mandatory, ParameterSetName = "FromAddress")] [IntPtr]$Address ) if ($PSCmdlet.ParameterSetName -eq "FromPath") { if (Test-Path $Path) { $Path = Resolve-Path $Path } [NtApiDotNet.Win32.SafeLoadLibraryHandle]::GetModuleHandle($Path) | Write-Output } else { [NtApiDotNet.Win32.SafeLoadLibraryHandle]::GetModuleHandle($Address) | Write-Output } } <# .SYNOPSIS Gets the exports from a loaded DLL. .DESCRIPTION This cmdlet gets the list of exports from a loaded DLL or a single exported function. .PARAMETER Module Specify the DLL. .PARAMETER Path Specify the path to the DLL. .PARAMETER ProcAddress Specify the name of the function to query. .INPUTS None .OUTPUTS NtApiDotNet.Win32.DllExport[] or int64. #> function Get-Win32ModuleExport { [CmdletBinding(DefaultParameterSetName = "FromModule")] Param( [Parameter(Position = 0, Mandatory, ParameterSetName = "FromModule")] [NtApiDotNet.Win32.SafeLoadLibraryHandle]$Module, [Parameter(Position = 0, Mandatory, ParameterSetName = "FromPath")] [string]$Path, [string]$ProcAddress = "" ) if ($PsCmdlet.ParameterSetName -eq "FromPath") { Use-NtObject($lib = Import-Win32Module -Path $Path -Flags LoadLibraryAsDataFile) { if ($null -ne $lib) { Get-Win32ModuleExport -Module $lib -ProcAddress $ProcAddress } } } else { if ($ProcAddress -eq "") { $Module.Exports | Write-Output } else { $Module.GetProcAddress($ProcAddress, $true).Result.ToInt64() | Write-Output } } } <# .SYNOPSIS Gets the imports from a loaded DLL. .DESCRIPTION This cmdlet gets the list of imports from a loaded DLL. .PARAMETER Module Specify the DLL. .PARAMETER Path Specify the path to the DLL. .PARAMETER DllName Specify a name of a DLL to only show imports from. .PARAMETER ResolveApiSet Specify to resolve API set names to the DLl names. .INPUTS None .OUTPUTS NtApiDotNet.Win32.DllImport[] #> function Get-Win32ModuleImport { [CmdletBinding(DefaultParameterSetName = "FromModule")] Param( [Parameter(Position = 0, Mandatory, ParameterSetName = "FromModule")] [NtApiDotNet.Win32.SafeLoadLibraryHandle]$Module, [Parameter(Position = 0, Mandatory, ParameterSetName = "FromPath")] [string]$Path, [string]$DllName, [switch]$ResolveApiSet ) $imports = if ($PsCmdlet.ParameterSetName -eq "FromPath") { Use-NtObject($lib = Import-Win32Module -Path $Path -Flags LoadLibraryAsDataFile) { if ($null -ne $lib) { Get-Win32ModuleImport -Module $lib -ResolveApiSet:$ResolveApiSet } } } else { if ($ResolveApiSet) { $Module.ApiSetImports } else { $Module.Imports } } if ($DllName -ne "") { $imports | Where-Object DllName -eq $DllName | Select-Object -ExpandProperty Functions | Write-Output } else { $imports | Write-Output } } <# .SYNOPSIS Download a symbol file from a symbol server for a module. .DESCRIPTION This cmdlet extracts the debug information from a loaded module and downloads the symbol file from a symbol server. .PARAMETER Module Specify the loaded module. .PARAMETER Path Specify the path to the module. .PARAMETER OutPath Specify the output path to write the symbol file to. If you specify a directory it will use the original filename. Defaults to current directory. .PARAMETER SymbolServerUrl Specify the URL for the symbol server. Defaults to the Microsoft public symbol server. .PARAMETER Mirror Specify that the output file should be a mirror of the symbol path. Useful to create a local symbol cache. .INPUTS None .OUTPUTS None #> function Get-Win32ModuleSymbolFile { [CmdletBinding(DefaultParameterSetName = "FromModule")] Param( [Parameter(Position = 0, Mandatory, ParameterSetName = "FromModule")] [NtApiDotNet.Win32.SafeLoadLibraryHandle]$Module, [Parameter(Position = 0, Mandatory, ParameterSetName = "FromPath")] [string]$Path, [Parameter(Position = 1)] [string]$OutPath, [string]$SymbolServerUrl = "https://msdl.microsoft.com/download/symbols", [switch]$Mirror ) if ($PsCmdlet.ParameterSetName -eq "FromPath") { Use-NtObject($lib = Import-Win32Module -Path $Path -Flags LoadLibraryAsDataFile) { if ($null -ne $lib) { Get-Win32ModuleSymbolFile -Module $lib -OutPath $OutPath -SymbolServerUrl $SymbolServerUrl -Mirror:$Mirror } } } else { $debug_data = $Module.DebugData $name = $debug_data.PdbName if ($Mirror) { if (!(Test-Path -Path $OutPath -PathType Container)) { Write-Error "Output path must be a directory when using mirror." return } $OutPath = $debug_data.GetSymbolPath((Resolve-Path $OutPath)) New-Item -Type Directory -Path (Split-Path $OutPath -Parent) -Force -ErrorAction Stop | Out-Null } else { if ("" -eq $OutPath) { $OutPath = $name } else { if (Test-Path -Path $OutPath -PathType Container) { $OutPath = Join-Path $OutPath $name } } } $url = $debug_data.GetSymbolPath($SymbolServerUrl) Invoke-WebRequest -Uri $url -OutFile $OutPath -ErrorAction Stop Write-Verbose "Wrote symbol file to $OutPath" } } <# .SYNOPSIS Gets the resources from a loaded DLL. .DESCRIPTION This cmdlet gets the list of resources from a loaded DLL. .PARAMETER Module Specify the DLL. .PARAMETER Path Specify the path to the DLL. .PARAMETER DontLoadResource Specify to not load the resource data. Ignored if getting a specific type. .PARAMETER Type Specify the type of resource to get. .PARAMETER Name Specify the name of resource tot get. Must be combined with the Type. .INPUTS None .OUTPUTS NtApiDotNet.Win32.Image.ImageResource #> function Get-Win32ModuleResource { [CmdletBinding(DefaultParameterSetName = "FromModule")] Param( [Parameter(Position = 0, Mandatory, ParameterSetName = "FromModule")] [NtApiDotNet.Win32.SafeLoadLibraryHandle]$Module, [Parameter(Position = 0, Mandatory, ParameterSetName = "FromPath")] [string]$Path, [switch]$DontLoadResource, [ValidateNotNullOrEmpty()] [string]$Type, [ValidateNotNullOrEmpty()] [ValidateScript({ if ($PSBoundParameters.Keys -contains 'Type') { $true } else { throw "Must specify a type when using a name." } })] [string]$Name ) try { $lib = if ($PSCmdlet.ParameterSetName -eq "FromPath") { Import-Win32Module -Path $Path -Flags LoadLibraryAsDataFile } else { $Module.AddRef() } Use-NtObject($lib) { if ("" -ne $Type) { if ("" -ne $Name) { $lib.LoadResource($Name, $Type) } else { $lib.GetResources($Type, !$DontLoadResource) | Write-Output } } else { $lib.GetResources(!$DontLoadResource) | Write-Output } } } catch { Write-Error $_ } } <# .SYNOPSIS Get the embedded signature information from a file. .DESCRIPTION This cmdlet gets the embedded authenticode signature information from a file. This differs from Get-AuthenticodeSignature in that it doesn't take into account catalog signing which is important for tracking down PP and PPL executables. .PARAMETER FullName The path to the file to extract the signature from. #> function Get-EmbeddedAuthenticodeSignature { [CmdletBinding()] param( [parameter(Mandatory, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [string]$FullName ) PROCESS { $content_type = [System.Security.Cryptography.X509Certificates.X509ContentType]::Unknown try { $path = Resolve-Path $FullName $content_type = [System.Security.Cryptography.X509Certificates.X509Certificate2]::GetCertContentType($path) } catch { Write-Error $_ } if ($content_type -ne "Authenticode") { return } $cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($path) $all_certs = [NtApiDotNet.Win32.Security.Authenticode.AuthenticodeUtils]::GetCertificates($path) | Write-Output $ppl = $false $pp = $false $tcb = $false $system = $false $dynamic = $false $elam = $false $store = $false $ium = $false $enclave = $false foreach ($eku in $cert.EnhancedKeyUsageList) { switch ($eku.ObjectId) { "1.3.6.1.4.1.311.10.3.22" { $ppl = $true } "1.3.6.1.4.1.311.10.3.24" { $pp = $true } "1.3.6.1.4.1.311.10.3.23" { $tcb = $true } "1.3.6.1.4.1.311.10.3.6" { $system = $true } "1.3.6.1.4.1.311.61.4.1" { $elam = $true } "1.3.6.1.4.1.311.76.5.1" { $dynamic = $true } "1.3.6.1.4.311.76.3.1" { $store = $true } "1.3.6.1.4.1.311.10.3.37" { $ium = $true } "1.3.6.1.4.1.311.10.3.42" { $enclave = $true } } } $page_hash = [NtApiDotNet.Win32.Security.Authenticode.AuthenticodeUtils]::ContainsPageHash($path) $props = @{ Path = $Path; Certificate = $cert; AllCertificates = $all_certs; ProtectedProcess = $pp; ProtectedProcessLight = $ppl; Tcb = $tcb; SystemComponent = $system; DynamicCodeGeneration = $dynamic; Elam = $elam; Store = $store; IsolatedUserMode = $ium; HasPageHash = $page_hash; Enclave = $enclave; } if ($elam) { $certs = [NtApiDotNet.Win32.Security.Authenticode.AuthenticodeUtils]::GetElamInformation($path, $false) if ($certs.IsSuccess) { $props["ElamCerts"] = $certs.Result } } if ($ium) { $policy = [NtApiDotNet.Win32.Security.Authenticode.ImagePolicyMetadata]::CreateFromFile($Path, $false) if ($policy.IsSuccess) { $props["TrustletPolicy"] = $policy.Result } } if ($ium -or $enclave) { $enclave = [NtApiDotNet.Win32.Security.Authenticode.AuthenticodeUtils]::GetEnclaveConfiguration($path, $false) if ($enclave.IsSuccess) { $props["EnclaveConfig"] = $enclave.Result $props["EnclavePrimaryImage"] = $enclave.Result.PrimaryImage $props["Enclave"] = $true } } $obj = New-Object –TypeName PSObject –Prop $props Write-Output $obj } } |