Dekodowanie polecenia programu PowerShell z uruchomionego procesu

Ten przykład działa tylko na platformach Windows.

Czasami może być uruchomiony proces programu PowerShell, który zajmuje dużą ilość zasobów. Ten proces może być uruchomiony w kontekście zadania harmonogramu zadań lub zadania agenta programu SQL Server. Jeśli jest uruchomionych wiele procesów programu PowerShell, trudno jest wiedzieć, który proces reprezentuje problem. W tym artykule pokazano, jak zdekodować blok skryptu, który jest obecnie uruchomiony przez proces programu PowerShell.

Tworzenie długotrwałego procesu

Aby zademonstrować ten scenariusz, otwórz nowe okno programu PowerShell i uruchom następujący kod. Wykonuje polecenie programu PowerShell, które generuje liczbę co minutę przez 10 minut.

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

Wyświetlanie procesu

Treść polecenia wykonywanego przez program PowerShell jest przechowywana we właściwości CommandLine klasy Win32_Process. Jeśli polecenie jest zakodowanym poleceniem, właściwość CommandLine zawiera ciąg "EncodedCommand". Korzystając z tych informacji, zakodowane polecenie można de-zaciemniać za pomocą następującego procesu.

Uruchom program PowerShell jako Administracja istrator. Ważne jest, aby program PowerShell był uruchomiony jako administrator. W przeciwnym razie podczas wykonywania zapytań dotyczących uruchomionych procesów nie są zwracane żadne wyniki.

Wykonaj następujące polecenie, aby pobrać wszystkie procesy programu PowerShell, które mają zakodowane polecenie:

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

Następujące polecenie tworzy niestandardowy obiekt programu PowerShell zawierający identyfikator procesu i zakodowane polecenie.

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

Teraz zakodowane polecenie można dekodować. Poniższy fragment kodu iteruje obiekt szczegółów polecenia, dekoduje zakodowane polecenie i dodaje dekodowane polecenie z powrotem do obiektu w celu dalszego badania.

$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 $currentProcess.processId } |
        Add-Member -MemberType NoteProperty -Name DecodedCommand -Value $decodedCommand
}
$commandDetails[0] | Format-List -Property *

Polecenie dekodowane można teraz przejrzeć, wybierając właściwość dekodowanego polecenia.

ProcessId      : 8752
EncodedCommand : IAAKAAoACgAgAAoAIAAgACAAIAAkAGkAIAA9ACAAMQAgAAoACgAKACAACgAgACAAIAAgAHcAaABpAGwAZQAgACgAIAAkAGkAIAAtAG
                 wAZQAgADEAMAAgACkAIAAKAAoACgAgAAoAIAAgACAAIAB7ACAACgAKAAoAIAAKACAAIAAgACAAIAAgACAAIABXAHIAaQB0AGUALQBP
                 AHUAdABwAHUAdAAgAC0ASQBuAHAAdQB0AE8AYgBqAGUAYwB0ACAAJABpACAACgAKAAoAIAAKACAAIAAgACAAIAAgACAAIABTAHQAYQ
                 ByAHQALQBTAGwAZQBlAHAAIAAtAFMAZQBjAG8AbgBkAHMAIAA2ADAAIAAKAAoACgAgAAoAIAAgACAAIAAgACAAIAAgACQAaQArACsA
                 IAAKAAoACgAgAAoAIAAgACAAIAB9ACAACgAKAAoAIAAKAA==
DecodedCommand :
                     $i = 1
                     while ( $i -le 10 )
                     {
                         Write-Output -InputObject $i
                         Start-Sleep -Seconds 60
                         $i++
                     }