他来了,他来了,他又带着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