Use PowerShell to find and replace hex values in binary files [duplicate]

点点圈 提交于 2019-12-08 04:08:54

问题


UPDATE: I got a working script to accomplish the task. I needed to batch process a bunch of files so it accepts a csv file formatted as FileName,OriginalHEX,CorrectedHEX. It's very slow even after limiting the search to the first 512 bytes. It could probably be written better and made faster. Thanks for the help.

UPDATE 2: Revised the search method to be faster but it's nowhere near as fast as a dedicated hex editor. Be aware that it's memory intensive. peaks around 32X the size of the file in RAM. 10MB=320MB of RAM. 100MB=3.2GB of RAM. I don't recommend for big files. It also saves to a new file instead of overwriting. Original file renamed as File.ext_original@date-time.

Import-CSV $PSScriptRoot\HEXCorrection.csv | ForEach-Object {
  $File = $_.'FileName'
  $Find = $_.'OriginalHEX'
  $Replace = $_.'CorrectedHEX'


  IF (([System.IO.File]::Exists("$PSScriptRoot\$File"))) {
    $Target = (Get-ChildItem -Path $PSScriptRoot\$File)
  } ELSE {
    Write-Host $File "- File Not Found`n" -ForegroundColor 'Red'
    RETURN
  }

  Write-Host "File:   "$Target.Name`n"Find:    "$Find`n"Replace: "$Replace
  $TargetLWT = $Target.LastWriteTime
  $TargetCT = $Target.CreationTime
  IF ($Target.IsReadOnly) {
    Write-Host $Target.Name "- Is Read-Only`n" -ForegroundColor 'Red'
    RETURN
  }
  $FindLen = $Find.Length
  $ReplaceLen = $Replace.Length
  $TargetLen = (1..$Target.Length)

  IF (!($FindLen %2 -eq 0) -OR !($ReplaceLen %2 -eq 0) -OR 
  [String]::IsNullOrEmpty($FindLen) -OR [String]::IsNullOrEmpty($ReplaceLen)) {
    Write-Host "Input hex values are not even or empty" -ForegroundColor 'DarkRed'
    RETURN
  } ELSEIF (
    $FindLen -ne $ReplaceLen) {
    Write-Host "Input hex values are different lengths" -ForegroundColor 'DarkYellow'
    RETURN
  }

  $FindAsBytes = New-Object System.Collections.ArrayList
  $Find -split '(.{2})' | ? {$_} | % { $FindAsBytes += [Convert]::ToInt64($_,16) }
  $ReplaceAsBytes = New-Object System.Collections.ArrayList
  $Replace -split '(.{2})' | ? {$_} | % { $ReplaceAsBytes += [Convert]::ToInt64($_,16) }
  # ^-- convert to base 10

  Write-Host "Starting Search"
  $FileBytes = [IO.File]::ReadAllBytes($Target)
  FOREACH ($Byte in $FileBytes) {
        $ByteCounter++
        IF ($Byte -eq [INT64]$FindAsBytes[0]) { TRY {
             (1..([INT64]$FindAsBytes.Count-1)) | % {
               $Test = ($FileBytes[[INT64]$ByteCounter-1+[INT64]$_] -eq $FindAsBytes[$_])
               IF ($Test -ne 'True') {
                 THROW
               }
  }
    Write-Host "Found at Byte:" $ByteCounter -ForegroundColor 'Green'
    (0..($ReplaceAsBytes.Count-1)) | % {
      $FileBytes[[INT64]$ByteCounter+[INT64]$_-1] = $ReplaceAsBytes[$_]}
  $Found = 'True'
  $BytesReplaces = $BytesReplaces + [INT64]$ReplaceAsBytes.Count
  }
CATCH {}
}

}
  IF ($Found -eq 'True'){
    [IO.File]::WriteAllBytes("$Target-temp", $FileBytes)
    $OriginalName = $Target.Name+'_Original'+'@'+(Get-Date).ToString('yyMMdd-HHmmss')
    Rename-Item -LiteralPath $Target.FullName -NewName $OriginalName
    Rename-Item $Target"-temp" -NewName $Target.Name
    #Preserve Last Modified Time
    $Target.LastWriteTime = $TargetLWT
    $Target.CreationTime = $TargetCT
    Write-Host $BytesReplaces "Bytes Replaced" -ForegroundColor 'Green'
    Write-Host "Original saved as:" $OriginalName
  } ELSE {
      Write-Host "No Matches" -ForegroundColor 'Red'}
    Write-Host "Finished Search`n"
    Remove-Variable -Name * -ErrorAction SilentlyContinue
} # end foreach from line 1

PAUSE

Original: This has been asked before but found no solutions to perform a simple and straight up find hex value and replace hex value on large files, 100MB+. Even better would be any recommendations for a hex editor with command line support for this task.


回答1:


Here's a first crack at it:

(get-content -encoding byte file) -replace '\b10\b',11 -as 'byte[]'

I was checking those other links, but the only answer that does search and replace has some bugs. I voted to reopen. The mklement0 one is close. None of them search and then print the position of the replacement.

Nevermind. Yours is faster and uses less memory.



来源:https://stackoverflow.com/questions/57336893/use-powershell-to-find-and-replace-hex-values-in-binary-files

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!