RpcFunctions.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. $protseq_completer = { param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) @("ncalrpc", "ncacn_np", "ncacn_ip_tcp", "ncacn_http") | Where-Object { $_ -like "$wordToComplete*" } } <# .SYNOPSIS Get a list of ALPC Ports that can be opened by a specified token. .DESCRIPTION This cmdlet checks for all ALPC ports on the system and tries to determine if one or more specified tokens can connect to them. If no tokens are specified then the current process token is used. This function searches handles for existing ALPC Port servers as you can't directly open the server object and just connecting might show inconsistent results. .PARAMETER ProcessId Specify a list of process IDs to open for their tokens. .PARAMETER ProcessName Specify a list of process names to open for their tokens. .PARAMETER ProcessCommandLine Specify a list of command lines to filter on find for the process tokens. .PARAMETER Token Specify a list token objects. .PARAMETER Process Specify a list process objects to use for their tokens. .INPUTS None .OUTPUTS NtObjectManager.Cmdlets.Accessible.CommonAccessCheckResult .NOTES For best results run this function as an administrator with SeDebugPrivilege available. .EXAMPLE Get-AccessibleAlpcPort Get all ALPC Ports connectable by the current token. .EXAMPLE Get-AccessibleAlpcPort -ProcessIds 1234,5678 Get all ALPC Ports connectable by the process tokens of PIDs 1234 and 5678 #> function Get-AccessibleAlpcPort { Param( [alias("ProcessIds")] [Int32[]]$ProcessId, [alias("ProcessNames")] [string[]]$ProcessName, [alias("ProcessCommandLines")] [string[]]$ProcessCommandLine, [alias("Tokens")] [NtApiDotNet.NtToken[]]$Token, [alias("Processes")] [NtApiDotNet.NtProcess[]]$Process ) $access = Get-NtAccessMask -AlpcPortAccess Connect -ToGenericAccess Get-AccessibleObject -FromHandle -ProcessId $ProcessId -ProcessName $ProcessName ` -ProcessCommandLine $ProcessCommandLine -Token $Token -Process $Process -TypeFilter "ALPC Port" -AccessRights $access } <# .SYNOPSIS Gets the endpoints for a RPC interface from the local endpoint mapper or by brute force. .DESCRIPTION This cmdlet gets the endpoints for a RPC interface from the local endpoint mapper. Not all RPC interfaces are registered in the endpoint mapper so it might not show. You can use the -FindAlpcPort command to try and brute force an ALPC port for the interface. .PARAMETER InterfaceId The UUID of the RPC interface. .PARAMETER InterfaceVersion The version of the RPC interface. .PARAMETER Server Parsed NDR server. .PARAMETER Binding A RPC binding string to query all endpoints from. .PARAMETER AlpcPort An ALPC port name. Can contain a full path as long as the string contains \RPC Control\ (case sensitive). .PARAMETER FindAlpcPort Use brute force to find a valid ALPC endpoint for the interface. .PARAMETER ProcessId Used to find all ALPC ports in a process and get the supported interfaces. .INPUTS None or NtApiDotNet.Ndr.NdrRpcServerInterface .OUTPUTS NtApiDotNet.Win32.RpcEndpoint[] .EXAMPLE Get-RpcEndpoint Get all RPC registered RPC endpoints. .EXAMPLE Get-RpcEndpoint $Server Get RPC endpoints for a parsed NDR server interface. .EXAMPLE Get-RpcEndpoint "A57A4ED7-0B59-4950-9CB1-E600A665154F" Get RPC endpoints for a specified interface ID ignoring the version. .EXAMPLE Get-RpcEndpoint "A57A4ED7-0B59-4950-9CB1-E600A665154F" "1.0" Get RPC endpoints for a specified interface ID and version. .EXAMPLE Get-RpcEndpoint "A57A4ED7-0B59-4950-9CB1-E600A665154F" "1.0" -FindAlpcPort Get ALPC RPC endpoints for a specified interface ID and version by brute force. .EXAMPLE Get-RpcEndpoint -Binding "ncalrpc:[RPC_PORT]" Get RPC endpoints for exposed over ncalrpc with name RPC_PORT. .EXAMPLE Get-RpcEndpoint -AlpcPort "RPC_PORT" Get RPC endpoints for exposed over ALPC with name RPC_PORT. .EXAMPLE Get-RpcEndpoint -ProcessId 1234 Get RPC endpoints for exposed over ALPC for the process 1234. #> function Get-RpcEndpoint { [CmdletBinding(DefaultParameterSetName = "All")] Param( [parameter(Mandatory, Position = 0, ParameterSetName = "FromId")] [parameter(Mandatory, Position = 0, ParameterSetName = "FromIdAndVersion")] [Guid]$InterfaceId, [parameter(Mandatory, Position = 1, ParameterSetName = "FromIdAndVersion")] [Version]$InterfaceVersion, [parameter(Mandatory, ParameterSetName = "FromServer", ValueFromPipeline)] [NtApiDotNet.Ndr.NdrRpcServerInterface]$Server, [parameter(Mandatory, ParameterSetName = "FromBinding")] [string]$Binding, [parameter(Mandatory, ParameterSetName = "FromAlpc")] [string]$AlpcPort, [parameter(Mandatory, ParameterSetName = "FromProcessId")] [alias("pid")] [int]$ProcessId, [parameter(Mandatory, ParameterSetName = "FromServiceName")] [string]$ServiceName, [parameter(ParameterSetName = "FromIdAndVersion")] [parameter(ParameterSetName = "FromServer")] [switch]$FindAlpcPort, [parameter(ParameterSetName = "All")] [parameter(ParameterSetName = "FromId")] [parameter(ParameterSetName = "FromIdAndVersion")] [parameter(ParameterSetName = "FromRpcClient")] [string]$SearchBinding = "", [parameter(ParameterSetName = "All")] [parameter(ParameterSetName = "FromId")] [parameter(ParameterSetName = "FromIdAndVersion")] [parameter(ParameterSetName = "FromRpcClient")] [string[]]$ProtocolSequence = @(), [parameter(Mandatory, ParameterSetName = "FromRpcClient")] [NtApiDotNet.Win32.Rpc.RpcClientBase]$Client ) PROCESS { $eps = switch ($PsCmdlet.ParameterSetName) { "All" { [NtApiDotNet.Win32.RpcEndpointMapper]::QueryEndpoints($SearchBinding) } "FromId" { [NtApiDotNet.Win32.RpcEndpointMapper]::QueryEndpoints($SearchBinding, $InterfaceId) } "FromIdAndVersion" { if ($FindAlpcPort) { [NtApiDotNet.Win32.RpcEndpointMapper]::FindAlpcEndpointForInterface($InterfaceId, $InterfaceVersion) } else { [NtApiDotNet.Win32.RpcEndpointMapper]::QueryEndpoints($SearchBinding, $InterfaceId, $InterfaceVersion) } } "FromServer" { if ($FindAlpcPort) { [NtApiDotNet.Win32.RpcEndpointMapper]::FindAlpcEndpointForInterface($Server.InterfaceId, $Server.InterfaceVersion) } else { [NtApiDotNet.Win32.RpcEndpointMapper]::QueryEndpoints($Server) } } "FromBinding" { [NtApiDotNet.Win32.RpcEndpointMapper]::QueryEndpointsForBinding($Binding) } "FromAlpc" { [NtApiDotNet.Win32.RpcEndpointMapper]::QueryEndpointsForAlpcPort($AlpcPort) } "FromRpcClient" { [NtApiDotNet.Win32.RpcEndpointMapper]::QueryEndpoints($SearchBinding, $Client.InterfaceId, $Client.InterfaceVersion) } "FromProcessId" { (Get-RpcAlpcServer -ProcessId $ProcessId).Endpoints } "FromServiceName" { try { $service = Get-Win32Service -Name $ServiceName if ($service.ProcessId -eq 0) { throw "Service $ServiceName is not running." } Get-RpcEndPoint -ProcessId $service.ProcessId } catch { Write-Error $_ } } } if ($ProtocolSequence.Count -gt 0) { $eps = $eps | Where-Object {$_.ProtocolSequence -in $ProtocolSequence} } $eps | Write-Output } } Register-ArgumentCompleter -CommandName Get-RpcEndpoint -ParameterName ProtocolSequence -ScriptBlock $protseq_completer <# .SYNOPSIS Get the RPC servers from a DLL. .DESCRIPTION This cmdlet parses the RPC servers from a DLL. Note that in order to parse 32 bit DLLs you must run this module in 32 bit PowerShell. .PARAMETER FullName The path to the DLL. .PARAMETER DbgHelpPath Specify path to a dbghelp DLL to use for symbol resolving. This should be ideally the dbghelp from debugging tool for Windows which will allow symbol servers however you can use the system version if you just want to pull symbols locally. .PARAMETER SymbolPath Specify path for the symbols. If not specified it will first use the _NT_SYMBOL_PATH environment variable then use the default of 'srv*https://msdl.microsoft.com/download/symbols' .PARAMETER AsText Return the results as text rather than objects. .PARAMETER RemoveComments When outputing as text remove comments from the output. .PARAMETER ParseClients Also parse client interface information, otherwise only servers are returned. .PARAMETER IgnoreSymbols Don't resolve any symbol information. .PARAMETER SerializedPath Path to a serialized representation of the RPC servers. .PARAMETER ResolveStructureNames If private symbols available try and resolve the names of structures and parameters. .PARAMETER SymSrvFallback Specify to use a built-in fallback for symbol server resolving when using the system dbghelp DLL. You also need to specify a local cache directory in SymbolPath. .PARAMETER ProcessId Specify a process to extract the RPC servers from. This parses all the modules in a process for any available servers. .PARAMETER ServiceName Specify the name of a service to extract the RPC servers from. .INPUTS string[] List of paths to DLLs. .OUTPUTS RpcServer[] The parsed RPC servers. .EXAMPLE Get-RpcServer c:\windows\system32\rpcss.dll Get the list of RPC servers from rpcss.dll. .EXAMPLE Get-RpcServer c:\windows\system32\rpcss.dll -AsText Get the list of RPC servers from rpcss.dll, return it as text. .EXAMPLE Get-ChildItem c:\windows\system32\*.dll | Get-RpcServer Get the list of RPC servers from all DLLs in system32, return it as text. .EXAMPLE Get-RpcServer c:\windows\system32\rpcss.dll -DbgHelpPath c:\windbg\x64\dbghelp.dll Get the list of RPC servers from rpcss.dll, specifying a different DBGHELP for symbol resolving. .EXAMPLE Get-RpcServer c:\windows\system32\rpcss.dll -SymbolPath c:\symbols Get the list of RPC servers from rpcss.dll, specifying a different symbol path. .EXAMPLE Get-RpcServer -SerializedPath rpc.bin Get the list of RPC servers from the serialized file rpc.bin. .EXAMPLE Get-RpcServer c:\windows\system32\rpcss.dll -SymSrvFallback -SymbolPath c:\symbols Get the list of RPC servers from rpcss.dll, use symbol server fallback with c:\symbols as the cache directory. #> function Get-RpcServer { [CmdletBinding(DefaultParameterSetName = "FromDll")] Param( [parameter(Mandatory, Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName, ParameterSetName = "FromDll")] [alias("Path")] [string]$FullName, [parameter(Mandatory, ParameterSetName = "FromSerialized")] [string]$SerializedPath, [parameter(Mandatory, ParameterSetName = "FromProcessId")] [alias("pid")] [int]$ProcessId, [parameter(Mandatory, ParameterSetName = "FromServiceName")] [string]$ServiceName, [parameter(ParameterSetName = "FromDll")] [parameter(ParameterSetName = "FromProcessId")] [parameter(ParameterSetName = "FromServiceName")] [string]$DbgHelpPath, [parameter(ParameterSetName = "FromDll")] [parameter(ParameterSetName = "FromProcessId")] [parameter(ParameterSetName = "FromServiceName")] [string]$SymbolPath, [parameter(ParameterSetName = "FromDll")] [switch]$ParseClients, [parameter(ParameterSetName = "FromDll")] [parameter(ParameterSetName = "FromProcessId")] [parameter(ParameterSetName = "FromServiceName")] [switch]$IgnoreSymbols, [parameter(ParameterSetName = "FromDll")] [parameter(ParameterSetName = "FromProcessId")] [parameter(ParameterSetName = "FromServiceName")] [switch]$ResolveStructureNames, [parameter(ParameterSetName = "FromDll")] [parameter(ParameterSetName = "FromProcessId")] [parameter(ParameterSetName = "FromServiceName")] [switch]$SymSrvFallback, [switch]$AsText, [switch]$RemoveComments ) BEGIN { if ($DbgHelpPath -eq "") { $DbgHelpPath = $Script:GlobalDbgHelpPath } if ($SymbolPath -eq "") { $SymbolPath = $env:_NT_SYMBOL_PATH if ($SymbolPath -eq "") { $SymbolPath = $Script:GlobalSymbolPath } } $ParserFlags = [NtApiDotNet.Win32.RpcServerParserFlags]::None if ($ParseClients) { $ParserFlags = $ParserFlags -bor [NtApiDotNet.Win32.RpcServerParserFlags]::ParseClients } if ($IgnoreSymbols) { $ParserFlags = $ParserFlags -bor [NtApiDotNet.Win32.RpcServerParserFlags]::IgnoreSymbols } if ($ResolveStructureNames) { $ParserFlags = $ParserFlags -bor [NtApiDotNet.Win32.RpcServerParserFlags]::ResolveStructureNames } if ($SymSrvFallback) { $ParserFlags = $ParserFlags -bor [NtApiDotNet.Win32.RpcServerParserFlags]::SymSrvFallback } } PROCESS { try { $servers = switch($PSCmdlet.ParameterSetName) { "FromDll" { $FullName = Resolve-Path -LiteralPath $FullName -ErrorAction Stop Write-Progress -Activity "Parsing RPC Servers" -CurrentOperation "$FullName" [NtApiDotNet.Win32.RpcServer]::ParsePeFile($FullName, $DbgHelpPath, $SymbolPath, $ParserFlags) } "FromSerialized" { $FullName = Resolve-Path -LiteralPath $SerializedPath -ErrorAction Stop Use-NtObject($stm = [System.IO.File]::OpenRead($FullName)) { while ($stm.Position -lt $stm.Length) { [NtApiDotNet.Win32.RpcServer]::Deserialize($stm) | Write-Output } } } "FromProcessId" { $proc = Get-Process -PID $ProcessId if ($null -eq $proc.SafeHandle) { throw "Can't open process $ProcessId" } $proc.Modules | % { Get-RpcServer -FullName $_.FileName -DbgHelpPath $DbgHelpPath -SymbolPath $SymbolPath ` -IgnoreSymbols:$IgnoreSymbols -ResolveStructureNames:$ResolveStructureNames -SymSrvFallback:$SymSrvFallback } } "FromServiceName" { $service = Get-Win32Service -Name $ServiceName if ($service.ProcessId -eq 0) { throw "Service $ServiceName is not running." } else { Get-RpcServer -ProcessId $service.ProcessId -DbgHelpPath $DbgHelpPath -SymbolPath $SymbolPath ` -IgnoreSymbols:$IgnoreSymbols -ResolveStructureNames:$ResolveStructureNames -SymSrvFallback:$SymSrvFallback } } } if ($null -ne $servers) { if ($AsText) { foreach ($server in $servers) { $text = $server.FormatAsText($RemoveComments) Write-Output $text } } else { Write-Output $servers } } } catch { Write-Error $_ } } } <# .SYNOPSIS Set a list RPC servers to a file for storage. .DESCRIPTION This cmdlet serializes a list of RPC servers to a file. This can be restored using Get-RpcServer -SerializedPath. .PARAMETER Path The path to the output file. .PARAMETER Server The list of servers to serialize. .INPUTS RpcServer[] List of paths to DLLs. .OUTPUTS None .EXAMPLE Set-RpcServer -Server $server -Path rpc.bin Serialize servers to file rpc.bin. #> function Set-RpcServer { Param( [parameter(Mandatory = $true, Position = 0, ValueFromPipeline)] [NtApiDotNet.Win32.RpcServer[]]$Server, [parameter(Mandatory = $true, Position = 1)] [string]$Path ) BEGIN { "" | Set-Content -Path $Path $Path = Resolve-Path -LiteralPath $Path -ErrorAction Stop $stm = [System.IO.File]::Create($Path) } PROCESS { try { foreach ($s in $Server) { $s.Serialize($stm) } } catch { Write-Error $_ } } END { $stm.Close() } } <# .SYNOPSIS Format the RPC servers as text. .DESCRIPTION This cmdlet formats a list of RPC servers as text. .PARAMETER RpcServer The RPC servers to format. .PARAMETER RemoveComments When outputing as text remove comments from the output. .PARAMETER CppFormat Format output in C++ pseudo syntax rather than C++. .INPUTS RpcServer[] The RPC servers to format. .OUTPUTS string[] The formatted RPC servers. .EXAMPLE Format-RpcServer $rpc Format list of RPC servers in $rpc. .EXAMPLE Format-RpcServer $rpc -RemoveComments Format list of RPC servers in $rpc without comments. .EXAMPLE Get-RpcServer c:\windows\system32\rpcss.dll | Format-RpcServer Get the list of RPC servers from rpcss.dll and format them. #> function Format-RpcServer { [CmdletBinding()] Param( [parameter(Mandatory = $true, Position = 0, ValueFromPipeline)] [NtApiDotNet.Win32.RpcServer[]]$RpcServer, [switch]$RemoveComments, [switch]$CppFormat ) PROCESS { foreach ($server in $RpcServer) { $server.FormatAsText($RemoveComments, $CppFormat) | Write-Output } } } <# .SYNOPSIS Gets a list of ALPC RPC servers. .DESCRIPTION This cmdlet gets a list of ALPC RPC servers. This relies on being able to access the list of ALPC ports in side a process so might need elevated privileges. .PARAMETER ProcessId The ID of a process to query for ALPC servers. .PARAMETER AlpcPort The path to the ALPC port to query. .PARAMETER IgnoreComInterface Ignore COM only interfaces. .INPUTS None .OUTPUTS NtApiDotNet.Win32.RpcAlpcServer[] .EXAMPLE Get-RpcAlpcServer Get all ALPC RPC servers. .EXAMPLE Get-RpcAlpcServer -ProcessId 1234 Get all ALPC RPC servers in process ID 1234. .EXAMPLE Get-RpcAlpcServer -AlpcPort srvsvc Get the ALPC RPC servers for the srvsvc ALPC port. Needs Windows 10 19H1 and above to work. #> function Get-RpcAlpcServer { [CmdletBinding(DefaultParameterSetName = "All")] Param( [parameter(Mandatory, Position = 0, ParameterSetName = "FromProcessId")] [int]$ProcessId, [parameter(Mandatory, ParameterSetName = "FromAlpc")] [string]$AlpcPort, [switch]$IgnoreComInterface ) Set-NtTokenPrivilege SeDebugPrivilege | Out-Null switch ($PsCmdlet.ParameterSetName) { "All" { [NtApiDotNet.Win32.RpcAlpcServer]::GetAlpcServers($IgnoreComInterface) } "FromProcessId" { [NtApiDotNet.Win32.RpcAlpcServer]::GetAlpcServers($ProcessId, $IgnoreComInterface) } "FromAlpc" { [NtApiDotNet.Win32.RpcAlpcServer]::GetAlpcServer($AlpcPort, $IgnoreComInterface) } } } <# .SYNOPSIS Get a RPC client object based on a parsed RPC server. .DESCRIPTION This cmdlet creates a new RPC client from a parsed RPC server. The client object contains methods to call RPC methods. The client starts off disconnected. You need to pass the client to Connect-RpcClient to connect to the server. If you specify an interface ID and version then a generic client will be created which allows simple calls to be made without requiring the NDR data. .PARAMETER Server Specify the RPC server to base the client on. .PARAMETER NamespaceName Specify the name of the compiled namespace for the client. .PARAMETER ClientName Specify the class name of the compiled client. .PARAMETER IgnoreCache Specify to ignore the compiled client cache and regenerate the source code. .PARAMETER InterfaceId Specify the interface ID for a generic client. .PARAMETER InterfaceVersion Specify the interface version for a generic client. .PARAMETER Provider Specify a Code DOM provider. Defaults to C#. .PARAMETER Flags Specify optional flags for the built client class. .PARAMETER EnableDebugging Specify to enable debugging on the compiled code. .PARAMETER UseAddType Specify to try and use the Add-Type command instead of the C# compiler to build the client. .INPUTS None .OUTPUTS NtApiDotNet.Win32.Rpc.RpcClientBase .EXAMPLE Get-RpcClient -Server $Server Create a new RPC client from a parsed RPC server. #> function Get-RpcClient { [CmdletBinding(DefaultParameterSetName = "FromServer")] Param( [parameter(Mandatory, Position = 0, ParameterSetName = "FromServer", ValueFromPipeline)] [NtApiDotNet.Win32.RpcServer]$Server, [parameter(ParameterSetName = "FromServer")] [string]$NamespaceName, [parameter(ParameterSetName = "FromServer")] [string]$ClientName, [parameter(ParameterSetName = "FromServer")] [switch]$IgnoreCache, [parameter(Mandatory, Position = 0, ParameterSetName = "FromIdAndVersion")] [string]$InterfaceId, [parameter(Mandatory, Position = 1, ParameterSetName = "FromIdAndVersion")] [Version]$InterfaceVersion, [parameter(ParameterSetName = "FromServer")] [System.CodeDom.Compiler.CodeDomProvider]$Provider, [parameter(ParameterSetName = "FromServer")] [NtApiDotNet.Win32.Rpc.RpcClientBuilderFlags]$Flags = "GenerateConstructorProperties, StructureReturn, HideWrappedMethods, UnsignedChar, NoNamespace, MarshalPipesAsArrays", [switch]$EnableDebugging, [switch]$UseAddType ) BEGIN { if (Get-IsPSCore) { if ($null -ne $Provider) { Write-Warning "PowerShell Core doesn't support arbitrary providers. Using in-built C#." } if ([NtObjectManager.Utils.CoreCSharpCodeProvider]::IsSupported) { $Provider = New-Object NtObjectManager.Utils.CoreCSharpCodeProvider } else { $UseAddType = $true } } if ($UseAddType) { $Flags = $Flags -band (-bnot [NtApiDotNet.Win32.Rpc.RpcClientBuilderFlags]::NoNamespace) $flags = $Flags -bor [NtApiDotNet.Win32.Rpc.RpcClientBuilderFlags]::ExcludeVariableSourceText } } PROCESS { if ($PSCmdlet.ParameterSetName -eq "FromServer") { if ($UseAddType) { $src = Format-RpcClient -Server $Server -ClientName $ClientName -Flags $Flags $ts = Add-Type -TypeDefinition $src -ReferencedAssemblies "NtApiDotNet.dll",'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089','System.Collections, Version=0.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' -PassThru foreach($t in $ts) { if ($t.BaseType -eq [NtApiDotNet.Win32.Rpc.RpcClientBase]) { New-Object $t.AssemblyQualifiedName break } } } else { $args = [NtApiDotNet.Win32.Rpc.RpcClientBuilderArguments]::new(); $args.NamespaceName = $NamespaceName $args.ClientName = $ClientName $args.Flags = $Flags $args.EnableDebugging = $EnableDebugging [NtApiDotNet.Win32.Rpc.RpcClientBuilder]::CreateClient($Server, $args, $IgnoreCache, $Provider) } } else { [NtApiDotNet.Win32.RpcClient]::new($InterfaceId, $InterfaceVersion) } } } <# .SYNOPSIS Connects a RPC client to an endpoint. .DESCRIPTION This cmdlet connects a RPC client to an endpoint. You can specify what transport to use based on the protocol sequence. .PARAMETER Client Specify the RPC client to connect. .PARAMETER ProtocolSequence Specify the RPC protocol sequence this client will connect through. .PARAMETER EndpointPath Specify the endpoint string. If not specified this will lookup the endpoint from the endpoint mapper. .PARAMETER NetworkAddress Specify the network address. If not specified the local system will be used. .PARAMETER SecurityQualityOfService Specify the security quality of service for the connection. .PARAMETER Credentials Specify user credentials for the RPC client authentication. .PARAMETER ServicePrincipalName Specify service principal name for the RPC client authentication. .PARAMETER AuthenticationLevel Specify authentication level for the RPC client authentication. .PARAMETER AuthenticationType Specify authentication type for the RPC client authentication. .PARAMETER AuthenticationCapabilities Specify authentication capabilities for the RPC client authentication. .PARAMETER PassThru Specify to the pass the client object to the output. .PARAMETER FindAlpcPort Specify to search for an ALPC port for the RPC client. .PARAMETER Force Specify to for the client to connect even if the client is already connected to another transport. .PARAMETER Cache Specify a local kerberos ticket cache for use with Kerberos authentication. .PARAMETER Configuration Specify low-level transport configuration. .INPUTS NtApiDotNet.Win32.Rpc.RpcClientBase[] .OUTPUTS NtApiDotNet.Win32.Rpc.RpcClientBase[] .EXAMPLE Connect-RpcClient -Client $Client Connect an RPC ALPC client, looking up the path using the endpoint mapper. .EXAMPLE Connect-RpcClient -Client $Client -EndpointPath "\RPC Control\ABC" Connect an RPC ALPC client with an explicit path. .EXAMPLE Connect-RpcClient -Client $Client -SecurityQualityOfService $(New-NtSecurityQualityOfService -ImpersonationLevel Anonymous) Connect an RPC ALPC client with anonymous impersonation level. .EXAMPLE Connect-RpcClient -Client $Client -ProtocolSequence "ncalrpc" Connect an RPC ALPC client from a specific protocol sequence. .EXAMPLE Connect-RpcClient -Client $Client -Endpoint $ep Connect an RPC client to a specific endpoint. .EXAMPLE Connect-RpcClient -Client $Client -FindAlpcPort Connect an RPC ALPC client, looking up the path using brute force. #> function Connect-RpcClient { [CmdletBinding(DefaultParameterSetName = "FromProtocol")] Param( [parameter(Mandatory, Position = 0, ValueFromPipeline)] [NtApiDotNet.Win32.Rpc.RpcClientBase]$Client, [parameter(Position = 1, ParameterSetName = "FromProtocol")] [string]$EndpointPath, [parameter(ParameterSetName = "FromProtocol")] [string]$ProtocolSequence = "ncalrpc", [parameter(ParameterSetName = "FromProtocol")] [string]$NetworkAddress, [parameter(Position = 1, Mandatory, ParameterSetName = "FromEndpoint")] [NtApiDotNet.Win32.RpcEndpoint]$Endpoint, [parameter(Mandatory, ParameterSetName = "FromFindEndpoint")] [switch]$FindAlpcPort, [parameter(ParameterSetName = "FromBindingString")] [string]$StringBinding, [NtApiDotNet.SecurityQualityOfService]$SecurityQualityOfService, [NtApiDotNet.Win32.Security.Authentication.AuthenticationCredentials]$Credentials, [string]$ServicePrincipalName, [NtApiDotNet.Win32.Rpc.Transport.RpcAuthenticationLevel]$AuthenticationLevel = "None", [NtApiDotNet.Win32.Rpc.Transport.RpcAuthenticationType]$AuthenticationType = "None", [NtApiDotNet.Win32.Rpc.Transport.RpcAuthenticationCapabilities]$AuthenticationCapabilities = "None", [NtApiDotNet.Win32.Security.Authentication.Kerberos.Client.KerberosLocalTicketCache]$Cache, [NtApiDotNet.Win32.Rpc.Transport.RpcClientTransportConfiguration]$Configuration, [switch]$PassThru, [switch]$Force ) BEGIN { $security = New-Object NtApiDotNet.Win32.Rpc.Transport.RpcTransportSecurity $security.SecurityQualityOfService = $SecurityQualityOfService $security.Credentials = $Credentials $security.ServicePrincipalName = $ServicePrincipalName $security.AuthenticationLevel = $AuthenticationLevel $security.AuthenticationType = $AuthenticationType $security.AuthenticationCapabilities = $AuthenticationCapabilities $security.TicketCache = $Cache $security.Configuration = $Configuration } PROCESS { if ($Force) { Disconnect-RpcClient -Client $Client } switch ($PSCmdlet.ParameterSetName) { "FromProtocol" { $Client.Connect($ProtocolSequence, $EndpointPath, $NetworkAddress, $security) } "FromEndpoint" { $Client.Connect($Endpoint, $security) } "FromFindEndpoint" { foreach ($ep in $(Get-ChildItem "NtObject:\RPC Control")) { try { $name = $ep.Name Write-Progress -Activity "Finding ALPC Endpoint" -CurrentOperation "$name" $Client.Connect("ncalrpc", $name, $security) } catch { Write-Information $_ } } } "FromBindingString" { $Client.Connect($StringBinding, $security) } } if ($PassThru) { $Client | Write-Output } } } Register-ArgumentCompleter -CommandName Connect-RpcClient -ParameterName ProtocolSequence -ScriptBlock $protseq_completer <# .SYNOPSIS Disconnect an RPC client. .DESCRIPTION This cmdlet disconnects a RPC client from an endpoint. .PARAMETER Client Specify the RPC client to disconnect. .PARAMETER PassThru Specify to the pass the client object to the output. .INPUTS NtApiDotNet.Win32.Rpc.RpcClientBase[] .OUTPUTS NtApiDotNet.Win32.Rpc.RpcClientBase[] .EXAMPLE Disconnect-RpcClient -Client $Client Disconnect an RPC ALPC client. #> function Disconnect-RpcClient { [CmdletBinding()] Param( [parameter(Mandatory, Position = 0, ValueFromPipeline)] [NtApiDotNet.Win32.Rpc.RpcClientBase]$Client, [switch]$PassThru ) PROCESS { $Client.Disconnect() if ($PassThru) { $Client | Write-Output } } } <# .SYNOPSIS Format a RPC client as source code based on a parsed RPC server. .DESCRIPTION This cmdlet gets source code for a RPC client from a parsed RPC server. .PARAMETER Server Specify the RPC server to base the client on. .PARAMETER NamespaceName Specify the name of the compiled namespace for the client. .PARAMETER ClientName Specify the class name of the compiled client. .PARAMETER Flags Specify to flags for the source creation. .PARAMETER Provider Specify a Code DOM provider. Defaults to C#. .PARAMETER Options Specify optional options for the code generation if Provider is also specified. .PARAMETER OutputPath Specify optional output directory to write formatted client. .PARAMETER GroupByName Specify when outputting to a directory to group by the name of the server executable. .INPUTS None .OUTPUTS string .EXAMPLE Format-RpcClient -Server $Server Get the source code for a RPC client from a parsed RPC server. .EXAMPLE $servers | Format-RpcClient Get the source code for RPC clients from a list of parsed RPC servers. .EXAMPLE $servers | Format-RpcClient -OutputPath rpc_output Get the source code for RPC clients from a list of parsed RPC servers and output as separate source code files. #> function Format-RpcClient { [CmdletBinding()] Param( [parameter(Mandatory, Position = 0, ValueFromPipeline)] [NtApiDotNet.Win32.RpcServer[]]$Server, [string]$NamespaceName, [string]$ClientName, [NtApiDotNet.Win32.Rpc.RpcClientBuilderFlags]$Flags = 0, [System.CodeDom.Compiler.CodeDomProvider]$Provider, [System.CodeDom.Compiler.CodeGeneratorOptions]$Options, [string]$OutputPath, [switch]$GroupByName ) BEGIN { $file_ext = "cs" if ($null -ne $Provider) { $file_ext = $Provider.FileExtension } if ("" -ne $OutputPath) { mkdir $OutputPath -ErrorAction Ignore | Out-Null } } PROCESS { $args = [NtApiDotNet.Win32.Rpc.RpcClientBuilderArguments]::new(); $args.NamespaceName = $NamespaceName $args.ClientName = $ClientName $args.Flags = $Flags foreach ($s in $Server) { $src = if ($null -eq $Provider) { [NtApiDotNet.Win32.Rpc.RpcClientBuilder]::BuildSource($s, $args) } else { [NtApiDotNet.Win32.Rpc.RpcClientBuilder]::BuildSource($s, $args, $Provider, $Options) } if ("" -eq $OutputPath) { $src | Write-Output } else { if ($GroupByName) { $path = Join-Path -Path $OutputPath -ChildPath $s.Name.ToLower() mkdir $path -ErrorAction Ignore | Out-Null } else { $path = $OutputPath } $path = Join-Path -Path $path -ChildPath "$($s.InterfaceId)_$($s.InterfaceVersion).$file_ext" $src | Set-Content -Path $path } } } } <# .SYNOPSIS Format RPC complex types to an encoder/decoder source code file. .DESCRIPTION This cmdlet gets source code for encoding and decoding RPC complex types. .PARAMETER ComplexType Specify the list of complex types to format. .PARAMETER Server Specify the server containing the list of complex types to format. .PARAMETER NamespaceName Specify the name of the compiled namespace for the client. .PARAMETER EncoderName Specify the class name of the encoder. .PARAMETER DecoderName Specify the class name of the decoder. .PARAMETER Provider Specify a Code DOM provider. Defaults to C#. .PARAMETER Options Specify optional options for the code generation if Provider is also specified. .PARAMETER Pointer Specify to always wrap complex types in an unique pointer. .INPUTS None .OUTPUTS string .EXAMPLE Format-RpcComplexType -Server $Server Get the source code for RPC complex types client from a parsed RPC server. .EXAMPLE Format-RpcComplexType -ComplexType $ComplexTypes Get the source code for RPC complex types client from a list of types. #> function Format-RpcComplexType { [CmdletBinding(DefaultParameterSetName = "FromTypes")] Param( [parameter(Mandatory, Position = 0, ParameterSetName = "FromTypes")] [NtApiDotNet.Ndr.NdrComplexTypeReference[]]$ComplexType, [parameter(Mandatory, Position = 0, ParameterSetName = "FromServer")] [NtApiDotNet.Win32.RpcServer]$Server, [string]$NamespaceName, [string]$EncoderName, [string]$DecoderName, [System.CodeDom.Compiler.CodeDomProvider]$Provider, [System.CodeDom.Compiler.CodeGeneratorOptions]$Options, [switch]$Pointer ) PROCESS { $types = switch ($PsCmdlet.ParameterSetName) { "FromTypes" { $ComplexType } "FromServer" { $Server.ComplexTypes } } if ($null -eq $Provider) { [NtApiDotNet.Win32.Rpc.RpcClientBuilder]::BuildSource([NtApiDotNet.Ndr.NdrComplexTypeReference[]]$types, $EncoderName, $DecoderName, $NamespaceName, $Pointer) | Write-Output } else { [NtApiDotNet.Win32.Rpc.RpcClientBuilder]::BuildSource([NtApiDotNet.Ndr.NdrComplexTypeReference[]]$types, $EncoderName, $DecoderName, $NamespaceName, $Pointer, $Provider, $Options) | Write-Output } } } <# .SYNOPSIS Get a new RPC context handle. .DESCRIPTION This cmdlet creates a new RPC context handle for calling RPC APIs. .PARAMETER Uuid The UUID for the context handle. .PARAMETER Attributes The attribute flags for the context handle. .INPUTS None .OUTPUTS NtApiDotNet.Ndr.NdrContextHandle .EXAMPLE New-RpcContextHandle Creates a new RPC context handle. #> function New-RpcContextHandle { param( [guid]$Uuid = [guid]::Empty, [int]$Attributes = 0 ) [NtApiDotNet.Ndr.Marshal.NdrContextHandle]::new($Attributes, $Uuid) } <# .SYNOPSIS Get an RPC string binding from its parts. .DESCRIPTION This cmdlet gets an RPC string binding based on its component parts. .PARAMETER ProtocolSequence Specify the RPC protocol sequence . .PARAMETER Endpoint Specify the endpoint string. .PARAMETER NetworkAddress Specify the network address. .PARAMETER ObjectUuid Specify the object UUID. .PARAMETER Options Specify the options. .PARAMETER AsObject Specify to return the binding as an object. .INPUTS None .OUTPUTS string .EXAMPLE Get-RpcStringBinding -ProtocolSequence "ncalrpc" Connect an RPC ALPC string binding from a specific protocol sequence. #> function Get-RpcStringBinding { [CmdletBinding(DefaultParameterSetName = "FromProtocol")] Param( [parameter(Mandatory, Position = 0)] [string]$ProtocolSequence, [parameter(Position = 1)] [string]$Endpoint, [parameter(Position = 2)] [string]$NetworkAddress, [parameter(Position = 3)] [System.Nullable[Guid]]$ObjectUuid, [parameter(Position = 4)] [string]$Options, [switch]$AsObject ) $binding = [NtApiDotNet.Win32.Rpc.RpcStringBinding]::new($ProtocolSequence, $NetworkAddress, $Endpoint, $Options, $ObjectUuid) if ($AsObject) { $binding } else { $binding.ToString() } } Register-ArgumentCompleter -CommandName Get-RpcStringBinding -ParameterName ProtocolSequence -ScriptBlock $protseq_completer <# .SYNOPSIS Creates a NDR parser for a process. .DESCRIPTION This cmdlet creates a new NDR parser for the given process. .PARAMETER Process The process to create the NDR parser on. If not specified then the current process is used. .PARAMETER SymbolResolver Specify a symbol resolver for the parser. Note that this should be a resolver for the same process as we're parsing. .PARAMETER ParserFlags Specify flags which affect the parsing operation. .OUTPUTS NtApiDotNet.Ndr.NdrParser - The NDR parser. .EXAMPLE $ndr = New-NdrParser Get an NDR parser for the current process. .EXAMPLE New-NdrParser -Process $p -SymbolResolver $resolver Get an NDR parser for a specific process with a known resolver. #> function New-NdrParser { Param( [NtApiDotNet.NtProcess]$Process, [NtApiDotNet.Win32.ISymbolResolver]$SymbolResolver, [NtApiDotNet.Ndr.NdrParserFlags]$ParserFlags = 0 ) [NtApiDotNet.Ndr.NdrParser]::new($Process, $SymbolResolver, $ParserFlags) } function Convert-HashTableToIidNames { Param( [Hashtable]$IidToName, [NtApiDotNet.Ndr.NdrComProxyDefinition[]]$Proxy ) $dict = [System.Collections.Generic.Dictionary[Guid, string]]::new() if ($null -ne $IidToName) { foreach ($pair in $IidToName.GetEnumerator()) { $guid = [Guid]::new($pair.Key) $dict.Add($guid, $pair.Value) } } if ($null -ne $Proxy) { foreach ($p in $Proxy) { $dict.Add($p.Iid, $p.Name) } } if (!$dict.ContainsKey("00000000-0000-0000-C000-000000000046")) { $dict.Add("00000000-0000-0000-C000-000000000046", "IUnknown") } if (!$dict.ContainsKey("00020400-0000-0000-C000-000000000046")) { $dict.Add("00020400-0000-0000-C000-000000000046", "IDispatch") } return $dict } <# .SYNOPSIS Parses COM proxy information from a DLL. .DESCRIPTION This cmdlet parses the COM proxy information from a specified DLL. .PARAMETER Path The path to the DLL containing the COM proxy information. .PARAMETER Clsid Optional CLSID for the object used to find the proxy information. .PARAMETER Iids Optional list of IIDs to parse from the proxy information. .PARAMETER ParserFlags Specify flags which affect the parsing operation. .OUTPUTS The parsed proxy information and complex types. .EXAMPLE $p = Get-NdrComProxy c:\path\to\proxy.dll Parse the proxy information from c:\path\to\proxy.dll .EXAMPLE $p = Get-NdrComProxy $env:SystemRoot\system32\combase.dll -Clsid "00000320-0000-0000-C000-000000000046" Parse the proxy information from combase.dll with a specific proxy CLSID. .EXAMPLE $p = Get-NdrComProxy $env:SystemRoot\system32\combase.dll -Clsid "00000320-0000-0000-C000-000000000046" -Iid "00000001-0000-0000-c000-000000000046" Parse the proxy information from combase.dll with a specific proxy CLSID, only returning a specific IID. #> function Get-NdrComProxy { Param( [parameter(Mandatory, Position = 0)] [string]$Path, [Guid]$Clsid = [Guid]::Empty, [NtApiDotNet.Win32.ISymbolResolver]$SymbolResolver, [Guid[]]$Iid, [NtApiDotNet.Ndr.NdrParserFlags]$ParserFlags = 0 ) $Path = Resolve-Path $Path -ErrorAction Stop Use-NtObject($parser = New-NdrParser -SymbolResolver $SymbolResolver -NdrParserFlags $ParserFlags) { $proxies = $parser.ReadFromComProxyFile($Path, $Clsid, $Iid) $props = @{ Path = $Path; Proxies = $proxies; ComplexTypes = $parser.ComplexTypes; IidToNames = Convert-HashTableToIidNames -Proxy $proxies; } $obj = New-Object –TypeName PSObject –Prop $props Write-Output $obj } } <# .SYNOPSIS Format an NDR procedure. .DESCRIPTION This cmdlet formats a parsed NDR procedure. .PARAMETER Procedure The procedure to format. .PARAMETER IidToName A dictionary of IID to name mappings for parameters. .OUTPUTS string - The formatted procedure. .EXAMPLE Format-NdrProcedure $proc Format a procedure. .EXAMPLE $procs = | Format-NdrProcedure Format a list of procedures from a pipeline. .EXAMPLE Format-NdrProcedure $proc -IidToName @{"00000000-0000-0000-C000-000000000046"="IUnknown";} Format a procedure with a known IID to name mapping. #> function Format-NdrProcedure { [CmdletBinding()] Param( [parameter(Mandatory, Position = 0, ValueFromPipeline = $true)] [NtApiDotNet.Ndr.NdrProcedureDefinition]$Procedure, [Hashtable]$IidToName ) BEGIN { $dict = Convert-HashTableToIidNames($IidToName) $formatter = [NtApiDotNet.Ndr.DefaultNdrFormatter]::Create($dict) } PROCESS { $fmt = $formatter.FormatProcedure($Procedure) Write-Output $fmt } } <# .SYNOPSIS Format an NDR complex type. .DESCRIPTION This cmdlet formats a parsed NDR complex type. .PARAMETER ComplexType The complex type to format. .PARAMETER IidToName A dictionary of IID to name mappings for parameters. .OUTPUTS string - The formatted complex type. .EXAMPLE Format-NdrComplexType $type Format a complex type. .EXAMPLE $ndr.ComplexTypes | Format-NdrComplexType Format a list of complex types from a pipeline. .EXAMPLE Format-NdrComplexType $type -IidToName @{"00000000-0000-0000-C000-000000000046"="IUnknown";} Format a complex type with a known IID to name mapping. #> function Format-NdrComplexType { [CmdletBinding()] Param( [parameter(Mandatory, Position = 0, ValueFromPipeline)] [NtApiDotNet.Ndr.NdrComplexTypeReference[]]$ComplexType, [Hashtable]$IidToName ) BEGIN { $dict = Convert-HashTableToIidNames($IidToName) $formatter = [NtApiDotNet.Ndr.DefaultNdrFormatter]::Create($dict) } PROCESS { foreach ($t in $ComplexType) { $formatter.FormatComplexType($t) | Write-Output } } } <# .SYNOPSIS Format an NDR COM proxy. .DESCRIPTION This cmdlet formats a parsed NDR COM proxy. .PARAMETER Proxy The proxy to format. .PARAMETER IidToName A dictionary of IID to name mappings for parameters. .PARAMETER DemangleComName A script block which demangles a COM name (for WinRT types) .OUTPUTS string - The formatted proxy. .EXAMPLE Format-NdrComProxy $proxy Format a COM proxy. .EXAMPLE $proxies = | Format-NdrComProxy Format a list of COM proxies from a pipeline. .EXAMPLE Format-NdrComProxy $proxy -IidToName @{"00000000-0000-0000-C000-000000000046"="IUnknown";} Format a COM proxy with a known IID to name mapping. #> function Format-NdrComProxy { [CmdletBinding()] Param( [parameter(Mandatory, Position = 0, ValueFromPipeline)] [NtApiDotNet.Ndr.NdrComProxyDefinition]$Proxy, [Hashtable]$IidToName, [ScriptBlock]$DemangleComName ) BEGIN { $dict = Convert-HashTableToIidNames($IidToName) $formatter = if ($null -eq $DemangleComName) { [NtApiDotNet.Ndr.DefaultNdrFormatter]::Create($dict) } else { [NtApiDotNet.Ndr.DefaultNdrFormatter]::Create($dict, [Func[string, string]]$DemangleComName) } } PROCESS { $fmt = $formatter.FormatComProxy($Proxy) Write-Output $fmt } } <# .SYNOPSIS Parses RPC server information from an executable. .DESCRIPTION This cmdlet parses the RPC server information from a specified executable with a known offset. .PARAMETER Path The path to the executable containing the RPC server information. .PARAMETER Offset The offset into the executable where the RPC_SERVER_INTERFACE structure is loaded. .PARAMETER ParserFlags Specify flags which affect the parsing operation. .OUTPUTS The parsed RPC server information and complex types. .EXAMPLE $p = Get-NdrRpcServerInterface c:\path\to\server.dll 0x18000 Parse the RPC server information from c:\path\to\proxy.dll with offset 0x18000 #> function Get-NdrRpcServerInterface { Param( [parameter(Mandatory, Position = 0)] [string]$Path, [parameter(Mandatory, Position = 1)] [int]$Offset, [NtApiDotNet.Win32.ISymbolResolver]$SymbolResolver, [NtApiDotNet.Ndr.NdrParserFlags]$ParserFlags = 0 ) $Path = Resolve-Path $Path -ErrorAction Stop Use-NtObject($parser = New-NdrParser -SymbolResolver $SymbolResolver -ParserFlags $ParserFlags) { $rpc_server = $parser.ReadFromRpcServerInterface($Path, $Offset) $props = @{ Path = $Path; RpcServer = $rpc_server; ComplexTypes = $parser.ComplexTypes; } $obj = New-Object –TypeName PSObject –Prop $props Write-Output $obj } } <# .SYNOPSIS Format an RPC server interface type. .DESCRIPTION This cmdlet formats a parsed RPC server interface type. .PARAMETER RpcServer The RPC server interface to format. .OUTPUTS string - The formatted RPC server interface. .EXAMPLE Format-NdrRpcServerInterface $type Format an RPC server interface type. #> function Format-NdrRpcServerInterface { [CmdletBinding()] Param( [parameter(Mandatory, Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)] [NtApiDotNet.Ndr.NdrRpcServerInterface]$RpcServer ) BEGIN { $formatter = [NtApiDotNet.Ndr.DefaultNdrFormatter]::Create() } PROCESS { $fmt = $formatter.FormatRpcServerInterface($RpcServer) Write-Output $fmt } } <# .SYNOPSIS Get NDR complex types from memory. .DESCRIPTION This cmdlet parses NDR complex type information from a location in memory. .PARAMETER PicklingInfo Specify pointer to the MIDL_TYPE_PICKLING_INFO structure. .PARAMETER StubDesc Specify pointer to the MIDL_STUB_DESC structure. .PARAMETER StublessProxy Specify pointer to the MIDL_STUBLESS_PROXY_INFO structure. .PARAMETER OffsetTable Specify pointer to type offset table. .PARAMETER TypeIndex Specify list of type index into type offset table. .PARAMETER TypeFormat Specify list of type format string addresses for the types. .PARAMETER TypeOffset Specify list of type offsets into the format string for the types. .PARAMETER Process Specify optional process which contains the types. .PARAMETER Module Specify optional module base address for the types. If set all pointers are relative offsets from the module address. .INPUTS None .OUTPUTS NdrComplexTypeReference[] #> function Get-NdrComplexType { [CmdletBinding(DefaultParameterSetName="FromDecode3")] Param( [Parameter(Mandatory)] [long]$PicklingInfo, [Parameter(Mandatory, ParameterSetName = "FromDecode2")] [Parameter(Mandatory, ParameterSetName = "FromDecode2Offset")] [long]$StubDesc, [Parameter(Mandatory, ParameterSetName = "FromDecode2")] [long[]]$TypeFormat, [Parameter(Mandatory, ParameterSetName = "FromDecode2Offset")] [int[]]$TypeOffset, [Parameter(Mandatory, ParameterSetName = "FromDecode3")] [long]$StublessProxy, [Parameter(Mandatory, ParameterSetName = "FromDecode3")] [long]$OffsetTable, [Parameter(Mandatory, ParameterSetName = "FromDecode3")] [int[]]$TypeIndex, [NtApiDotNet.Win32.SafeLoadLibraryHandle]$Module, [NtApiDotNet.NtProcess]$Process, [NtApiDotNet.Ndr.NdrParserFlags]$Flags = "IgnoreUserMarshal" ) $base_address = 0 if ($null -ne $Module) { $base_address = $Module.DangerousGetHandle().ToInt64() } switch($PSCmdlet.ParameterSetName) { "FromDecode2" { $type_offset = $TypeFormat | % { $_ + $base_address } [NtApiDotNet.Ndr.NdrParser]::ReadPicklingComplexTypes($Process, $PicklingInfo+$base_address,` $StubDesc+$base_address, $type_offset, $Flags) | Write-Output } "FromDecode2Offset" { [NtApiDotNet.Ndr.NdrParser]::ReadPicklingComplexTypes($Process, $PicklingInfo+$base_address,` $StubDesc+$base_address, $TypeOffset, $Flags) | Write-Output } "FromDecode3" { [NtApiDotNet.Ndr.NdrParser]::ReadPicklingComplexTypes($Process, $PicklingInfo+$base_address,` $StublessProxy+$base_address, $OffsetTable+$base_address, $TypeIndex, $Flags) | Write-Output } } } <# .SYNOPSIS Gets an ALPC server port. .DESCRIPTION This cmdlet gets an ALPC server port by name. As you can't directly open the server end of the port this function goes through all handles and tries to extract the port from the hosting process. This might require elevated privileges, especially debug privilege, to work correctly. .PARAMETER Path The path to the ALPC server port to get. .PARAMETER ProcessId The process ID of the process to query for ALPC servers. .INPUTS None .OUTPUTS NtApiDotNet.NtAlpc .EXAMPLE Get-NtAlpcServer Gets all ALPC server objects accessible to the current process. .EXAMPLE Get-NtAlpcServer "\RPC Control\atsvc" Gets the "\RPC Control\atsvc" ALPC server. .EXAMPLE Get-NtAlpcServer -ProcessId 1234 Gets all ALPC servers from PID 1234. #> function Get-NtAlpcServer { [CmdletBinding(DefaultParameterSetName = "All")] Param( [parameter(Mandatory, Position = 0, ParameterSetName = "FromPath")] [string]$Path, [parameter(Mandatory, Position = 0, ParameterSetName = "FromProcessId")] [alias("pid")] [int]$ProcessId ) if (![NtApiDotNet.NtToken]::EnableDebugPrivilege()) { Write-Warning "Can't enable debug privilege, results might be incomplete" } if ($PSCmdlet.ParameterSetName -ne "FromProcessId") { $ProcessId = -1 } $hs = Get-NtHandle -ObjectTypes "ALPC Port" -ProcessId $ProcessId | Where-Object Name -ne "" switch ($PSCmdlet.ParameterSetName) { "All" { Write-Output $hs.GetObject() } "FromProcessId" { Write-Output $hs.GetObject() } "FromPath" { foreach ($h in $hs) { if ($h.Name -eq $Path) { Write-Output $h.GetObject() break } } } } } <# .SYNOPSIS Add a RPC security context to a client. .DESCRIPTION This cmdlet adds a RPC security context to an endpoint. .PARAMETER Client Specify the RPC client to add the context to. .PARAMETER SecurityQualityOfService Specify the security quality of service for the connection. .PARAMETER Credentials Specify user credentials for the RPC client authentication. .PARAMETER ServicePrincipalName Specify service principal name for the RPC client authentication. .PARAMETER AuthenticationLevel Specify authentication level for the RPC client authentication. .PARAMETER AuthenticationType Specify authentication type for the RPC client authentication. .PARAMETER AuthenticationCapabilities Specify authentication capabilities for the RPC client authentication. .PARAMETER PassThru Specify to the pass the security context object to the output. If you don't specify this the security context will be set as the current context before returning. .INPUTS None .OUTPUTS NtApiDotNet.Win32.Rpc.Transport.RpcTransportSecurityContext #> function Add-RpcClientSecurityContext { [CmdletBinding(DefaultParameterSetName = "FromProtocol")] Param( [parameter(Mandatory, Position = 0)] [NtApiDotNet.Win32.Rpc.RpcClientBase]$Client, [NtApiDotNet.SecurityQualityOfService]$SecurityQualityOfService, [NtApiDotNet.Win32.Security.Authentication.AuthenticationCredentials]$Credentials, [string]$ServicePrincipalName, [NtApiDotNet.Win32.Rpc.Transport.RpcAuthenticationLevel]$AuthenticationLevel = "None", [NtApiDotNet.Win32.Rpc.Transport.RpcAuthenticationType]$AuthenticationType = "None", [NtApiDotNet.Win32.Rpc.Transport.RpcAuthenticationCapabilities]$AuthenticationCapabilities = "None", [switch]$PassThru ) try { $security = New-Object NtApiDotNet.Win32.Rpc.Transport.RpcTransportSecurity $security.SecurityQualityOfService = $SecurityQualityOfService $security.Credentials = $Credentials $security.ServicePrincipalName = $ServicePrincipalName $security.AuthenticationLevel = $AuthenticationLevel $security.AuthenticationType = $AuthenticationType $security.AuthenticationCapabilities = $AuthenticationCapabilities $ctx = $Client.Transport.AddSecurityContext($security) if ($PassThru) { $ctx } else { Set-RpcClientSecurityContext -Client $Client -SecurityContext $ctx } } catch { Write-Error $_ } } <# .SYNOPSIS Set a RPC security context on a client. .DESCRIPTION This cmdlet sets the current RPC security context for a client. .PARAMETER Client Specify the RPC client to set the context to. .PARAMETER SecurityContext Specify the security context to set. .PARAMETER ContextId Specify the ID of the security context to set. .INPUTS None .OUTPUTS None #> function Set-RpcClientSecurityContext { [CmdletBinding(DefaultParameterSetName="FromContext")] Param( [parameter(Mandatory, Position = 0)] [NtApiDotNet.Win32.Rpc.RpcClientBase]$Client, [parameter(Mandatory, Position = 1, ParameterSetName="FromContext")] [NtApiDotNet.Win32.Rpc.Transport.RpcTransportSecurityContext]$SecurityContext, [parameter(Mandatory, Position = 1, ParameterSetName="FromId")] [int]$ContextId ) if ($PSCmdlet.ParameterSetName -eq "FromId") { $SecurityContext = Get-RpcClientSecurityContext -Client $Client -ContextId $ContextId } $Client.Transport.CurrentSecurityContext = $SecurityContext } <# .SYNOPSIS Get a RPC security contexts from a client. .DESCRIPTION This cmdlet gets the current RPC security context for a client. .PARAMETER Client Specify the RPC client to set the context to. .PARAMETER Current Specify to return the current context only. .PARAMETER ContextId Specify to return the context with the specified ID. .INPUTS None .OUTPUTS NtApiDotNet.Win32.Rpc.Transport.RpcTransportSecurityContext[] #> function Get-RpcClientSecurityContext { [CmdletBinding(DefaultParameterSetName="All")] Param( [parameter(Mandatory, Position = 0)] [NtApiDotNet.Win32.Rpc.RpcClientBase]$Client, [parameter(Mandatory, ParameterSetName="FromCurrent")] [switch]$Current, [parameter(Mandatory, Position = 1, ParameterSetName="FromId")] [int]$ContextId ) switch($PSCmdlet.ParameterSetName) { "All" { $Client.Transport.SecurityContext | Write-Output } "FromCurrent" { $Client.Transport.CurrentSecurityContext } "FromId" { $Client.Transport.SecurityContext | Where-Object ContextId -eq $ContextId } } } <# .SYNOPSIS Get the registered security principal name for a RPC server. .DESCRIPTION This cmdlet gets the registered security principal name for a RPC server. .PARAMETER Binding Specify the server binding. .PARAMETER AuthenticationType Specify the authentication type. .INPUTS None .OUTPUTS string #> function Get-RpcSecurityPrincipalName { [CmdletBinding()] Param( [parameter(Mandatory, Position = 0)] [string]$Binding, [parameter(Mandatory, Position = 1)] [NtApiDotNet.Win32.Rpc.Transport.RpcAuthenticationType]$AuthenticationType ) [NtApiDotNet.Win32.Rpc.Transport.RpcTransportSecurity]::QueryServicePrincipalName($Binding, $AuthenticationType) } |