他來了,他來了,他又帶著bug走來了!
5月底,微軟釋出的一份最新文件,稱修復了一個令眾多使用者苦惱的問題。Win10 檔案管理器中存在一個 Bug,可使部分 FLAC 格式音訊檔案損壞。(好傢伙,無損變全損,這我可受不住)
微軟稱,在 Win10 2004 及以上版本中,如果使用檔案管理器修改 FLAC 音訊檔案的後設資料,比如標題、藝術家或者其他音訊後設資料,將使 FLAC 檔案損壞,無法播放。
部分 FLAC 檔案開頭會包含 ID3 幀頭,其中包含歌手、標題、專輯名稱、年代、風格等資訊。
而在 Win10 2004 及以上版本中,檔案資源管理器會忽略 ID3 幀頭,因為它預設判定 FLAC 檔案使用 4 位元組 fLaC 開頭。因此當使用者使用檔案資源管理器修改 FLAC 檔案的後設資料時,就會把 ID3 幀頭覆蓋掉,從而破壞原有的 FLAC 檔案結構,使音樂播放器無法正常識別。
該bug影響多個Windows 10版本(Home、Pro、Enterprise、Education、Pro Education和Pro for工作站)和版本2004和版本20H2。
微軟已針對該 Bug 釋出了緊急修復更新,在 KB5003214 更新中,微軟確認已修復該問題,大家安裝即可。
除了KB 5003214更新,微軟還提供了一個PowerShell指令碼,可用於修復以前損壞的FLAC音樂檔案。
要修復FLAC檔案,請按照以下步驟操作:
1. 開啟notepad,並輸入下方內容
# Copyright 2021 Microsoft
# This script will repair a FLAC file that has been corrupted by Media Foundation in reference to KB5003430.
# Refer to KB5003430 for further information
param(
[parameter(Mandatory=$true,
HelpMessage="The path to the FLAC file that has been corrupted by Media Foundation",
ValueFromRemainingArguments=$true)]
[ValidateScript({ -not [String]::IsNullOrEmpty($_) -and (Test-Path $_) })]
[String]$File
)
# We need to back up the current file incase we have any errors
$FileDirectory = Split-Path -Resolve $File
$Filename = Split-Path -Leaf -Resolve $File
$FullPath = Join-Path -Resolve $FileDirectory $Filename
$Filename = [String]::Format("Backup_{0:yyyyMMdd_hhmmss}_{1}", [DateTime]::Now, $Filename)
$BackupLocation = Join-Path $FileDirectory $Filename
Write-Output "Microsoft FLAC Repair Tool. This tool will repair a FLAC audio file that was corrupted when editing its details."
Write-Output "Affected File: $FullPath"
Write-Output "A backup of the file will be made: $BackupLocation"
Write-Output "Do you wish to continue?"
$choice=$host.ui.PromptForChoice("Fixing FLAC Script", "Do you wish to continue", ('&Yes', '&No'), 1)
function ParseStreamInfoMetadataBlock([System.IO.FileStream]$stream)
{
$blockType = $stream.ReadByte()
$lastBlock = ($blockType -shr 7) -ne 0
$blockType = $blockType -band 0x7F
if ($blockType -ne 0)
{
return $false
}
$blockSize = (($stream.ReadByte() -shl 16) -bor ($stream.ReadByte() -shl 8) -bor $stream.ReadByte())
if ($blockSize -lt 34)
{
return $false
}
$minAudioBlockSize = ($stream.ReadByte() -shl 8) -bor $stream.ReadByte()
$maxAudioBlockSize = ($stream.ReadByte() -shl 8) -bor $stream.ReadByte()
if ($minAudioBlockSize -lt 16 -or $maxAudioBlockSize -lt 16)
{
return $false
}
$minFrameSize = (($stream.ReadByte() -shl 16) -bor ($stream.ReadByte() -shl 8) -bor $stream.ReadByte())
$maxFrameSize = (($stream.ReadByte() -shl 16) -bor ($stream.ReadByte() -shl 8) -bor $stream.ReadByte())
$sampleInfo = (($stream.ReadByte() -shl 24) -bor ($stream.ReadByte() -shl 16) -bor ($stream.ReadByte() -shl 8) -bor $stream.ReadByte())
$sampleRate = $sampleInfo -shr 12
$channelCount = (($sampleInfo -shr 9) -band 0x7) + 1
$bitsPerSample = (($sampleInfo -shr 4) -band 0x1F) + 1
[UInt64]$sampleCount = (($stream.ReadByte() -shl 24) -bor ($stream.ReadByte() -shl 16) -bor ($stream.ReadByte() -shl 8) -bor $stream.ReadByte())
$sampleCount = (([UInt64]$sampleInfo -band 0xF) -shl 32) -bor $sampleCount
$MD5HashBytes = New-Object byte[] 16
$stream.Read($MD5HashBytes, 0, $MD5HashBytes.Length)
$MD5Hash = [Guid]($MD5HashBytes)
if ($sampleRate -eq 0)
{
return $false
}
# Passing these checks means that we likely have a stream info header and can rebuild the file
Write-Output "File Stream Information"
Write-Output "Sample Rate: $sampleRate"
Write-Output "Audio Channels: $channelCount"
Write-Output "Sample Depth: $bitsPerSample"
Write-Output "MD5 Audio Sample Hash: $MD5Hash"
return $true
}
if ($choice -eq 0)
{
Copy-Item $FullPath -Destination $BackupLocation -Force
$stream = [System.IO.File]::Open($FullPath, [System.IO.FileMode]::Open)
$stream.Seek(4, [System.IO.SeekOrigin]::Begin)
while ($stream.ReadByte() -eq 0) {}
# We now need to figure out where a valid FLAC metadata frame begins
# We are likely pointing to the last byte of the size member so we'll seek back 4 bytes and retry
$flacDataStartPosition = $stream.Position - 4
$stream.Seek($flacDataStartPosition, [System.IO.SeekOrigin]::Begin)
while (-not(ParseStreamInfoMetadataBlock($stream)))
{
$flacDataStartPosition = $flacDataStartPosition + 1
$stream.Seek($flacDataStartPosition, [System.IO.SeekOrigin]::Begin)
}
# Insert the start code
$stream.Seek($flacDataStartPosition, [System.IO.SeekOrigin]::Begin)
if (Test-Path "$FullPath.tmp")
{
Remove-Item "$FullPath.tmp"
}
$fixedStream = [System.IO.File]::Open("$FullPath.tmp", [System.IO.FileMode]::CreateNew)
[byte[]]$startCode = [char[]]('f', 'L', 'a', 'C');
$fixedStream.Write($startCode, 0, $startCode.Length)
$stream.CopyTo($fixedStream)
$stream.Close()
$fixedStream.Close()
Move-Item -Force "$FullPath.tmp" $FullPath
}
2. 點選儲存,將檔案儲存為 FixFlacFiles.ps1,儲存型別設定為(*.txt)
3. 在Windows資源管理器中找到儲存的PowerShell指令碼,然後單擊「使用PowerShell執行」
4. 在彈出的對話方塊中,輸入不可播放的fLAC檔案的檔名,然後點選「enter」
公眾號ID:ikanxue
官方微博:看雪安全
商務合作:wsc@kanxue.com