我试图仅使用powershell从命令行执行二进制十六进制编辑。用此片段执行六角替换已取得部分成功。当多次出现123456并且仅在特定位置发生替换时,问题就会出现。
注意:片段需要此处的Convert-ByteArrayToHexString
和Convert-HexStringToByteArray
功能。
http://www.sans.org/windows-security/2010/02/11/powershell-byte-array-hex-convert
$readin = [System.IO.File]::ReadAllBytes("C:\OldFile.exe");
$hx = Convert-ByteArrayToHexString $readin -width 40 -delimiter "";
$hx = $hx -replace "123456","FFFFFF";
$hx = "0x" + $hx;
$writeout = Convert-HexStringToByteArray $hx;
set-content -value $writeout -encoding byte -path "C:\NewFile.exe";
我们如何在powershell中指定偏移位置来替换此粗略的-replace命令。
您已经有一个字节数组,因此您可以简单地在任何给定的偏移量处修改字节。
$bytes = [System.IO.File]::ReadAllBytes("C:\OldFile.exe")
$offset = 23
$bytes[$offset] = 0xFF
$bytes[$offset+1] = 0xFF
$bytes[$offset+2] = 0xFF
[System.IO.File]::WriteAllBytes("C:\NewFile.exe", $bytes)
据我所知,无需对字节流进行任何十六进制转换即可进行替换。您可以只在十进制值列表(默认字符串转换)上进行替换,其中值以空格(字尾)为界,例如:(我正在跳过文件输入/输出,这已经在answer from @mklement0中进行了解释]
$bInput = [Byte[]](0x69, 0x52, 0x6f, 0x6e, 0x57, 0x61, 0x73, 0x48, 0x65, 0x72, 0x65)
$bOriginal = [Byte[]](0x57, 0x61, 0x73, 0x48)
$bSubstitute = [Byte[]](0x20, 0x77, 0x61, 0x73, 0x20, 0x68 -as [Byte[]])
$bOutput = [Byte[]]("$bInput" -Replace "\b$bOriginal\b", "$bSubstitute" -Split '\s+')
如果您想使用十六进制字符串(例如,替换参数),则可以将十六进制字符串转换为字节数组,如下所示:[Byte[]]('123456' -Split '(..)' | ? { $_ } | % {[Convert]::toint16($_, 16)})
请注意,此解决方案支持不同的$bOriginal
和$bSubstitute
长度。在这种情况下,如果您想从特定的偏移量开始替换,则可能要使用Select-Object
cmdlet:
Select-Object
可能是PowerShell最惯用的方式:
$Offset = 3
$bArray = $bInput | Select -Skip $Offset
$bArray = [Byte[]]("$bArray" -Replace "\b$bOriginal\b", "$bSubstitute" -Split '\s+')
$bOutput = ($bInput | Select -First $Offset) + $bArray
我们如何在PowerShell中指定偏移位置来替换此粗略的
$offset = 0x3C [byte[]]$bytes = Get-Content C:\OldFile.exe -Encoding Byte -Raw $bytes[$offset++] = 0xFF $bytes[$offset++] = 0xFF $bytes[$offset] = 0xFF ,$bytes |Set-Content C:\NewFile.exe -Encoding Byte
命令。
[-replace
解决了偏移量问题,Ansgar Wiechers' helpful answer显示了更多PowerShell惯用语变体。
就是说,这听起来像是如果您有一种解决方案,仅替换出现在搜索字符串中的[[first,则原始的解决方案可能会起作用。
PowerShell的brianary's helpful answer运算符和.NET的-replace
方法都没有将替换限制为一个
解决方法:
String.Replace()
$hx = $hx -replace '(?s)123456(.*)', 'FFFFFF$1'
是一个内联正则表达式选项,它使正则表达式元字符(?s)
也匹配newlines
.
捕获捕获组1中的所有remaining
(.*)
引用它们,这实际上删除了first事件。 (有关$1
和替换操作数的语法的更多信息,请参见this answer。)>搜索字符串
刚好包含您想直接使用的正则表达式元字符,请-replace
分别转义它们,或更普遍地,将整个搜索词传递给\
。替换字符串
恰好包含您想直接使用的[regex]::Escape()
字符,请$
进行转义,或更笼统地将$
(原文如此)。不是完全鲁棒的解决方案,因为不能保证搜索字符串将在一个字节边界;例如,即使输入字符串中没有由字节 将构成字节的数字分别用空格隔开-replace '\$', '$$$$'
和iRon组成的byte 12
,单字节搜索字符串12
也会与0123
中的中间12
匹配。为了解决这种歧义,输入“字节字符串”和搜索字符串的结构必须不同:只需
全PowerShell解决方案
(PSv4 +),不需要第三方功能:注意:搜索和替换字符串
构造为带有空格分隔的十六进制的“字节字符串”。从字节数组输入创建的表示形式,使用与从input01
->23
(0x12, 0x34, 0x56, 0x1).ForEach('ToString', 'X') -join ' '
等效于在每个数组元素上调用'12 34 56 1'
并收集结果。.ForEach('ToString', 'X')
的值(例如.ToString('X')
而不是0x10
),也请使用01
,这会增加内存消耗但是。另外,您还必须在搜索字符串中为1
前缀一位数字字节值,例如:'X2'
0