Skip to content

Instantly share code, notes, and snippets.

@nafai
Forked from out0xb2/Check-Dbx.ps1
Last active May 18, 2023 16:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nafai/e014e2b9600e1f7dc93d0999df4ff720 to your computer and use it in GitHub Desktop.
Save nafai/e014e2b9600e1f7dc93d0999df4ff720 to your computer and use it in GitHub Desktop.
Parses signature data from the pk, kek, db, and dbx UEFI variables.
[CmdletBinding()]Param(
[Parameter(ParameterSetName = 'Filename')]
[string]$Filename,
[Parameter(ParameterSetName = 'Base64')]
[string]$Base64
)
if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
{
Write-Error "Insufficient permissions to run this script. Open the PowerShell console as administrator and run this script again." -ErrorAction Stop
}
if ((Get-Command Get-UefiDatabaseSignatures -ErrorAction SilentlyContinue).count -eq 0)
{
Write-Error "Please import function Get-UefiDatabaseSignatures." -ErrorAction Stop
}
# Fail early if Secure Boot isn't enabled on the local system.
Get-SecureBootPolicy -ErrorAction Stop | Out-Null
$LocalDbx = Get-SecureBootUEFI dbx | Get-UEFIDatabaseSignatures
if ($PSCmdlet.ParameterSetName -eq "Base64")
{
$DecodedBytes = [System.Convert]::FromBase64String($Base64)
$Filename = "$env:temp\dbxupdate.bin"
Set-Content -Encoding Byte -Path $Filename -Value $DecodedBytes -Force
}
Try
{
$Filename = (Resolve-Path $Filename -ErrorAction Stop).Path
Write-Verbose ("Using file: $Filename")
$DbxFileSigs = Get-UEFIDatabaseSignatures -Filename $Filename
}
Catch
{
Write-Error "Failure while parsing $Filename." -ErrorAction Stop
}
$LocalSigs = @($LocalDbx).ForEach({if ($_.SignatureType -eq "EFI_CERT_SHA256_GUID") { $_.SignatureList.SignatureData } elseif ($_.SignatureType -eq "EFI_CERT_X509_GUID") { $_.SignatureList.SignatureData.Thumbprint }}) | Sort-Object
$FileSigs = @($DbxFileSigs).ForEach({if ($_.SignatureType -eq "EFI_CERT_SHA256_GUID") { $_.SignatureList.SignatureData } elseif ($_.SignatureType -eq "EFI_CERT_X509_GUID") { $_.SignatureList.SignatureData.Thumbprint }}) | Sort-Object
$ExtraSigs = (Compare-Object $LocalSigs $FileSigs).Where({$_.SideIndicator -eq "<="}).InputObject
$MissingSigs = (Compare-Object $LocalSigs $FileSigs).Where({$_.SideIndicator -eq "=>"}).InputObject
$result = [pscustomobject]@{
"Filename"=$Filename;
"LocalSigCount"=$LocalSigs.Count;
"FileSigCount"=$FileSigs.Count;
"MissingSigCount"=$MissingSigs.Count;
"ExtraSigCount"=$ExtraSigs.Count;
}
Write-Verbose ("{0} signatures in local database, {1} signatures in database file. {2} are present in the file and not on this system, {3} are present on this system and not in the update file." -f $result.LocalSigCount,$result.FileSigCount,$result.MissingSigCount,$result.ExtraSigCount)
Return $result
function Get-UefiDatabaseSignatures {
<#
.SYNOPSIS
Parses UEFI Signature Databases into logical Powershell objects
.DESCRIPTION
Original Author: Matthew Graeber (@mattifestation)
Modified By: Jeremiah Cox (@int0x6)
Modified By: Joel Roth (@nafai)
Additional Source: https://gist.github.com/mattifestation/991a0bea355ec1dc19402cef1b0e3b6f
Additional Source: https://www.powershellgallery.com/packages/SplitDbxContent/1.0
License: BSD 3-Clause
.PARAMETER Variable
Specifies a UEFI variable, an instance of which is returned by calling the Get-SecureBootUEFI cmdlet. Only 'db' and 'dbx' are supported.
.PARAMETER BytesIn
Specifies a byte array consisting of the PK, KEK, db, or dbx UEFI vairable contents.
.EXAMPLE
$DbxBytes = [IO.File]::ReadAllBytes('.\dbx.bin')
Get-UEFIDatabaseSignatures -BytesIn $DbxBytes
.EXAMPLE
Get-UEFIDatabaseSignatures -Filename ".\DBXUpdate-20230314.x64.bin"
.EXAMPLE
Get-SecureBootUEFI -Name db | Get-UEFIDatabaseSignatures
.EXAMPLE
Get-SecureBootUEFI -Name dbx | Get-UEFIDatabaseSignatures
.EXAMPLE
Get-SecureBootUEFI -Name pk | Get-UEFIDatabaseSignatures
.EXAMPLE
Get-SecureBootUEFI -Name kek | Get-UEFIDatabaseSignatures
.INPUTS
Microsoft.SecureBoot.Commands.UEFIEnvironmentVariable
Accepts the output of Get-SecureBootUEFI over the pipeline.
.OUTPUTS
UefiSignatureDatabase
Outputs an array of custom powershell objects describing a UEFI Signature Database. "77fa9abd-0359-4d32-bd60-28f4e78f784b" refers to Microsoft as the owner.
#>
[CmdletBinding()]
param (
[Parameter(Mandatory, ValueFromPipeline, ParameterSetName = 'UEFIVariable')]
[ValidateScript({ ($_.GetType().Fullname -eq 'Microsoft.SecureBoot.Commands.UEFIEnvironmentVariable') -and ($_.Name -in "kek","pk","db","dbx") })]
$Variable,
[Parameter(Mandatory, ParameterSetName = 'ByteArray')]
[Byte[]]
[ValidateNotNullOrEmpty()]
$BytesIn,
[Parameter(Mandatory, ParameterSetName = 'File')]
[string]
[ValidateScript({ (Resolve-Path "$_").where({Test-Path $_}).Path })]
$Filename
)
$SignatureTypeMapping = @{
'C1C41626-504C-4092-ACA9-41F936934328' = 'EFI_CERT_SHA256_GUID' # Most often used for dbx
'A5C059A1-94E4-4AA7-87B5-AB155C2BF072' = 'EFI_CERT_X509_GUID' # Most often used for db
}
$Bytes = $null
if ($Filename)
{
$Bytes = Get-Content -Encoding Byte $Filename -ErrorAction Stop
}
elseif ($Variable)
{
$Bytes = $Variable.Bytes
}
else
{
$Bytes = $BytesIn
}
# Modified from Split-Dbx
if (($Bytes[40] -eq 0x30) -and ($Bytes[41] -eq 0x82 ))
{
Write-Debug "Removing signature."
# Signature is known to be ASN size plus header of 4 bytes
$sig_length = $Bytes[42] * 256 + $Bytes[43] + 4
if ($sig_length -gt ($Bytes.Length + 40)) {
Write-Error "Signature longer than file size!" -ErrorAction Stop
}
## Unsigned db store
[System.Byte[]]$Bytes = @($Bytes[($sig_length+40)..($Bytes.Length - 1)].Clone())
}
else
{
Write-Debug "Signature not found. Assuming it's already split."
}
try
{
$MemoryStream = New-Object -TypeName IO.MemoryStream -ArgumentList @(,$Bytes)
$BinaryReader = New-Object -TypeName IO.BinaryReader -ArgumentList $MemoryStream, ([Text.Encoding]::Unicode)
}
catch
{
throw $_
return
}
# What follows will be an array of EFI_SIGNATURE_LIST structs
while ($BinaryReader.PeekChar() -ne -1) {
$SignatureType = $SignatureTypeMapping[([Guid][Byte[]] $BinaryReader.ReadBytes(16)).Guid]
$SignatureListSize = $BinaryReader.ReadUInt32()
$SignatureHeaderSize = $BinaryReader.ReadUInt32()
$SignatureSize = $BinaryReader.ReadUInt32()
$SignatureHeader = $BinaryReader.ReadBytes($SignatureHeaderSize)
# 0x1C is the size of the EFI_SIGNATURE_LIST header
$SignatureCount = ($SignatureListSize - 0x1C) / $SignatureSize
$SignatureList = 1..$SignatureCount | ForEach-Object {
$SignatureDataBytes = $BinaryReader.ReadBytes($SignatureSize)
$SignatureOwner = [Guid][Byte[]] $SignatureDataBytes[0..15]
switch ($SignatureType) {
'EFI_CERT_SHA256_GUID' {
$SignatureData = ([Byte[]] $SignatureDataBytes[0x10..0x2F] | ForEach-Object { $_.ToString('X2') }) -join ''
}
'EFI_CERT_X509_GUID' {
$SignatureData = New-Object Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList @(,([Byte[]] $SignatureDataBytes[16..($SignatureDataBytes.Count - 1)]))
}
}
[PSCustomObject] @{
PSTypeName = 'EFI.SignatureData'
SignatureOwner = $SignatureOwner
SignatureData = $SignatureData
}
}
[PSCustomObject] @{
PSTypeName = 'EFI.SignatureList'
SignatureType = $SignatureType
SignatureList = $SignatureList
}
}
}
@nafai
Copy link
Author

nafai commented May 18, 2023

In case it helps anyone else, https://github.com/fwupd/dbx-firmware has been a more convenient source than uefi.org for the historical/archived files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment