Files

121 lines
3.9 KiB
PowerShell

param(
[Parameter(Mandatory = $true)]
[string]$GoodFile,
[Parameter(Mandatory = $true)]
[string]$BadFile,
[int]$ContextBytes = 32,
[int]$MaxDifferences = 200
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
function Format-Byte {
param([byte]$Value)
if ($Value -eq 0x0D) { return "CR" }
if ($Value -eq 0x0A) { return "LF" }
if ($Value -eq 0x09) { return "TAB" }
if ($Value -eq 0x12) { return "DC2" }
if ($Value -eq 0x14) { return "DC4" }
if ($Value -eq 0x20) { return "SPACE" }
if ($Value -ge 32 -and $Value -le 126) { return [char]$Value }
return "."
}
function Format-Bytes {
param(
[byte[]]$Bytes,
[int]$Start,
[int]$Count
)
if ($Bytes.Length -eq 0) { return "" }
$safeStart = [Math]::Max(0, $Start)
$safeEnd = [Math]::Min($Bytes.Length - 1, $safeStart + $Count - 1)
if ($safeStart -gt $safeEnd) { return "" }
$hex = New-Object System.Collections.Generic.List[string]
$txt = New-Object System.Collections.Generic.List[string]
for ($i = $safeStart; $i -le $safeEnd; $i++) {
$hex.Add($Bytes[$i].ToString("X2"))
$txt.Add((Format-Byte $Bytes[$i]))
}
return ("HEX: " + ($hex -join " ") + [Environment]::NewLine + "TXT: " + ($txt -join " "))
}
$goodPath = (Resolve-Path -LiteralPath $GoodFile).Path
$badPath = (Resolve-Path -LiteralPath $BadFile).Path
$good = [System.IO.File]::ReadAllBytes($goodPath)
$bad = [System.IO.File]::ReadAllBytes($badPath)
Write-Host "GOOD: $goodPath"
Write-Host "BAD : $badPath"
Write-Host "GOOD length: $($good.Length) bytes"
Write-Host "BAD length: $($bad.Length) bytes"
Write-Host ""
$limit = [Math]::Min($good.Length, $bad.Length)
$diffCount = 0
for ($i = 0; $i -lt $limit; $i++) {
if ($good[$i] -ne $bad[$i]) {
$diffCount++
if ($diffCount -le $MaxDifferences) {
Write-Host ("Difference #{0} at byte {1} / 0x{1:X}" -f $diffCount, $i)
Write-Host (" GOOD: 0x{0} [{1}]" -f $good[$i].ToString("X2"), (Format-Byte $good[$i]))
Write-Host (" BAD : 0x{0} [{1}]" -f $bad[$i].ToString("X2"), (Format-Byte $bad[$i]))
Write-Host " GOOD context:"
Write-Host (Format-Bytes $good ($i - $ContextBytes) (($ContextBytes * 2) + 1))
Write-Host " BAD context:"
Write-Host (Format-Bytes $bad ($i - $ContextBytes) (($ContextBytes * 2) + 1))
Write-Host ""
}
}
}
if ($good.Length -ne $bad.Length) {
Write-Host "Files have different length."
if ($good.Length -gt $bad.Length) {
Write-Host "GOOD has extra bytes from offset $($bad.Length) / 0x$($bad.Length.ToString("X")):"
Write-Host (Format-Bytes $good $bad.Length ([Math]::Min(256, $good.Length - $bad.Length)))
} else {
Write-Host "BAD has extra bytes from offset $($good.Length) / 0x$($good.Length.ToString("X")):"
Write-Host (Format-Bytes $bad $good.Length ([Math]::Min(256, $bad.Length - $good.Length)))
}
Write-Host ""
}
Write-Host "Total differing byte positions in common length: $diffCount"
$badControls = @{}
for ($i = 0; $i -lt $bad.Length; $i++) {
$b = $bad[$i]
$allowed = $b -eq 0x09 -or $b -eq 0x0A -or $b -eq 0x0D -or ($b -ge 0x20 -and $b -le 0x7E)
if (-not $allowed) {
$key = "0x" + $b.ToString("X2") + " " + (Format-Byte $b)
if (-not $badControls.ContainsKey($key)) {
$badControls[$key] = New-Object System.Collections.Generic.List[int]
}
if ($badControls[$key].Count -lt 20) {
$badControls[$key].Add($i)
}
}
}
Write-Host ""
Write-Host "Suspicious bytes in BAD file, excluding TAB/CR/LF/ASCII printable:"
if ($badControls.Count -eq 0) {
Write-Host " none"
} else {
foreach ($entry in $badControls.GetEnumerator() | Sort-Object Name) {
Write-Host (" {0}: offsets {1}" -f $entry.Key, (($entry.Value | ForEach-Object { "$_ / 0x$($_.ToString("X"))" }) -join ", "))
}
}