Condividi tramite


Decodificare un comando PowerShell da un processo in esecuzione

Questo esempio viene eseguito solo su piattaforme Windows.

A volte, potrebbe essere in esecuzione un processo di PowerShell che occupa una grande quantità di risorse. Questo processo potrebbe essere in esecuzione nel contesto di un'attività dell'utilità di pianificazione o di un'attività del SQL Server Agent . In presenza di più processi di PowerShell in esecuzione, può essere difficile sapere quale processo rappresenta il problema. Questo articolo illustra come decodificare un blocco di script in cui è in esecuzione un processo di PowerShell.

Creare un processo a esecuzione prolungata

Per illustrare questo scenario, aprire una nuova finestra di PowerShell ed eseguire il codice seguente. Esegue un comando di PowerShell che restituisce un numero ogni minuto per 10 minuti.

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

Visualizzare il processo

Il corpo del comando eseguito da PowerShell viene archiviato nella proprietà CommandLine della classe Win32_Process. Se il comando è un comando codificato, la proprietà CommandLine contiene la stringa "EncodedCommand". Usando queste informazioni, il comando codificato può essere defuscato tramite il processo seguente.

Avviare PowerShell come amministratore. È fondamentale che PowerShell sia in esecuzione come amministratore. In caso contrario, non vengono restituiti risultati durante l'esecuzione di query sui processi in esecuzione.

Eseguire il comando seguente per ottenere tutti i processi di PowerShell con un comando codificato:

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

Il comando seguente crea un oggetto PowerShell personalizzato che contiene l'ID processo e il comando codificato.

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

È ora possibile decodificare il comando codificato. Il seguente frammento di codice scorre l'oggetto che contiene i dettagli del comando, decodifica il comando codificato e aggiunge il comando decodificato nuovamente all'oggetto per ulteriori analisi.

$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 *

Il comando decodificato può ora essere esaminato selezionando la proprietà del comando decodificata.

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