diff --git a/README.md b/README.md
index f82d27b..f5082f4 100644
--- a/README.md
+++ b/README.md
@@ -33,6 +33,30 @@ Example output:
+## Audit ESP or an attached drive for revoked EFI binaries (DBX)
+
+Right-click `Scan ESP for revoked files.cmd` and select *Run as administrator*.
+
+This script:
+- Downloads the latest Microsoft DBX JSON
+- Scans EFI binaries in the ESP
+- Matches them against revoked hashes and certificates
+
+You can also scan other drives (e.g., USB, CD-ROM):
+
+`powershell -ExecutionPolicy Bypass -Command "& 'ps\Find-EfiFilesRevokedByDbx.ps1' -Paths D:\ -MatchMode Both -MsftJsonPath C:\path\dbx_info_msft_latest.json -ScanESP:$false`
+
+Default JSON:
+https://raw.githubusercontent.com/microsoft/secureboot_objects/main/PreSignedObjects/DBX/dbx_info_msft_latest.json
+
+Example output:
+
+
+[!WARNING]
+Detection is based on hash and certificate matching only.
+Newer revocations using **SVN (version-based enforcement)** and **SBAT** are **not currently checked**. However `Check EFI file info.cmd` will display SVN/SBAT data if present, but this tool currently does not compare it against UEFI NVRAM policy. Support for SVN and SBAT comparison is welcome as a feature request.
+
+
## Re-applying the Secure Boot DBX updates
If the Secure Boot variables were accidentally reset to default in the UEFI/BIOS settings for example, it is possible to make Windows re-apply the DBX updates that Windows had previously applied. Right-click `Apply DBX update.cmd` and *Run as administrator*. Wait for awhile. The DBX updates should be applied after that.
diff --git a/Scan ESP for revoked files.cmd b/Scan ESP for revoked files.cmd
new file mode 100644
index 0000000..6b83f35
--- /dev/null
+++ b/Scan ESP for revoked files.cmd
@@ -0,0 +1,11 @@
+:: Created for cjee21/Check-UEFISecureBootVariables
+@echo off
+title Scan EFI files against Microsoft DBX JSON
+
+:: NOTE: Replace URL with a raw URL or use -MsftJsonPath to a local file.
+set MSFT_JSON_URL=https://raw.githubusercontent.com/microsoft/secureboot_objects/main/PreSignedObjects/DBX/dbx_info_msft_latest.json
+
+powershell -ExecutionPolicy Bypass -Command "& '%~dp0ps\Find-EfiFilesRevokedByDbx.ps1' -ScanESP -ScanDefaultPaths -MatchMode MsftJson -MsftJsonUrl '%MSFT_JSON_URL%'"
+
+echo.
+pause
\ No newline at end of file
diff --git a/docs/screenshot-audit.png b/docs/screenshot-audit.png
new file mode 100644
index 0000000..f4d4f42
Binary files /dev/null and b/docs/screenshot-audit.png differ
diff --git a/ps/Find-EfiFilesRevokedByDbx.ps1 b/ps/Find-EfiFilesRevokedByDbx.ps1
new file mode 100644
index 0000000..8b6dcf5
--- /dev/null
+++ b/ps/Find-EfiFilesRevokedByDbx.ps1
@@ -0,0 +1,258 @@
+# Created for cjee21/Check-UEFISecureBootVariables
+# Purpose: Walk EFI binaries and warn if they match revocations via:
+# - file hash (Authenticode hash if you wire it in later)
+# - signer certificate match (X509 DER match) against current DBX (EFI_CERT_X509_GUID)
+# Also supports checking against microsoft/secureboot_objects dbx_info_msft_latest.json.
+
+[CmdletBinding()]
+param(
+ # Root directories to scan for .efi files (optional)
+ [string[]] $Paths,
+
+ # If set, will mount ESP to S: (mountvol s: /s) and scan it (default: true)
+ [switch] $ScanESP = $true,
+
+ # Helper flag: scan common OS paths too (default: false)
+ [switch] $ScanDefaultPaths = $false,
+
+ # Which revocation source(s) to match against
+ [ValidateSet('CurrentDbx','MsftJson','Both')]
+ [string] $MatchMode = 'CurrentDbx',
+
+ # Optional: local path to dbx_info_msft_latest.json
+ [string] $MsftJsonPath,
+
+ # Optional: URL to download dbx_info_msft_latest.json
+ [string] $MsftJsonUrl
+)
+
+$ErrorActionPreference = 'Stop'
+
+Import-Module "$PSScriptRoot\Get-UEFIDatabaseSignatures.ps1" -Force
+Import-Module "$PSScriptRoot\Get-EfiSignatures.ps1" -Force
+
+function Get-FileSha256Hex {
+ param([Parameter(Mandatory)][string] $FilePath)
+ (Get-FileHash -Algorithm SHA256 -LiteralPath $FilePath).Hash.ToUpperInvariant()
+}
+
+function Get-CertDerHex {
+ param([Parameter(Mandatory)][System.Security.Cryptography.X509Certificates.X509Certificate2] $Cert)
+ ([System.BitConverter]::ToString($Cert.RawData) -replace '-', '').ToUpperInvariant()
+}
+
+function Get-DbxSetsFromCurrentDbx {
+ # Returns:
+ # - HashSet of SHA256 hex strings (EFI_CERT_SHA256_GUID)
+ # - HashSet of X509 DER hex strings (EFI_CERT_X509_GUID)
+ $dbx = Get-SecureBootUEFI -Name dbx
+ $parsed = $dbx | Get-UEFIDatabaseSignatures
+
+ $sha256Set = New-Object 'System.Collections.Generic.HashSet[string]'
+ $x509DerSet = New-Object 'System.Collections.Generic.HashSet[string]'
+
+ foreach ($list in $parsed) {
+ foreach ($entry in $list.SignatureList) {
+ if ($list.SignatureType -eq 'EFI_CERT_SHA256_GUID') {
+ [void]$sha256Set.Add(($entry.SignatureData.ToString().ToUpperInvariant()))
+ } elseif ($list.SignatureType -eq 'EFI_CERT_X509_GUID') {
+ $derHex = Get-CertDerHex -Cert $entry.SignatureData
+ [void]$x509DerSet.Add($derHex)
+ }
+ }
+ }
+
+ [PSCustomObject]@{
+ Name = 'CurrentDbx'
+ Sha256Set = $sha256Set
+ X509DerSet = $x509DerSet
+ }
+}
+
+function Get-DbxSetsFromMsftJson {
+ param(
+ [string] $Path,
+ [string] $Url
+ )
+
+ $jsonText = $null
+ if ($Path) {
+ if (-not (Test-Path -LiteralPath $Path)) {
+ throw "MsftJsonPath not found: $Path"
+ }
+ $jsonText = Get-Content -LiteralPath $Path -Raw
+ } elseif ($Url) {
+ # Download to memory
+ $jsonText = (Invoke-WebRequest -UseBasicParsing -Uri $Url).Content
+ } else {
+ throw "MatchMode requires -MsftJsonPath or -MsftJsonUrl."
+ }
+
+ $j = $jsonText | ConvertFrom-Json
+
+ # MSFT JSON structure: { "images": { "x64": [ { authenticodeHash, flatHash, ... }, ... ], "arm64": [ ... ] } }
+ $sha256Set = New-Object 'System.Collections.Generic.HashSet[string]'
+
+ foreach ($archProp in $j.images.PSObject.Properties) {
+ $archName = $archProp.Name
+ $items = $archProp.Value
+ foreach ($img in $items) {
+ if ($img.authenticodeHash -and $img.authenticodeHash.Trim()) {
+ #Focus on authenticodeHash for matches as most reliable
+ [void]$sha256Set.Add($img.authenticodeHash.Trim().ToUpperInvariant())
+ }
+ }
+ }
+
+ # MSFT JSON does not directly provide DER blobs for revoked cert entries (at least in the snippet provided),
+ # so in MsftJson mode we can only do hash-based checks unless you add a mapping of signer certs separately.
+ $x509DerSet = New-Object 'System.Collections.Generic.HashSet[string]'
+if ($j.PSObject.Properties.Name -contains 'certificates' -and $j.certificates) {
+ foreach ($cert in $j.certificates) {
+ $tp = $cert.thumbprint
+ if ($tp -and $tp.Trim()) {
+ # normalize: remove separators/spaces just in case, and normalize case
+ $norm = ($tp.Trim() -replace '[^0-9a-fA-F]', '').ToUpperInvariant()
+
+ # optional sanity check: SHA1 thumbprints are 20 bytes => 40 hex chars
+ if ($norm.Length -eq 40) {
+ [void]$x509DerSet.Add($norm)
+ }
+ }
+ }
+}
+
+ [PSCustomObject]@{
+ Name = 'MsftJson'
+ Sha256Set = $sha256Set
+ X509DerSet = $x509DerSet
+ }
+}
+
+function Get-EfiFilesUnderPaths {
+ param([Parameter(Mandatory)][string[]] $RootPaths)
+
+ $all = New-Object System.Collections.Generic.List[string]
+ foreach ($root in $RootPaths) {
+ if (-not (Test-Path -LiteralPath $root)) { continue }
+ Get-ChildItem -LiteralPath $root -Recurse -File -ErrorAction SilentlyContinue |
+ Where-Object { $_.Extension -ieq '.efi' } |
+ ForEach-Object { $all.Add($_.FullName) | Out-Null }
+ }
+ $all
+}
+
+# Build scan roots
+$scanRoots = New-Object System.Collections.Generic.List[string]
+
+$didMountEsp = $false
+if ($ScanESP) {
+ try {
+ mountvol s: /s | Out-Null
+ $didMountEsp = $true
+ $scanRoots.Add('S:\') | Out-Null
+ } catch {
+ Write-Warning "Could not mount ESP to S:. Run as Administrator? Continuing..."
+ }
+}
+
+if ($ScanDefaultPaths) {
+ # Common locations where EFI binaries may exist on the OS volume.
+ $scanRoots.Add("$env:SystemRoot\Boot\EFI") | Out-Null
+ $scanRoots.Add("$env:SystemDrive\EFI") | Out-Null
+ $scanRoots.Add("$env:SystemDrive\Boot") | Out-Null
+}
+
+if ($Paths) {
+ foreach ($p in $Paths) { $scanRoots.Add($p) | Out-Null }
+}
+
+if ($scanRoots.Count -eq 0) {
+ throw "No scan roots specified and ESP mount failed. Provide -Paths or run elevated."
+}
+
+# Load revocation sets
+$revocationSets = New-Object System.Collections.Generic.List[object]
+
+if ($MatchMode -eq 'CurrentDbx' -or $MatchMode -eq 'Both') {
+ Write-Host "Loading current DBX..." -ForegroundColor Cyan
+ $revocationSets.Add((Get-DbxSetsFromCurrentDbx)) | Out-Null
+}
+
+if ($MatchMode -eq 'MsftJson' -or $MatchMode -eq 'Both') {
+ Write-Host "Loading Microsoft DBX JSON..." -ForegroundColor Cyan
+ $revocationSets.Add((Get-DbxSetsFromMsftJson -Path $MsftJsonPath -Url $MsftJsonUrl)) | Out-Null
+}
+
+foreach ($s in $revocationSets) {
+ Write-Host ("Loaded {0}: SHA256-like={1}, X509={2}" -f $s.Name, $s.Sha256Set.Count, $s.X509DerSet.Count)
+}
+
+Write-Host "Scanning for EFI binaries..." -ForegroundColor Cyan
+$efiFiles = Get-EfiFilesUnderPaths -RootPaths $scanRoots.ToArray()
+Write-Host ("Found {0} EFI file(s)." -f $efiFiles.Count)
+
+$warnCount = 0
+$idx = 0
+
+foreach ($file in $efiFiles) {
+ $idx++
+ Write-Progress -Activity "Checking EFI files" -Status $file -PercentComplete (($idx / [Math]::Max(1, $efiFiles.Count)) * 100)
+
+ $fileSha = $null
+
+ # Signer cert DER hexes (may be empty)
+ $signerThumbprints = @()
+ try {
+ $sigs = Get-EfiSignatures -FilePath $file
+ $fileSha = $sigs.Authentihash
+ foreach ($sig in $sigs.Signatures) {
+ foreach ($c in $sig.Certificates) {
+ if ($c -and $c.Thumbprint) {
+ $signerThumbprints += $c.Thumbprint.ToUpperInvariant()
+ }
+ }
+ }
+ } catch {}
+
+ $matches = @()
+
+ foreach ($set in $revocationSets) {
+ # Hash match
+ if ($fileSha -and $set.Sha256Set.Contains($fileSha)) {
+ $matches += [PSCustomObject]@{ Source=$set.Name; Type='Hash'; Detail='SHA256(Authenticode) matches revocation list' }
+ }
+
+ # Cert match (only meaningful for CurrentDbx unless you add cert data to MsftJson mode)
+ if ($signerThumbprints.Count -gt 0 -$set.X509DerSet.Count -gt 0) {
+ foreach ($derHex in $signerThumbprints) {
+ if ($set.X509DerSet.Contains($derHex)) {
+ $matches += [PSCustomObject]@{ Source=$set.Name; Type='SignerCert'; Detail='Signer certificate DER matches DBX X509 revocation' }
+ break
+ }
+ }
+ }
+ }
+
+ if ($matches.Count -gt 0) {
+ $warnCount++
+ Write-Host ""
+ Write-Host "WARNING: EFI file matches revocation list(s)" -ForegroundColor Yellow
+ Write-Host (" Path: {0}" -f $file)
+ if ($fileSha) { Write-Host (" SHA256 (Authenticode): {0}" -f $fileSha) }
+ if ($signerThumbprints.Count -gt 0) {
+ Write-Host (" Signer thumbprint(s): {0}" -f ($signerThumbprints -join ', '))
+ }
+
+ foreach ($m in $matches) {
+ Write-Host (" Match: [{0}] {1} - {2}" -f $m.Source, $m.Type, $m.Detail) -ForegroundColor Yellow
+ }
+ }
+}
+
+Write-Host ""
+Write-Host ("Scan complete. Warnings: {0}" -f $warnCount) -ForegroundColor Cyan
+
+if ($didMountEsp) {
+ try { mountvol s: /d | Out-Null } catch {}
+}
\ No newline at end of file