Skip to content

Instantly share code, notes, and snippets.

@Drovosek01
Created July 8, 2024 13:10
Show Gist options
  • Save Drovosek01/9d47068365ea0bce26526ee61b23be7c to your computer and use it in GitHub Desktop.
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
# 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