Декодирование команды PowerShell из выполняемого процесса

Этот пример выполняется только на платформах Windows.

Иногда у вас может быть запущен процесс PowerShell, который занимает большое количество ресурсов. Этот процесс может быть запущен в контексте задания планировщика задач или задания агента SQL Server. Если запущено несколько процессов PowerShell, может быть трудно определить, какой процесс представляет проблему. В этой статье показано, как декодировать блок скрипта, который в данный момент выполняется процессом PowerShell.

Создание длительного процесса

Для демонстрации этого сценария откройте новое окно PowerShell и выполните следующий код. Он выполняет команду PowerShell, которая выводит число каждую минуту в течение 10 минут.

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

Представление процесса

Текст команды, выполняемой PowerShell, хранится в свойстве CommandLine класса Win32_Process. Если команда является зашифрованной, свойство CommandLine содержит строку EncodedCommand. Используя эту информацию, зашифрованная команда может быть удалена с помощью следующего процесса.

Запустите PowerShell от имени администратора. Крайне важно, чтобы PowerShell выполнялась от имени администратора, в противном случае результаты не возвращаются при запросе выполняемых процессов.

Выполните следующую команду, чтобы получить все процессы PowerShell с закодированной командой:

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

Следующая команда создает пользовательский объект PowerShell, который содержит идентификатор процесса и зашифрованную команду.

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

Теперь зашифрованная команда может быть декодирована. Следующий фрагмент перебирает объект сведений о команде, декодирует зашифрованную команду и добавляет декодированную команду обратно к объекту для дальнейшего изучения.

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

Теперь можно просмотреть декодированную команду, выбрав ее свойство.

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