PowerShell脚本Base64编码超长报错,求解决及替代编码方案
如何规避PowerShell EncodedCommand的字符长度限制及替代编码方法
你尝试通过Base64编码执行脚本以实现“一眼无法读取”的效果,执行步骤如下:
$expression = Get-Content -Path .\backupsql_v1.0.ps1 -Raw $bytes = [System.Text.Encoding]::Unicode.GetBytes($expression) $b64 = [System.Convert]::ToBase64String($bytes) Write-Debug "Base64: $b64" powershell.exe -EncodedCommand "$b64"
但遇到了以下错误:
Program 'powershell.exe' failed to run: The filename or extension is too longAt line:1 char:1 + powershell.exe -EncodedCommand "$b64" + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~. At line:1 char:1 + powershell.exe -EncodedCommand "$b64" + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ResourceUnavailable: (:) [], ParentContainsErrorRecordException + FullyQualifiedErrorId : NativeCommandFailed
一、规避EncodedCommand长度限制的方法
1. 用临时文件传递编码内容
把生成的Base64字符串写入临时文件,再让PowerShell读取文件内容解码执行,完全绕开命令行长度限制:
# 生成脚本的Base64编码 $expression = Get-Content -Path .\backupsql_v1.0.ps1 -Raw $bytes = [System.Text.Encoding]::Unicode.GetBytes($expression) $b64 = [System.Convert]::ToBase64String($bytes) # 创建临时文件保存编码内容 $tempFile = [System.IO.Path]::GetTempFileName() Set-Content -Path $tempFile -Value $b64 -NoNewline # 读取临时文件解码并执行 powershell.exe -Command "& ([ScriptBlock]::Create([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String((Get-Content -Path '$tempFile' -Raw)))))" # 清理临时文件 Remove-Item -Path $tempFile -Force
2. 拆分脚本分块执行
如果你的脚本可以拆分成独立的逻辑片段,把大脚本拆成多个小文件分别编码执行,通过全局变量或文件传递上下文数据:
# 拆分脚本为多个部分(示例拆成part1和part2) $part1 = Get-Content -Path .\part1.ps1 -Raw $part2 = Get-Content -Path .\part2.ps1 -Raw # 分别生成Base64编码 $b64Part1 = [System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($part1)) $b64Part2 = [System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($part2)) # 依次执行各部分 powershell.exe -EncodedCommand $b64Part1 powershell.exe -EncodedCommand $b64Part2
3. 加密文件配合-File参数
把脚本加密后存成文件,执行时先解密再读取,既绕开长度限制又增强隐蔽性:
# 生成AES密钥(注意:密钥需妥善保存,执行时要用到相同的密钥) $aes = [System.Security.Cryptography.Aes]::Create() $key = $aes.Key $iv = $aes.IV # 加密脚本内容 $scriptContent = Get-Content -Path .\backupsql_v1.0.ps1 -Raw $plainBytes = [System.Text.Encoding]::Unicode.GetBytes($scriptContent) $encryptor = $aes.CreateEncryptor($key, $iv) $encryptedBytes = $encryptor.TransformFinalBlock($plainBytes, 0, $plainBytes.Length) # 保存加密后的内容和IV到文件 Set-Content -Path .\encrypted_script.bin -Value ($iv + $encryptedBytes) -Encoding Byte # 执行时解密并运行 $encryptedData = Get-Content -Path .\encrypted_script.bin -Encoding Byte $iv = $encryptedData[0..15] $encryptedBytes = $encryptedData[16..($encryptedData.Length-1)] $aes = [System.Security.Cryptography.Aes]::Create() $decryptor = $aes.CreateDecryptor($key, $iv) $plainBytes = $decryptor.TransformFinalBlock($encryptedBytes, 0, $encryptedBytes.Length) $decryptedScript = [System.Text.Encoding]::Unicode.GetString($plainBytes) Invoke-Expression $decryptedScript
二、其他脚本编码/混淆方法
1. 字节数组直接执行
把脚本转换成Unicode字节数组,直接通过内存创建脚本块执行,完全不用命令行传递参数:
$scriptBytes = [System.Text.Encoding]::Unicode.GetBytes((Get-Content -Path .\backupsql_v1.0.ps1 -Raw)) $scriptBlock = [System.Management.Automation.ScriptBlock]::Create($scriptBytes) & $scriptBlock
2. 简单字符串混淆
对脚本内容做反转、字符替换等简单混淆,执行时再还原,实现“一眼看不懂”的效果:
# 混淆:反转脚本字符串 $originalScript = Get-Content -Path .\backupsql_v1.0.ps1 -Raw $obfuscatedScript = -join ($originalScript.ToCharArray() | Reverse) # 执行时还原并运行 $decryptedScript = -join ($obfuscatedScript.ToCharArray() | Reverse) Invoke-Expression $decryptedScript
3. 内存编译执行
利用PowerShell的脚本编译能力,把脚本编译成内存中的程序集,通过反射执行,隐蔽性更强:
$scriptContent = Get-Content -Path .\backupsql_v1.0.ps1 -Raw # 编译脚本为内存程序集 $compiler = New-Object Microsoft.PowerShell.Commands.PSCompiler $assembly = $compiler.Compile($scriptContent) # 获取脚本类并执行入口方法 $scriptType = $assembly.GetType("GeneratedScript") $runMethod = $scriptType.GetMethod("Run") $runMethod.Invoke($null, $null)
内容的提问来源于stack exchange,提问作者Toni
相关产品推荐
相关产品推荐

