Created
July 8, 2024 13:10
-
-
Save Drovosek01/9d47068365ea0bce26526ee61b23be7c to your computer and use it in GitHub Desktop.
Native way on Windows for find and replace bytes like hex squence in file
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# TODO: Add counter for search replace pattern | |
# TODO: Add support regexp like here - https://stackoverflow.com/a/55314611 | |
# Example usage in Windows Powershell: | |
# .\ReplaceHexBytesAll.ps1 -filePath "D:\TEMP\file.exe" -patterns "4883EC28BA2F000000488D0DB0B7380A/11111111111111111111111111111111","C4252A0A48894518488D5518488D4D68/11111111111111111111111111111111","45A8488D55A8488D4D68E8618C1E05BA/1111111111111111111111111111111" | |
# Main script | |
param ( | |
[Parameter(Mandatory)] | |
[string]$filePath, | |
# One pattern is string with search/replace hex like "AABB/1122" or "AABB,1122" or "\xAA\xBB/\x11\x22" | |
[Parameter(Mandatory)] | |
[string[]]$patterns | |
) | |
if (-not (Test-Path $filePath)) { | |
Write-Error "File not found: $filePath" | |
exit 1 | |
} | |
# Function to convert hex string to byte array | |
function Convert-HexStringToByteArray { | |
param ( | |
[string]$hexString | |
) | |
$hexString = $hexString -replace ' ', '' | |
if ($hexString.Length % 2 -ne 0) { | |
throw "Invalid hex string length." | |
} | |
[byte[]]$byteArray = @() | |
for ($i = 0; $i -lt $hexString.Length; $i += 2) { | |
$byteArray += [Convert]::ToByte($hexString.Substring($i, 2), 16) | |
} | |
return $byteArray | |
} | |
# Function for clean hex string and separate search and replace patterns | |
function Separate-Patterns { | |
param ( | |
[Parameter(Mandatory)] | |
[string[]]$patterns | |
) | |
[System.Collections.ArrayList]$searchBytes = New-Object System.Collections.ArrayList | |
[System.Collections.ArrayList]$replaceBytes = New-Object System.Collections.ArrayList | |
foreach ($pattern in $patterns) { | |
$temp = $pattern.Clone().Replace("\x","").Replace(",","/").Replace("\","/").Split("/") | |
if ($temp.Count -gt 2) { | |
throw "Wrong pattern $pattern" | |
} | |
[byte[]]$searchHexPattern = (Convert-HexStringToByteArray -hexString $temp[0]) | |
[byte[]]$replaceHexPattern = (Convert-HexStringToByteArray -hexString $temp[1]) | |
[System.Collections.ArrayList]$searchBytes += , $searchHexPattern | |
[System.Collections.ArrayList]$replaceBytes += , $replaceHexPattern | |
} | |
return $searchBytes, $replaceBytes | |
} | |
# Function to search and replace hex patterns in a binary file | |
function SearchAndReplace-HexPatternInBinaryFile { | |
param ( | |
[Parameter(Mandatory)] | |
[string]$filePath, | |
[string[]]$patterns | |
) | |
if ($patterns.Count -eq 0) { | |
throw "No patterns given" | |
} | |
[System.Collections.ArrayList]$handledPatterns = Separate-Patterns $patterns | |
[System.Collections.ArrayList]$searchBytes = $handledPatterns[0] | |
[System.Collections.ArrayList]$replaceBytes = $handledPatterns[1] | |
[byte[]]$fileBytes = [System.IO.File]::ReadAllBytes($filePath) | |
[int[]]$foundPatternsIndexes = @() | |
for ($i = 0; $i -lt $patterns.Count; $i++) { | |
[int]$searchLength = $searchBytes[$i].Length | |
[int]$index = 0 | |
while ($index -lt $fileBytes.Length) { | |
$foundIndex = [Array]::IndexOf($fileBytes, $searchBytes[$i][0], $index) | |
if ($foundIndex -eq -1) { | |
break | |
} | |
$match = $true | |
for ($x = 1; $x -lt $searchLength; $x++) { | |
if ($fileBytes[$foundIndex + $x] -ne $searchBytes[$i][$x]) { | |
$match = $false | |
break | |
} | |
} | |
if ($match) { | |
[Array]::Copy($replaceBytes[$i], 0, $fileBytes, $foundIndex, $searchLength) | |
$index = $foundIndex + $searchLength | |
$foundPatternsIndexes += $i | |
} else { | |
$index = $foundIndex + 1 | |
} | |
} | |
} | |
# Not re-write file if hex-patterns not found in file | |
if (!($foundPatternsIndexes.Count -eq 0)) { | |
[System.IO.File]::WriteAllBytes($filePath, $fileBytes) | |
} | |
return $foundPatternsIndexes | |
} | |
$watch = [System.Diagnostics.Stopwatch]::StartNew() | |
$watch.Start() # launch timer | |
try { | |
$foundPatternsIndexes = SearchAndReplace-HexPatternInBinaryFile -filePath $filePath -patterns $patterns | |
[string]$notFoundPatterns = '' | |
if ($foundPatternsIndexes.Count -eq 0) { | |
Write-Host "No patterns was found" | |
} | |
elseif ($foundPatternsIndexes.Count -eq $patterns.Count) { | |
Write-Host "All hex patterns found and replaced successfully in $filePath" | |
} | |
else { | |
[int[]]$notFoundPatternsIndexes = (0..$patterns.Count).Where({$_ -notin $foundPatternsIndexes}) | |
for ($i = 0; $i -lt $notFoundPatternsIndexes.Count; $i++) { | |
$notFoundPatterns += ' ' + $patterns[$notFoundPatternsIndexes[$i]] | |
} | |
Write-Host "Hex patterns" $notFoundPatterns.Trim() "- not found, but other given patterns found and replaced successfully in $filePath" | |
} | |
} catch { | |
Write-Error $_.Exception.Message | |
exit 1 | |
} | |
$watch.Stop() # stop timer | |
Write-Host "Script execution time is" $watch.Elapsed # time of execution code |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Update 2