Skip to content

FinalPolicy Bypass

Kriyos Arcane edited this page Jul 4, 2026 · 4 revisions

FinalPolicy Bypass

WinVerifyTrust does not decide trust at the first step. It walks through a short chain, then reaches one last decision gate named FinalPolicy. TrustMeBro swaps that last gate with a cleanup function that reports success, so the whole check ends in "valid."

Diagram

FinalPolicy Bypass Flow

Technical detail

The default Authenticode action uses seven stages:

  1. Initialization
  2. Message
  3. Signature
  4. Certificate
  5. CertCheck
  6. FinalPolicy
  7. Cleanup

SoftpubAuthenticode makes the real trust decision. SoftpubCleanup is the cleanup handler and returns S_OK.

The important registry value is $Function under the Authenticode action GUID:

  • Key: HKLM\SOFTWARE\Microsoft\Cryptography\Providers\Trust\FinalPolicy\{00AAC56B-CD44-11d0-8CC2-00C04FC295EE}
  • Before: $Function = SoftpubAuthenticode
  • After: $Function = SoftpubCleanup

Result:

  • system-wide effect
  • survives reboot
  • every WinVerifyTrust check that reaches this action returns success

If you pair this with a stolen signature, UAC shows the donor certificate's Subject CN in the publisher field.

Stage-by-stage test results

Testing all seven WinVerifyTrust stages with the same cleanup redirection showed one useful slot.

Stage Redirect result
Initialization failed
Message 0x800B0100, null signer
Signature failed
Certificate failed
CertCheck failed
FinalPolicy bypass succeeded
Cleanup failed

Only FinalPolicy redirected to SoftpubCleanup yields a trust bypass.

Why FinalPolicy works

On Win11 24H2, wintrust.dll places the real Authenticode decision logic in SoftpubAuthenticode at 0x18001E0A0. That path checks hash match, EKU, revocation, and chain trust. SoftpubCleanup at 0x180022670 frees state and returns S_OK. One function decides trust. The other tears down state.

Action GUID coverage

FinalPolicy redirection works across all six registered Authenticode action GUIDs, not only {00AAC56B-CD44-11d0-8CC2-00C04FC295EE}. The custom-provider feature relies on that wider coverage.

EKU findings

Lifetime Signing special case

WintrustCertificateTrust at 0x18002D850 checks EKU 1.3.6.1.4.1.311.10.3.13, Lifetime Signing, and treats it as a separate allow path. This logic sits apart from FinalPolicy.

EKU confusion results on Win11 24H2

EKU set Result
codeSigning pass
no EKU pass
anyExtendedKeyUsage pass
serverAuth fail 0x800B0110

Clone this wiki locally