通过Powershell十六进制编辑二进制文件的方法

问题描述 投票:9回答:4

我试图仅使用powershell从命令行执行二进制十六进制编辑。用此片段执行六角替换已取得部分成功。当多次出现123456并且仅在特定位置发生替换时,问题就会出现。

注意:片段需要此处的Convert-ByteArrayToHexStringConvert-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命令。

powershell binary hex powershell-2.0 patch
4个回答
15
投票

您已经有一个字节数组,因此您可以简单地在任何给定的偏移量处修改字节。

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

1
投票

据我所知,无需对字节流进行任何十六进制转换即可进行替换。您可以只在十进制值列表(默认字符串转换)上进行替换,其中值以空格(字尾)为界,例如:(我正在跳过文件输入/输出,这已经在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

1
投票

可能是PowerShell最惯用的方式:

$Offset = 3
$bArray = $bInput | Select -Skip $Offset
$bArray = [Byte[]]("$bArray" -Replace "\b$bOriginal\b", "$bSubstitute" -Split '\s+')
$bOutput = ($bInput | Select -First $Offset) + $bArray

1
投票

我们如何在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()字符,请$进行转义,或更笼统地将$(原文如此)。
  • 但是,正如[C​​0]指出的那样,尽管以上解决了一次只能替换的问题,但它是

    不是完全鲁棒的解决方案,因为不能保证搜索字符串将在一个字节边界;例如,即使输入字符串中没有由字节-replace '\$', '$$$$'iRon组成的byte 12,单字节搜索字符串12也会与0123中的中间12匹配。为了解决这种歧义,输入“字节字符串”和搜索字符串的结构必须不同:只需

    将构成字节的数字分别用空格隔开

    ,如下所示。


    搜索

    代替字节序列,而不是固定的偏移量:这里是

    全PowerShell解决方案

    (PSv4 +),不需要第三方功能:注意:

    • 正如您尝试的那样,立即读取整个文件的内容,并执行往返字符串的转换; PSv4 +语法

    • 搜索和替换字符串

      构造为带有空格分隔的十六进制的“字节字符串”。从字节数组输入创建的表示形式,使用与从input
    • 构造字节字符串相同的方法,如下所示,例如:]]
        01->23
        • [(0x12, 0x34, 0x56, 0x1).ForEach('ToString', 'X') -join ' '等效于在每个数组元素上调用'12 34 56 1'并收集结果。
  • [如果希望每个字节一致地表示为
  • two
  • 十六进制数字,即使对于小于.ForEach('ToString', 'X')的值(例如.ToString('X')而不是0x10),也请使用01,这会增加内存消耗但是。另外,您还必须在搜索字符串中为1前缀一位数字字节值,例如:'X2'0
    © www.soinside.com 2019 - 2024. All rights reserved.