Home Malware Analysis Labs About

Signing PE Files with PFX

Table of Contents

Verify a Code Signing Cert exists:

Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert

Response should look like this:

PS C:\Windows\system32> Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert


   PSParentPath: Microsoft.PowerShell.Security\Certificate::CurrentUser\My

Thumbprint                                Subject
----------                                -------
8664A3E2DDE08E5D266835043F9C9C5F1B621189  CN=Iroh, OU=IT, OU=Avatar Users, DC=avatar, DC=local

If it doesnt, and this is for a lab, then the following articles are required:

Signing an Executable (Windows)

Store the output in a variable and sign the executable/script with Set-AuthenticodeSignature:

PS C:\Windows\system32> $Cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert
PS C:\Windows\system32> Set-AuthenticodeSignature C:\Users\iroh\Desktop\alita.exe -Certificate $Cert


    Directory: C:\Users\iroh\Desktop


SignerCertificate                         Status                                 Path
-----------------                         ------                                 ----
8664A3E2DDE08E5D266835043F9C9C5F1B621189  Valid                                  alita.exe

To double-check, Get-AuthenticodeSignature can be used:

PS C:\Windows\system32> Get-AuthenticodeSignature C:\Users\iroh\Desktop\alita.exe


    Directory: C:\Users\iroh\Desktop


SignerCertificate                         Status                                 Path
-----------------                         ------                                 ----
8664A3E2DDE08E5D266835043F9C9C5F1B621189  Valid                                  alita.exe

Exporting the certificate

Using the Export-PfxCertificate cmdlet, there are several options.

An additional note, if the executable is going to be signed from osslsigncode then ProtectTo by itself will not work due to no password being configured.

Password Protected

Set a password:

$password = ConvertTo-SecureString -String "Password123!" -Force -AsPlainText

Store the certificate in a variable:

$Cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert

Export to PFX:

Export-PfxCertificate -Cert $Cert -FilePath "C:\Users\iroh\Desktop\password-protected.pfx" -Password $password

Example:

PS C:\Windows\system32> $password = ConvertTo-SecureString -String "Password123!" -Force -AsPlainText
PS C:\Windows\system32> $Cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert
PS C:\Windows\system32> Export-PfxCertificate -Cert $Cert -FilePath C:\Users\iroh\Desktop\password-protected.pfx -Password $password

    Directory: C:\Users\iroh\Desktop


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       13/02/2021     14:13           4428 password-protected.pfx

User protected

It is also possible to only allow certain users to utilise the certificate. The only difference here is the Export-PfxCertificate syntax:

Export-PfxCertificate -Cert $Cert -FilePath C:\Users\iroh\Desktop\user-protected.pfx -ProtectTo "avatar\iroh", "avatar\aang"

The files

PS C:\Windows\system32> Get-ChildItem C:\Users\iroh\Desktop

    Directory: C:\Users\iroh\Desktop
    
Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       13/02/2021     14:16           4428 password-protected.pfx
-a----       13/02/2021     14:17           6009 user-protected.pfx

Signing an Executable (Linux)

osslsigncode is currently the most effective way to sign executables from Linux. Due to the Private Key being exported as a part of the PFX, a password will be required to sign the executables. If none is given, as seen in the ProtectTo example, it will fail.

Password Protected

As a reminder, a password is set with:

Export-PfxCertificate -Cert $Cert -FilePath "C:\Users\iroh\Desktop\password-protected.pfx" -Password $password

To sign an executable with this:

osslsigncode sign -pkcs12 ./password-protected.pfx -in alita.exe -out signed.exe -pass 'Password123!'

If all goes well, it will respond with:

Succeeded

ProtectTo

Note how no password is set:

Export-PfxCertificate -Cert $Cert -FilePath C:\Users\iroh\Desktop\user-protected.pfx -ProtectTo "avatar\iroh", "avatar\aang"

If osslsigncode is ran without a password:

# osslsigncode sign -pkcs12 ./user-protected.pfx -in alita.exe -out signed.exe
Failed to parse PKCS#12 file: ./user-protected.pfx (Wrong password?)
140531319478912:error:23076071:PKCS12 routines:PKCS12_parse:mac verify failure:../crypto/pkcs12/p12_kiss.c:66:

Failed

Giving it any password:

# osslsigncode sign -pkcs12 ./user-protected.pfx -in ./output/alita.exe -out signed.exe -pass 'Password123!'
Failed to parse PKCS#12 file: ./user-protected.pfx (Wrong password?)
140115482978944:error:23076071:PKCS12 routines:PKCS12_parse:mac verify failure:../crypto/pkcs12/p12_kiss.c:70:

Failed

To sign an executable, a password is required.

Password and ProtectTo

With that said, both is recommended:

Export-PfxCertificate -Cert $Cert -FilePath C:\Users\iroh\Desktop\both.pfx -ProtectTo "avatar\iroh", "avatar\aang" -Password $password

In the above a certificate is being bound to two users, and a password is being set. This can now be set with osslsigncode:

osslsigncode sign -pkcs12 ./both.pfx -in ./output/alita.exe -out signed.exe -pass 'Password123!'

This should respond with:

Succeeded