Dekodowanie polecenia programu PowerShell z uruchomionego procesuDecode a PowerShell command from a running process

Czasami może być uruchomiony proces programu PowerShell, który zajmuje znaczną ilość zasobów.At times, you may have a PowerShell process running that is taking up a large amount of resources. Ten proces może być uruchomiony w kontekście zadania harmonogram zadań lub zadania [agenta SQL Server][] .This process could be running in the context of a Task Scheduler job or a SQL Server Agent job. W przypadku wielu uruchomionych procesów programu PowerShell może być trudne, aby wiedzieć, który proces reprezentuje problem.Where there are multiple PowerShell processes running, it can be difficult to know which process represents the problem. W tym artykule pokazano, jak zdekodować blok skryptu, w którym aktualnie działa proces programu PowerShell.This article shows how to decode a script block that a PowerShell process is currently running.

Tworzenie długotrwałego procesuCreate a long running process

Aby zademonstrować ten scenariusz, Otwórz nowe okno programu PowerShell i uruchom następujący kod.To demonstrate this scenario, open a new PowerShell window and run the following code. Wykonuje polecenie programu PowerShell, które wyprowadza liczbę co minutę przez 10 minut.It executes a PowerShell command that outputs a number every minute for 10 minutes.

powershell.exe -Command {
    $i = 1
    while ( $i -le 10 )
    {
        Write-Output -InputObject $i
        Start-Sleep -Seconds 60
        $i++
    }
}

Wyświetlanie procesuView the process

Treść polecenia, które wykonuje program PowerShell, jest przechowywana we właściwości CommandLine klasy Win32_Process .The body of the command which PowerShell is executing is stored in the CommandLine property of the Win32_Process class. Jeśli polecenie jest zakodowane polecenie, właściwość CommandLine zawiera ciąg "EncodedCommand".If the command is an encoded command, the CommandLine property contains the string "EncodedCommand". Korzystając z tych informacji, zakodowane polecenie może zostać cofnięte jako niesłonięte za pośrednictwem następującego procesu.Using this information, the encoded command can be de-obfuscated via the following process.

Uruchom program PowerShell jako administrator.Start PowerShell as Administrator. Niezbędne jest, aby program PowerShell działał jako administrator, w przeciwnym razie żadne wyniki nie są zwracane podczas wykonywania zapytań dotyczących uruchomionych procesów.It is vital that PowerShell is running as administrator, otherwise no results are returned when querying the running processes.

Wykonaj następujące polecenie, aby pobrać wszystkie procesy programu PowerShell, które mają zakodowane polecenie:Execute the following command to get all of the PowerShell processes that have an encoded command:

$powerShellProcesses = Get-CimInstance -ClassName Win32_Process -Filter 'CommandLine LIKE "%EncodedCommand%"'

Następujące polecenie tworzy niestandardowy obiekt programu PowerShell, który zawiera identyfikator procesu i zakodowane polecenie.The following command creates a custom PowerShell object that contains the process ID and the encoded command.

$commandDetails = $powerShellProcesses | Select-Object -Property ProcessId,
@{
    name       = 'EncodedCommand'
    expression = {
        if ( $_.CommandLine -match 'encodedCommand (.*) -inputFormat' )
        {
            return $matches[1]
        }
    }
}

Teraz zakodowane polecenie może być zdekodowane.Now the encoded command can be decoded. Poniższy fragment kodu iteruje za pośrednictwem obiektu szczegóły polecenia, dekoduje zakodowane polecenie i dodaje dekodowane polecenie z powrotem do obiektu w celu dalszej analizy.The following snippet iterates over the command details object, decodes the encoded command, and adds the decoded command back to the object for further investigation.

$commandDetails | ForEach-Object -Process {
    # Get the current process
    $currentProcess = $_

    # Convert the Base 64 string to a Byte Array
    $commandBytes = [System.Convert]::FromBase64String($currentProcess.EncodedCommand)

    # Convert the Byte Array to a string
    $decodedCommand = [System.Text.Encoding]::Unicode.GetString($commandBytes)

    # Add the decoded command back to the object
    $commandDetails |
        Where-Object -FilterScript { $_.ProcessId -eq $_.ProcessId } |
        Add-Member -MemberType NoteProperty -Name DecodedCommand -Value $decodedCommand
}
$commandDetails[0]

Dekodowane polecenie można teraz przejrzeć, wybierając zdekodowaną właściwość polecenia.The decoded command can now be reviewed by selecting the decoded command property.

ProcessId      : 8752
EncodedCommand : IAAKAAoACgAgAAoAIAAgACAAIAAkAGkAIAA9ACAAMQAgAAoACgAKACAACgAgACAAIAAgAHcAaABpAGwAZQAgACgAIAAkAGkAIAAtAG
                 wAZQAgADEAMAAgACkAIAAKAAoACgAgAAoAIAAgACAAIAB7ACAACgAKAAoAIAAKACAAIAAgACAAIAAgACAAIABXAHIAaQB0AGUALQBP
                 AHUAdABwAHUAdAAgAC0ASQBuAHAAdQB0AE8AYgBqAGUAYwB0ACAAJABpACAACgAKAAoAIAAKACAAIAAgACAAIAAgACAAIABTAHQAYQ
                 ByAHQALQBTAGwAZQBlAHAAIAAtAFMAZQBjAG8AbgBkAHMAIAA2ADAAIAAKAAoACgAgAAoAIAAgACAAIAAgACAAIAAgACQAaQArACsA
                 IAAKAAoACgAgAAoAIAAgACAAIAB9ACAACgAKAAoAIAAKAA==
DecodedCommand :
                     $i = 1

                     while ( $i -le 10 )

                     {

                         Write-Output -InputObject $i

                         Start-Sleep -Seconds 60

                         $i++

                     }