NtSectionFunctions.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 Create a new image section based on an existing file. .DESCRIPTION This cmdlet creates an image section based on an existing file. .PARAMETER File A file object to an image file to create. .PARAMETER Path A path to an image to create. .PARAMETER Win32Path Resolve path as a Win32 path .PARAMETER ObjectPath Specify an object path for the new section object. .INPUTS None .OUTPUTS NtApiDotNet.NtSection .EXAMPLE New-NtSectionImage -Path \??\c:\windows\notepad.exe Creates a .EXAMPLE New-NtSectionImage -File $file Creates a new image section from an open NtFile object. #> function New-NtSectionImage { [CmdletBinding(DefaultParameterSetName = "FromFile")] Param( [Parameter(Position = 0, ParameterSetName = "FromFile", Mandatory = $true)] [NtApiDotNet.NtFile]$File, [Parameter(Position = 0, ParameterSetName = "FromPath", Mandatory = $true)] [string]$Path, [Parameter(ParameterSetName = "FromPath")] [switch]$Win32Path, [string]$ObjectPath ) if ($null -eq $File) { if ($Win32Path) { $Path = Get-NtFilePath $Path -Resolve } Use-NtObject($new_file = Get-NtFile -Path $Path -Share Read, Delete -Access GenericExecute) { return [NtApiDotNet.NtSection]::CreateImageSection($ObjectPath, $new_file) } } else { return [NtApiDotNet.NtSection]::CreateImageSection($ObjectPath, $File) } } <# .SYNOPSIS Displays a mapped section in a UI. .DESCRIPTION This cmdlet displays a section object inside a UI from where the data can be inspected or edited. .PARAMETER Section Specify a section object. .PARAMETER Wait Optionally wait for the user to close the UI. .PARAMETER ReadOnly Optionally force the viewer to be read-only when passing a section with Map Write access. .PARAMETER Path Path to a file to view as a section. .PARAMETER ObjPath Path to a object name to view as a section. .OUTPUTS None .EXAMPLE Show-NtSection $section Show the mapped section. .EXAMPLE Show-NtSection $section -ReadOnly Show the mapped section as read only. .EXAMPLE Show-NtSection $section -Wait Show the mapped section and wait for the viewer to exit. .EXAMPLE Show-NtSection ([byte[]]@(0, 1, 2, 3)) Show an arbitrary byte array in the viewer. .EXAMPLE Show-NtSection path\to\file.bin Show an arbitrary file in the viewer. #> function Show-NtSection { [CmdletBinding(DefaultParameterSetName = "FromSection")] Param( [Parameter(Position = 0, Mandatory = $true, ParameterSetName = "FromSection")] [NtApiDotNet.NtSection]$Section, [Parameter(ParameterSetName = "FromSection")] [switch]$ReadOnly, [Parameter(Position = 0, Mandatory = $true, ParameterSetName = "FromData")] [byte[]]$Data, [Parameter(Position = 0, Mandatory = $true, ParameterSetName = "FromFile")] [string]$Path, [Parameter(Position = 0, Mandatory = $true, ParameterSetName = "FromPath")] [string]$ObjPath, [switch]$Wait ) switch ($PSCmdlet.ParameterSetName) { "FromSection" { if (!$Section.IsAccessGranted("MapRead")) { Write-Error "Section doesn't have Map Read access." return } Use-NtObject($obj = $Section.Duplicate()) { $obj.Inherit = $true $cmdline = [string]::Format("EditSection --handle {0}", $obj.Handle.DangerousGetHandle()) if ($ReadOnly) { $cmdline += " --readonly" } $config = New-Win32ProcessConfig $cmdline -ApplicationName "$PSScriptRoot\EditSection.exe" -InheritHandles $config.InheritHandleList.Add($obj.Handle.DangerousGetHandle()) Use-NtObject($p = New-Win32Process -Config $config) { if ($Wait) { $p.Process.Wait() | Out-Null } } } } "FromData" { if ($Data.Length -eq 0) { return } $tempfile = New-TemporaryFile $path = $tempfile.FullName [System.IO.File]::WriteAllBytes($path, $Data) Use-NtObject($p = New-Win32Process "EditSection --delete --file=""$path""" -ApplicationName "$PSScriptRoot\EditSection.exe") { if ($Wait) { $p.Process.Wait() | Out-Null } } } "FromFile" { $Path = Resolve-Path $Path if ($Path -ne "") { Use-NtObject($p = New-Win32Process "EditSection --file=""$Path""" -ApplicationName "$PSScriptRoot\EditSection.exe") { if ($Wait) { $p.Process.Wait() | Out-Null } } } } "FromPath" { Use-NtObject($p = New-Win32Process "EditSection --path=""$ObjPath""" -ApplicationName "$PSScriptRoot\EditSection.exe") { if ($Wait) { $p.Process.Wait() | Out-Null } } } } } <# .SYNOPSIS Get a mapped view of a section. .DESCRIPTION This cmdlet calls the Map method on a section to map it into memory. .PARAMETER Section The section object to map. .PARAMETER Protection The protection of the mapping. .PARAMETER Process Optional process to map the section into. Default is the current process. .PARAMETER ViewSize The size of the view to map, 0 means map the entire section. .PARAMETER BaseAddress Base address for the mapping, 0 means pick a location. .PARAMETER ZeroBits The number of zero bits in the mapping address. .PARAMETER CommitSize The size of memory to commit from the section. .PARAMETER SectionOffset Offset into the section for the base address. .PARAMETER SectionInherit Inheritance flags for the section. .PARAMETER AllocationType The allocation type for the mapping. .OUTPUTS NtApiDotNet.NtMappedSection - The mapped section. .EXAMPLE Add-NtSection -Section $sect -Protection ReadWrite Map the section as Read/Write. .EXAMPLE Add-NtSection -Section $sect -Protection ReadWrite -ViewSize 4096 Map the first 4096 bytes of the section as Read/Write. .EXAMPLE Add-NtSection -Section $sect -Protection ReadWrite -SectionOffset (64*1024) Map the section starting from offset 64k. #> function Add-NtSection { Param( [parameter(Mandatory, Position = 0)] [NtApiDotNet.NtSection]$Section, [parameter(Mandatory, Position = 1)] [NtApiDotNet.MemoryAllocationProtect]$Protection, [NtApiDotNet.NtProcess]$Process, [IntPtr]$ViewSize = 0, [IntPtr]$BaseAddress = 0, [IntPtr]$ZeroBits = 0, [IntPtr]$CommitSize = 0, [NtApiDotNet.LargeInteger]$SectionOffset, [NtApiDotNet.SectionInherit]$SectionInherit = [NtApiDotNet.SectionInherit]::ViewUnmap, [NtApiDotNet.AllocationType]$AllocationType = "None" ) if ($null -eq $Process) { $Process = Get-NtProcess -Current } $Section.Map($Process, $Protection, $ViewSize, $BaseAddress, ` $ZeroBits, $CommitSize, $SectionOffset, ` $SectionInherit, $AllocationType) | Write-Output } Set-Alias -Name Get-NtMappedSection -Value Add-NtSection <# .SYNOPSIS Unmap a view of a section. .DESCRIPTION This cmdlet unmaps a section from virtual memory. .PARAMETER Mapping The mapping to unmap. .PARAMETER Address The address to unmap. .PARAMETER Process Optional process to unmap from. Default is the current process. .PARAMETER Flags Optional flags for unmapping. .OUTPUTS None .EXAMPLE Remove-NtSection -Mapping $map Unmap an existing section created with Add-NtSection. .EXAMPLE Remove-NtSection -Address $addr Unmap an address .EXAMPLE Remove-NtSection -Address $addr -Process $p Unmap an address in a specified process. #> function Remove-NtSection { [CmdletBinding(DefaultParameterSetName = "FromMapping")] Param( [parameter(Mandatory, Position = 0, ParameterSetName = "FromMapping")] [NtApiDotNet.NtMappedSection]$Mapping, [parameter(Mandatory, Position = 0, ParameterSetName = "FromAddress")] [int64]$Address, [parameter(Position = 1, ParameterSetName = "FromAddress")] [NtApiDotNet.NtProcess]$Process, [parameter(ParameterSetName = "FromAddress")] [NtApiDotNet.MemUnmapFlags]$Flags = 0 ) switch ($PsCmdlet.ParameterSetName) { "FromMapping" { $Mapping.Dispose() } "FromAddress" { if ($null -eq $Process) { $Process = Get-NtProcess -Current } $Process.Unmap($Address, $Flags) } } } <# .SYNOPSIS Get the cached signing level for a file. .DESCRIPTION This cmdlet gets the cached signing level for a specified file. .PARAMETER Path The file to get the cached signing level from. .PARAMETER Win32Path Specify to treat Path as a Win32 path. .PARAMETER FromEa Specify whether to the read the cached signing level from the extended attribute. .OUTPUTS NtApiDotNet.CachedSigningLevel .EXAMPLE Get-NtCachedSigningLevel \??\c:\path\to\file.dll Get the cached signing level from \??\c:\path\to\file.dll .EXAMPLE Get-NtCachedSigningLevel c:\path\to\file.dll -Win32Path Get the cached signing level from c:\path\to\file.dll converting from a win32 path. .EXAMPLE Get-NtCachedSigningLevel \??\c:\path\to\file.dll -FromEa Get the cached signing level from \??\c:\path\to\file.dll using the extended attribute. #> function Get-NtCachedSigningLevel { Param( [parameter(Position = 0, Mandatory)] [string]$Path, [switch]$Win32Path, [switch]$FromEa ) $access = if ($FromEa) { [NtApiDotNet.FileAccessRights]::ReadEa } else { [NtApiDotNet.FileAccessRights]::ReadData } Use-NtObject($f = Get-NtFile $Path -Win32Path:$Win32Path -Access $access -ShareMode Read) { if ($FromEa) { $f.GetCachedSigningLevelFromEa(); } else { $f.GetCachedSigningLevel() } } } <# .SYNOPSIS Set the cached signing level for a file. .DESCRIPTION This cmdlet sets the cached signing level for a specified file. .PARAMETER Path The file to set the cached signing level on. .PARAMETER Win32Path Specify to treat Path as a Win32 path. .PARAMETER Flags Specify the flags for the cache operation. .PARAMETER SigningLevel Specify the signing level for the cache operation. .PARAMETER AdditionalFiles Specify the additional files for the cache operation. .PARAMETER CatalogPath Specify the catalog path for the cache operation. .PARAMETER PassThru Specify to return the cached signing level. INPUTS None .OUTPUTS NtApiDotNet.CachedSigningLevel .EXAMPLE Set-NtCachedSigningLevel \??\c:\path\to\file.dll Set the cached signing level to \??\c:\path\to\file.dll .EXAMPLE Set-NtCachedSigningLevel c:\path\to\file.dll -Win32Path Set the cached signing level to \??\c:\path\to\file.dll #> function Set-NtCachedSigningLevel { Param( [parameter(Position = 0, Mandatory)] [string]$Path, [switch]$Win32Path, [int]$Flags = 4, [NtApiDotNet.SigningLevel]$SigningLevel = 0, [NtApiDotnet.NtFile[]]$AdditionalFiles, [string]$CatalogPath, [switch]$PassThru ) Use-NtObject($f = Get-NtFile $Path -Win32Path:$Win32Path -Access ReadData -ShareMode Read, Delete) { $f.SetCachedSigningLevel($Flags, $SigningLevel, $AdditionalFiles, $CatalogPath) if ($PassThru) { $f.GetCachedSigningLevel() } } } <# .SYNOPSIS Gets the signing level for an image file. .DESCRIPTION This cmdlet gets the signing level for an image file. .PARAMETER Path Specify the path to the image file. .PARAMETER Win32Path Specify that the path is a Win32 path. .PARAMETER DontResolve Specify to not try and resolve the signing level. .INPUTS None .OUTPUTS NtApiDotNet.SigningLevel #> function Get-NtSigningLevel { [CmdletBinding(DefaultParameterSetName="FromPath")] param( [Parameter(Position = 0, Mandatory, ParameterSetName="FromPath")] [string]$Path, [Parameter(ParameterSetName="FromPath")] [switch]$Win32Path, [switch]$DontResolve ) try { if ($Win32Path) { $Path = Get-NtFilePath -Path $Path } Use-NtObject($sect = New-NtSectionImage -Path $Path) { Use-NtObject($map = $sect.MapRead()) { if ($map.ImageSigningLevel -ne "Unchecked" -or $DontResolve) { return $map.ImageSigningLevel } $script = { Set-NtProcessMitigationPolicy -Signature AuditMicrosoftSignedOnly [NtObjectManager.Utils.PSUtils]::GetSigningLevel($input) | Out-Null } $job = Start-Job -ScriptBlock $script -InputObject $Path Wait-Job $job | Out-Null return $map.ImageSigningLevel } } } catch { Write-Error $_ } } <# .SYNOPSIS Compares two signing levels to see which is higher. .DESCRIPTION This cmdlet compares two signing levels to see which is higher. .PARAMETER .INPUTS None .OUTPUTS Bool .EXAMPLE Compare-NtSigningLevel -Left Windows -Right WindowsTCB Compare two signing levels, returns True if the left level is greater or equal to right. #> function Compare-NtSigningLevel { param( [parameter(Mandatory, Position = 0)] [NtApiDotNet.SigningLevel]$Left, [parameter(Mandatory, Position = 1)] [NtApiDotNet.SigningLevel]$Right ) [NtApiDotNet.NtSecurity]::CompareSigningLevel($Left, $Right) } |