493 lines
16 KiB
PowerShell
493 lines
16 KiB
PowerShell
param(
|
|
[Parameter(Mandatory=$true)]
|
|
[string]$BootResDllPath,
|
|
|
|
[Parameter(Mandatory=$false)]
|
|
[string]$OutputFolder,
|
|
|
|
[switch]$ExtractAll,
|
|
|
|
[switch]$ShowInfo
|
|
)
|
|
|
|
# Boot logo sizes for Windows 10/11
|
|
# Note: Actual Windows 11 uses square logos (height x height)
|
|
# The original Windows 8/10 used wider rectangles
|
|
$LogoSizes = @(
|
|
@{Name="winlogo1.bmp"; Width=72; Height=72; Description="Small Logo"},
|
|
@{Name="winlogo2.bmp"; Width=90; Height=90; Description="Medium Logo"},
|
|
@{Name="winlogo3.bmp"; Width=115; Height=115; Description="Standard Logo"},
|
|
@{Name="winlogo3n.bmp"; Width=87; Height=115; Description="Narrow Logo"},
|
|
@{Name="winlogo4.bmp"; Width=214; Height=214; Description="Large Logo"},
|
|
@{Name="winlogo5.bmp"; Width=284; Height=284; Description="Extra Large Logo"}
|
|
)
|
|
|
|
# Function to log messages
|
|
function Write-Log {
|
|
param(
|
|
[string]$Message,
|
|
[string]$Color = "White"
|
|
)
|
|
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
|
Write-Host "[$timestamp] $Message" -ForegroundColor $Color
|
|
}
|
|
|
|
# Function to check if 7-Zip is available
|
|
function Test-7ZipAvailable {
|
|
$7zipPaths = @(
|
|
"C:\Program Files\7-Zip\7z.exe",
|
|
"C:\Program Files (x86)\7-Zip\7z.exe",
|
|
"$env:ProgramFiles\7-Zip\7z.exe"
|
|
)
|
|
|
|
foreach ($path in $7zipPaths) {
|
|
if (Test-Path $path) {
|
|
return $path
|
|
}
|
|
}
|
|
|
|
# Check if 7z is in PATH
|
|
try {
|
|
$null = Get-Command 7z -ErrorAction Stop
|
|
return "7z"
|
|
} catch {
|
|
return $null
|
|
}
|
|
}
|
|
|
|
# Function to get file version info
|
|
function Get-FileVersionInfo {
|
|
param([string]$FilePath)
|
|
|
|
try {
|
|
$versionInfo = [System.Diagnostics.FileVersionInfo]::GetVersionInfo($FilePath)
|
|
return @{
|
|
FileVersion = $versionInfo.FileVersion
|
|
ProductVersion = $versionInfo.ProductVersion
|
|
CompanyName = $versionInfo.CompanyName
|
|
FileDescription = $versionInfo.FileDescription
|
|
InternalName = $versionInfo.InternalName
|
|
OriginalFilename = $versionInfo.OriginalFilename
|
|
ProductName = $versionInfo.ProductName
|
|
}
|
|
} catch {
|
|
return $null
|
|
}
|
|
}
|
|
|
|
# Function to check digital signature
|
|
function Get-DigitalSignature {
|
|
param([string]$FilePath)
|
|
|
|
try {
|
|
$signature = Get-AuthenticodeSignature -FilePath $FilePath
|
|
return @{
|
|
Status = $signature.Status
|
|
SignerCertificate = $signature.SignerCertificate
|
|
TimeStamperCertificate = $signature.TimeStamperCertificate
|
|
IsSigned = $signature.Status -eq 'Valid'
|
|
SignerSubject = if ($signature.SignerCertificate) { $signature.SignerCertificate.Subject } else { "N/A" }
|
|
SignerIssuer = if ($signature.SignerCertificate) { $signature.SignerCertificate.Issuer } else { "N/A" }
|
|
}
|
|
} catch {
|
|
return @{
|
|
Status = "Error"
|
|
IsSigned = $false
|
|
SignerSubject = "N/A"
|
|
SignerIssuer = "N/A"
|
|
}
|
|
}
|
|
}
|
|
|
|
# Function to get file architecture (32-bit or 64-bit)
|
|
function Get-FileArchitecture {
|
|
param([string]$FilePath)
|
|
|
|
try {
|
|
$bytes = [System.IO.File]::ReadAllBytes($FilePath)
|
|
|
|
# Check DOS signature
|
|
if ($bytes[0] -ne 0x4D -or $bytes[1] -ne 0x5A) {
|
|
return "Unknown"
|
|
}
|
|
|
|
# Get PE header offset
|
|
$peOffset = [BitConverter]::ToInt32($bytes, 0x3C)
|
|
|
|
# Check PE signature
|
|
if ($bytes[$peOffset] -ne 0x50 -or $bytes[$peOffset + 1] -ne 0x45) {
|
|
return "Unknown"
|
|
}
|
|
|
|
# Get machine type
|
|
$machineType = [BitConverter]::ToUInt16($bytes, $peOffset + 4)
|
|
|
|
switch ($machineType) {
|
|
0x014C { return "32-bit (x86)" }
|
|
0x0200 { return "64-bit (IA64)" }
|
|
0x8664 { return "64-bit (x64)" }
|
|
default { return "Unknown ($machineType)" }
|
|
}
|
|
} catch {
|
|
return "Error reading file"
|
|
}
|
|
}
|
|
|
|
# Function to extract WIM from bootres.dll
|
|
function Extract-BootResWim {
|
|
param(
|
|
[string]$DllPath,
|
|
[string]$OutputPath,
|
|
[string]$SevenZipPath
|
|
)
|
|
|
|
Write-Log "Extracting WIM archive from bootres.dll..." -Color Cyan
|
|
|
|
# First, extract the PE resources
|
|
$extractArgs = @(
|
|
"e",
|
|
"`"$DllPath`"",
|
|
"-o`"$OutputPath`"",
|
|
"-r",
|
|
"-y"
|
|
)
|
|
|
|
$process = Start-Process -FilePath $SevenZipPath -ArgumentList $extractArgs -Wait -NoNewWindow -PassThru -RedirectStandardOutput "$OutputPath\7z_extract.log"
|
|
|
|
if ($process.ExitCode -ne 0) {
|
|
throw "Failed to extract resources from bootres.dll"
|
|
}
|
|
|
|
# Look for the WIM file - it might be named "1" or have .wim extension
|
|
$possibleWimFiles = @(
|
|
(Get-ChildItem -Path $OutputPath -Filter "*.wim" -ErrorAction SilentlyContinue),
|
|
(Get-ChildItem -Path $OutputPath -Filter "1" -ErrorAction SilentlyContinue),
|
|
(Get-ChildItem -Path $OutputPath -Filter "RCDATA" -ErrorAction SilentlyContinue)
|
|
) | Where-Object { $_ -ne $null } | Select-Object -First 1
|
|
|
|
if (-not $possibleWimFiles) {
|
|
# Try to find any file that starts with MSWIM signature
|
|
$allFiles = Get-ChildItem -Path $OutputPath -File
|
|
foreach ($file in $allFiles) {
|
|
try {
|
|
$bytes = [System.IO.File]::ReadAllBytes($file.FullName)
|
|
if ($bytes.Length -ge 6) {
|
|
$signature = [System.Text.Encoding]::ASCII.GetString($bytes[0..4])
|
|
if ($signature -eq "MSWIM") {
|
|
$wimPath = Join-Path $OutputPath "bootres.wim"
|
|
Move-Item -Path $file.FullName -Destination $wimPath -Force
|
|
return $wimPath
|
|
}
|
|
}
|
|
} catch {
|
|
continue
|
|
}
|
|
}
|
|
throw "No WIM file found after extraction. Files in output: $(($allFiles | Select-Object -ExpandProperty Name) -join ', ')"
|
|
}
|
|
|
|
$extractedWim = $possibleWimFiles
|
|
|
|
# Rename to bootres.wim if it has a different name
|
|
$wimPath = Join-Path $OutputPath "bootres.wim"
|
|
if ($extractedWim.FullName -ne $wimPath) {
|
|
Move-Item -Path $extractedWim.FullName -Destination $wimPath -Force
|
|
}
|
|
|
|
return $wimPath
|
|
}
|
|
|
|
# Function to list contents of WIM
|
|
function Get-WimContents {
|
|
param(
|
|
[string]$WimPath,
|
|
[string]$SevenZipPath
|
|
)
|
|
|
|
Write-Log "Listing contents of WIM archive..." -Color Cyan
|
|
|
|
$listArgs = @(
|
|
"l",
|
|
"`"$WimPath`""
|
|
)
|
|
|
|
$output = & $SevenZipPath $listArgs 2>&1
|
|
|
|
# Parse output to get file list
|
|
$files = @()
|
|
$inFileList = $false
|
|
|
|
foreach ($line in $output) {
|
|
if ($line -match "^-{5,}") {
|
|
$inFileList = -not $inFileList
|
|
continue
|
|
}
|
|
|
|
if ($inFileList -and $line -match "\.bmp$") {
|
|
# Extract filename from the line
|
|
if ($line -match "\s+(\S+\.bmp)\s*$") {
|
|
$files += $matches[1]
|
|
}
|
|
}
|
|
}
|
|
|
|
return $files
|
|
}
|
|
|
|
# Function to extract bitmaps from WIM
|
|
function Extract-BitmapsFromWim {
|
|
param(
|
|
[string]$WimPath,
|
|
[string]$OutputPath,
|
|
[string]$SevenZipPath
|
|
)
|
|
|
|
Write-Log "Extracting bitmaps from WIM..." -Color Cyan
|
|
|
|
$extractArgs = @(
|
|
"e",
|
|
"`"$WimPath`"",
|
|
"-o`"$OutputPath`"",
|
|
"*.bmp",
|
|
"-y"
|
|
)
|
|
|
|
$process = Start-Process -FilePath $SevenZipPath -ArgumentList $extractArgs -Wait -NoNewWindow -PassThru
|
|
|
|
if ($process.ExitCode -ne 0) {
|
|
throw "Failed to extract bitmaps from WIM"
|
|
}
|
|
}
|
|
|
|
# Function to get bitmap info
|
|
function Get-BitmapInfo {
|
|
param([string]$BitmapPath)
|
|
|
|
try {
|
|
Add-Type -AssemblyName System.Drawing
|
|
$image = [System.Drawing.Image]::FromFile($BitmapPath)
|
|
|
|
$info = @{
|
|
Width = $image.Width
|
|
Height = $image.Height
|
|
PixelFormat = $image.PixelFormat.ToString()
|
|
RawFormat = $image.RawFormat.ToString()
|
|
HorizontalResolution = $image.HorizontalResolution
|
|
VerticalResolution = $image.VerticalResolution
|
|
}
|
|
|
|
$image.Dispose()
|
|
return $info
|
|
} catch {
|
|
return $null
|
|
}
|
|
}
|
|
|
|
# Function to display bitmap info
|
|
function Show-BitmapInfo {
|
|
param(
|
|
[string]$BitmapPath,
|
|
[string]$Name
|
|
)
|
|
|
|
$info = Get-BitmapInfo -BitmapPath $BitmapPath
|
|
$fileSize = (Get-Item $BitmapPath).Length
|
|
|
|
if ($info) {
|
|
$expectedInfo = $LogoSizes | Where-Object { $_.Name -eq $Name }
|
|
|
|
Write-Host ""
|
|
Write-Host " File: $Name" -ForegroundColor Yellow
|
|
if ($expectedInfo) {
|
|
Write-Host " Description: $($expectedInfo.Description)" -ForegroundColor Gray
|
|
}
|
|
Write-Host " Dimensions: $($info.Width) x $($info.Height) pixels" -ForegroundColor White
|
|
Write-Host " Pixel Format: $($info.PixelFormat)" -ForegroundColor Gray
|
|
Write-Host " File Size: $([math]::Round($fileSize / 1KB, 2)) KB" -ForegroundColor Gray
|
|
Write-Host " Resolution: $($info.HorizontalResolution) x $($info.VerticalResolution) DPI" -ForegroundColor Gray
|
|
|
|
if ($expectedInfo) {
|
|
if ($info.Width -eq $expectedInfo.Width -and $info.Height -eq $expectedInfo.Height) {
|
|
Write-Host " Status: Correct size" -ForegroundColor Green
|
|
} else {
|
|
Write-Host " Status: Size mismatch! Expected $($expectedInfo.Width)x$($expectedInfo.Height)" -ForegroundColor Red
|
|
}
|
|
}
|
|
} else {
|
|
Write-Host " Error reading bitmap: $Name" -ForegroundColor Red
|
|
}
|
|
}
|
|
|
|
# Function to open image viewer
|
|
function Open-ImageViewer {
|
|
param([string]$ImagePath)
|
|
|
|
try {
|
|
Start-Process $ImagePath
|
|
} catch {
|
|
Write-Log "Could not open image viewer for: $ImagePath" -Color Yellow
|
|
}
|
|
}
|
|
|
|
# Main script execution
|
|
try {
|
|
Write-Host ""
|
|
Write-Host "================================================" -ForegroundColor Cyan
|
|
Write-Host " Windows Boot Resource Viewer v1.0 " -ForegroundColor Cyan
|
|
Write-Host "================================================" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
|
|
# Validate input file
|
|
if (-not (Test-Path $BootResDllPath)) {
|
|
throw "bootres.dll not found at: $BootResDllPath"
|
|
}
|
|
|
|
$fileInfo = Get-Item $BootResDllPath
|
|
|
|
Write-Host "FILE INFORMATION" -ForegroundColor Green
|
|
Write-Host "================" -ForegroundColor Green
|
|
Write-Host "File Path: $($fileInfo.FullName)" -ForegroundColor White
|
|
Write-Host "File Size: $([math]::Round($fileInfo.Length / 1KB, 2)) KB" -ForegroundColor White
|
|
Write-Host "Created: $($fileInfo.CreationTime)" -ForegroundColor White
|
|
Write-Host "Modified: $($fileInfo.LastWriteTime)" -ForegroundColor White
|
|
|
|
# Get file architecture
|
|
$arch = Get-FileArchitecture -FilePath $BootResDllPath
|
|
Write-Host "Architecture: $arch" -ForegroundColor White
|
|
|
|
# Get version info
|
|
if ($ShowInfo) {
|
|
$versionInfo = Get-FileVersionInfo -FilePath $BootResDllPath
|
|
if ($versionInfo) {
|
|
Write-Host ""
|
|
Write-Host "VERSION INFORMATION" -ForegroundColor Green
|
|
Write-Host "===================" -ForegroundColor Green
|
|
Write-Host "File Version: $($versionInfo.FileVersion)" -ForegroundColor White
|
|
Write-Host "Product Version: $($versionInfo.ProductVersion)" -ForegroundColor White
|
|
Write-Host "Company: $($versionInfo.CompanyName)" -ForegroundColor White
|
|
Write-Host "Description: $($versionInfo.FileDescription)" -ForegroundColor White
|
|
Write-Host "Product Name: $($versionInfo.ProductName)" -ForegroundColor White
|
|
}
|
|
|
|
# Get digital signature
|
|
$signature = Get-DigitalSignature -FilePath $BootResDllPath
|
|
Write-Host ""
|
|
Write-Host "DIGITAL SIGNATURE" -ForegroundColor Green
|
|
Write-Host "=================" -ForegroundColor Green
|
|
Write-Host "Status: $($signature.Status)" -ForegroundColor $(if ($signature.IsSigned) { "Green" } else { "Red" })
|
|
Write-Host "Signed By: $($signature.SignerSubject)" -ForegroundColor White
|
|
Write-Host "Issuer: $($signature.SignerIssuer)" -ForegroundColor White
|
|
}
|
|
|
|
# Check for 7-Zip
|
|
$7zPath = Test-7ZipAvailable
|
|
if (-not $7zPath) {
|
|
throw "7-Zip is required but not found. Please install 7-Zip from https://www.7-zip.org/"
|
|
}
|
|
Write-Log "Found 7-Zip at: $7zPath" -Color Green
|
|
|
|
# Create temporary directory
|
|
$tempDir = Join-Path $env:TEMP "BootResViewer_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
|
|
New-Item -ItemType Directory -Path $tempDir -Force | Out-Null
|
|
|
|
# Extract bitmaps directly from bootres.dll
|
|
Write-Log "Extracting bitmaps from bootres.dll..." -Color Cyan
|
|
|
|
$extractArgs = @(
|
|
"e",
|
|
"`"$BootResDllPath`"",
|
|
"-o`"$tempDir`"",
|
|
"*.bmp",
|
|
"-r",
|
|
"-y"
|
|
)
|
|
|
|
$process = Start-Process -FilePath $7zPath -ArgumentList $extractArgs -Wait -NoNewWindow -PassThru
|
|
|
|
if ($process.ExitCode -ne 0) {
|
|
throw "Failed to extract bitmaps from bootres.dll"
|
|
}
|
|
|
|
# Get extracted bitmaps
|
|
$extractedBitmaps = Get-ChildItem -Path $tempDir -Filter "*.bmp"
|
|
|
|
if ($extractedBitmaps.Count -eq 0) {
|
|
throw "No bitmaps found in bootres.dll"
|
|
}
|
|
|
|
Write-Log "Successfully extracted $($extractedBitmaps.Count) bitmap(s)" -Color Green
|
|
|
|
# Separate winlogo and qrcode bitmaps
|
|
$winlogoBitmaps = $extractedBitmaps | Where-Object { $_.Name -like "winlogo*" }
|
|
$qrcodeBitmaps = $extractedBitmaps | Where-Object { $_.Name -like "qrcode*" }
|
|
|
|
Write-Host ""
|
|
Write-Host "EXTRACTED BITMAPS" -ForegroundColor Green
|
|
Write-Host "=================" -ForegroundColor Green
|
|
|
|
if ($winlogoBitmaps.Count -gt 0) {
|
|
Write-Host "Boot Logos (winlogo*):" -ForegroundColor Cyan
|
|
$winlogoBitmaps | ForEach-Object { Write-Host " - $($_.Name)" -ForegroundColor White }
|
|
}
|
|
|
|
if ($qrcodeBitmaps.Count -gt 0) {
|
|
Write-Host "QR Codes (qrcode*):" -ForegroundColor Cyan
|
|
$qrcodeBitmaps | ForEach-Object { Write-Host " - $($_.Name)" -ForegroundColor White }
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "BITMAP DETAILS" -ForegroundColor Green
|
|
Write-Host "==============" -ForegroundColor Green
|
|
|
|
foreach ($bitmap in $extractedBitmaps) {
|
|
Show-BitmapInfo -BitmapPath $bitmap.FullName -Name $bitmap.Name
|
|
}
|
|
|
|
# Extract to output folder if specified
|
|
if ($OutputFolder) {
|
|
if (-not (Test-Path $OutputFolder)) {
|
|
New-Item -ItemType Directory -Path $OutputFolder -Force | Out-Null
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Log "Copying bitmaps to: $OutputFolder" -Color Cyan
|
|
|
|
foreach ($bitmap in $extractedBitmaps) {
|
|
$destPath = Join-Path $OutputFolder $bitmap.Name
|
|
Copy-Item -Path $bitmap.FullName -Destination $destPath -Force
|
|
Write-Host " Copied: $($bitmap.Name)" -ForegroundColor Green
|
|
}
|
|
}
|
|
|
|
# Summary
|
|
Write-Host ""
|
|
Write-Host "================================================" -ForegroundColor Cyan
|
|
Write-Host "SUMMARY" -ForegroundColor Green
|
|
Write-Host "================================================" -ForegroundColor Cyan
|
|
Write-Host "Total bitmaps found: $($extractedBitmaps.Count)" -ForegroundColor White
|
|
Write-Host " - Boot logos (winlogo*): $($winlogoBitmaps.Count)" -ForegroundColor White
|
|
Write-Host " - QR codes (qrcode*): $($qrcodeBitmaps.Count)" -ForegroundColor White
|
|
Write-Host "Temporary files location: $tempDir" -ForegroundColor White
|
|
|
|
if ($OutputFolder) {
|
|
Write-Host "Bitmaps saved to: $OutputFolder" -ForegroundColor Green
|
|
} else {
|
|
Write-Host ""
|
|
Write-Host "TIP: Use -OutputFolder parameter to save bitmaps to a specific location" -ForegroundColor Yellow
|
|
Write-Host "Example: .\view-bootres.ps1 -BootResDllPath 'C:\path\to\bootres.dll' -OutputFolder 'C:\extracted'" -ForegroundColor Yellow
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "Expected boot logo sizes:" -ForegroundColor Cyan
|
|
foreach ($logoSize in $LogoSizes) {
|
|
Write-Host " $($logoSize.Name): $($logoSize.Width)x$($logoSize.Height) - $($logoSize.Description)" -ForegroundColor Gray
|
|
}
|
|
|
|
Write-Host ""
|
|
|
|
} catch {
|
|
Write-Host ""
|
|
Write-Host "ERROR: $_" -ForegroundColor Red
|
|
Write-Host "Stack Trace: $($_.ScriptStackTrace)" -ForegroundColor Red
|
|
exit 1
|
|
} |