Private/Test-FoFileGate.ps1
|
function Test-FoPathMask { param( [string]$Path, [string]$Mask ) if ([string]::IsNullOrWhiteSpace($Mask)) { return $true } $tokens = $Mask.Split(',') | ForEach-Object { $_.Trim() } | Where-Object { $_ } foreach ($t in $tokens) { if ($Path -like "*$t*") { return $true } } return $false } function Test-FoFileGate { [CmdletBinding()] [OutputType([hashtable])] param( [Parameter(Mandatory)] [string]$Path, [hashtable]$Settings ) if ($Settings.IncludeMask -and -not (Test-FoPathMask -Path $Path -Mask $Settings.IncludeMask)) { return @{ Pass = $false; Reason = 'IncludeMask' } } if ($Settings.ExcludeMask -and (Test-FoPathMask -Path $Path -Mask $Settings.ExcludeMask)) { return @{ Pass = $false; Reason = 'ExcludeMask' } } if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) { return @{ Pass = $false; Reason = 'NotFound' } } return @{ Pass = $true; Reason = $null } } function Test-FoIsAPNG { param([string]$Path) try { $fs = [System.IO.File]::OpenRead($Path) try { $br = New-Object System.IO.BinaryReader($fs) $sig = $br.ReadBytes(8) if ($sig.Length -lt 8) { return $false } $pngSig = [byte[]](0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A) for ($i = 0; $i -lt 8; $i++) { if ($sig[$i] -ne $pngSig[$i]) { return $false } } while ($fs.Position -lt $fs.Length) { if (($fs.Length - $fs.Position) -lt 8) { return $false } $lenBytes = $br.ReadBytes(4) $length = ([uint32]$lenBytes[0] -shl 24) -bor ([uint32]$lenBytes[1] -shl 16) -bor ([uint32]$lenBytes[2] -shl 8) -bor [uint32]$lenBytes[3] $type = [System.Text.Encoding]::ASCII.GetString($br.ReadBytes(4)) if ($type -eq 'acTL' -or $type -eq 'fcTL' -or $type -eq 'fdAT') { return $true } $skip = [int64]$length + 4 if ($skip -lt 0 -or ($fs.Position + $skip) -gt $fs.Length) { return $false } if ($skip -gt 0) { $fs.Position += $skip } } return $false } finally { $fs.Dispose() } } catch { return $false } } function Test-FoIsPNG9Patch { param([string]$Path) if ($Path -like '*.9.png') { return $true } try { $fs = [System.IO.File]::OpenRead($Path) try { $br = New-Object System.IO.BinaryReader($fs) $sig = $br.ReadBytes(8) if ($sig.Length -lt 8) { return $false } $pngSig = [byte[]](0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A) for ($i = 0; $i -lt 8; $i++) { if ($sig[$i] -ne $pngSig[$i]) { return $false } } while ($fs.Position -lt $fs.Length) { if (($fs.Length - $fs.Position) -lt 8) { return $false } $lenBytes = $br.ReadBytes(4) $length = ([uint32]$lenBytes[0] -shl 24) -bor ([uint32]$lenBytes[1] -shl 16) -bor ([uint32]$lenBytes[2] -shl 8) -bor [uint32]$lenBytes[3] $type = [System.Text.Encoding]::ASCII.GetString($br.ReadBytes(4)) if ($type -eq 'npTc' -or $type -eq 'npLb') { return $true } $skip = [int64]$length + 4 if ($skip -lt 0 -or ($fs.Position + $skip) -gt $fs.Length) { return $false } if ($skip -gt 0) { $fs.Position += $skip } } return $false } finally { $fs.Dispose() } } catch { return $false } } function Get-FoFileHeaderBytes { param( [string]$Path, [int]$MaxBytes = 524288 ) try { $fs = [System.IO.File]::OpenRead($Path) try { $len = [Math]::Min($MaxBytes, $fs.Length) if ($len -le 0) { return $null } $buf = New-Object byte[] $len [void]$fs.Read($buf, 0, $len) return $buf } finally { $fs.Dispose() } } catch { return $null } } function Test-FoBufferContainsBytes { param( [byte[]]$Buffer, [byte[]]$Pattern ) if (-not $Buffer -or -not $Pattern -or $Pattern.Length -eq 0 -or $Buffer.Length -lt $Pattern.Length) { return $false } for ($i = 0; $i -le ($Buffer.Length - $Pattern.Length); $i++) { $matched = $true for ($j = 0; $j -lt $Pattern.Length; $j++) { if ($Buffer[$i + $j] -ne $Pattern[$j]) { $matched = $false break } } if ($matched) { return $true } } return $false } function Test-FoBufferContainsAscii { param( [byte[]]$Buffer, [string]$Text ) if (-not $Buffer -or [string]::IsNullOrEmpty($Text)) { return $false } $pattern = [System.Text.Encoding]::ASCII.GetBytes($Text) return Test-FoBufferContainsBytes -Buffer $Buffer -Pattern $pattern } function Test-FoIsEXESFX { param([string]$Path) $buf = Get-FoFileHeaderBytes -Path $Path -MaxBytes 1048576 if (-not $buf -or $buf.Length -lt 2) { return $false } if (-not (Test-FoBufferContainsBytes -Buffer $buf -Pattern ([byte[]](0x4D, 0x5A))) -and -not (Test-FoBufferContainsBytes -Buffer $buf -Pattern ([byte[]](0x5A, 0x4D)))) { return $false } foreach ($marker in @( 'Inno Setup' 'InstallShield' 'Nullsoft Install System' 'RTPatch' )) { if (Test-FoBufferContainsAscii -Buffer $buf -Text $marker) { return $true } } foreach ($pattern in @( [byte[]](0x52, 0x61, 0x72, 0x21, 0x1A, 0x07) [byte[]](0x50, 0x4B, 0x03, 0x04) [byte[]](0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C) [byte[]](0x4D, 0x53, 0x43, 0x46) )) { if (Test-FoBufferContainsBytes -Buffer $buf -Pattern $pattern) { return $true } } return $false } function Test-FoIsZipSFX { param([string]$Path) return Test-FoIsEXESFX -Path $Path } function Test-FoIsPDFLayered { param([string]$Path) $buf = Get-FoFileHeaderBytes -Path $Path -MaxBytes 524288 if (-not $buf) { return $false } return Test-FoBufferContainsAscii -Buffer $buf -Text '<< /Type /OCG /Name' } function Test-FoIsJPEGCMYK { param([string]$Path) $buf = Get-FoFileHeaderBytes -Path $Path -MaxBytes 524288 if (-not $buf) { return $false } $start = 0 while ($true) { $idx = -1 for ($i = $start; $i -le ($buf.Length - 2); $i++) { if ($buf[$i] -eq 0xFF -and $buf[$i + 1] -eq 0xC0) { $idx = $i break } } if ($idx -lt 0) { return $false } $searchFrom = $idx $progIdx = -1 for ($i = $searchFrom; $i -le ($buf.Length - 2); $i++) { if ($buf[$i] -eq 0xFF -and $buf[$i + 1] -eq 0xC2) { $progIdx = $i break } } if ($progIdx -ge 0 -and ($progIdx + 9) -lt $buf.Length) { return ($buf[$progIdx + 9] -eq 4) } $start = $idx + 2 if ($start -ge $buf.Length) { return $false } } } function New-FoFileContext { param( [string]$InputFile, [hashtable]$Settings ) $ext = [System.IO.Path]::GetExtension($InputFile).ToLowerInvariant() $detected = Get-ExtensionByContent -Path $InputFile -Extension $ext -Settings $Settings @{ InputFile = $InputFile Extension = $detected Settings = $Settings IsAPNG = (Test-FoIsAPNG -Path $InputFile) IsPNG9Patch = (Test-FoIsPNG9Patch -Path $InputFile) IsZipSFX = (Test-FoIsZipSFX -Path $InputFile) IsEXESFX = (Test-FoIsEXESFX -Path $InputFile) IsJPEGCMYK = (Test-FoIsJPEGCMYK -Path $InputFile) IsPDFLayered = (Test-FoIsPDFLayered -Path $InputFile) } } |