Search code examples
powershellbinaryfiles

delete some sequence of bytes in Powershell


I have a *.bin file. How can I delete with poweshell some part of bytes (29 bytes, marked yellow) with repeatig sequence of bytes (12 bytes, marked red pen)? Thanks a lot!!

enter image description here


Solution

  • Using a very helpful article and ditto function I found here, it seems it is posible to read a binary file and convert it to a string while not altering any of the bytes by using Codepage 28591.

    With that (I slightly changed the function), you can do this to delete the bytes in your *.bin file:

    function ConvertTo-BinaryString {
        # converts the bytes of a file to a string that has a
        # 1-to-1 mapping back to the file's original bytes. 
        # Useful for performing binary regular expressions.
        [OutputType([String])]
        Param (
            [Parameter(Mandatory = $True, ValueFromPipeline = $True, Position = 0)]
            [ValidateScript( { Test-Path $_ -PathType Leaf } )]
            [String]$Path
        )
    
        $Stream = New-Object System.IO.FileStream -ArgumentList $Path, 'Open', 'Read'
    
        # Note: Codepage 28591 returns a 1-to-1 char to byte mapping
        $Encoding     = [Text.Encoding]::GetEncoding(28591)
        $StreamReader = New-Object System.IO.StreamReader -ArgumentList $Stream, $Encoding
        $BinaryText   = $StreamReader.ReadToEnd()
    
        $StreamReader.Close()
        $Stream.Close()
    
        return $BinaryText
    }
    
    $inputFile  = 'D:\test.bin'
    $outputFile = 'D:\test2.bin'
    $fileBytes  = [System.IO.File]::ReadAllBytes($inputFile)
    $binString  = ConvertTo-BinaryString -Path $inputFile
    
    # create your regex: 17 bytes in range of \x00 to \xFF followed by 12 bytes specific range
    $re = [Regex]'[\x00-\xFF]{17}\xEB\x6F\xD3\x01\x18\x00{3}\xFF{3}\xFE'
    
    # use a MemoryStream object to store the result
    $ms  = New-Object System.IO.MemoryStream
    $pos = $replacements = 0
    
    $re.Matches($binString) | ForEach-Object {
        # write the part of the byte array before the match to the MemoryStream
        $ms.Write($fileBytes, $pos, $_.Index)
        # update the 'cursor' position for the next match
        $pos += ($_.Index + $_.Length)
        # and count the number of replacements done
        $replacements++
    }
    
    # write the remainder of the bytes to the stream
    $ms.Write($fileBytes, $pos, $fileBytes.Count - $pos)
    
    # save the updated bytes to a new file (will overwrite existing file)
    [System.IO.File]::WriteAllBytes($outputFile, $ms.ToArray())
    $ms.Dispose()
    
    if ($replacements) {
        Write-Host "$replacements replacement(s) made."
    }
    else {
        Write-Host "Byte sequence not found. No replacements made."
    }