Last active
April 19, 2023 00:28
-
-
Save heaths/ebbca7d956f0b42bbb33193f0837e272 to your computer and use it in GitHub Desktop.
Check Authenticode signature on Windows with Go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//go:build windows | |
package main | |
import ( | |
"flag" | |
"fmt" | |
"log" | |
"os" | |
"path/filepath" | |
"syscall" | |
"unsafe" | |
"golang.org/x/sys/windows" | |
) | |
type WTD_UI uint32 | |
type WTD_REVOKE uint32 | |
type WTD_CHOICE uint32 | |
type WTD_STATEACTION uint32 | |
type WTD_FLAGS uint32 | |
type WTD_UICONTEXT uint32 | |
const ( | |
INVALID_HANDLE_VALUE syscall.Handle = syscall.Handle(1<<(unsafe.Sizeof(uintptr(0))*8-1)<<1 - 1) | |
WTD_UI_NONE WTD_UI = 2 | |
WTD_REVOKE_NONE WTD_REVOKE = 0 | |
WTD_REVOKE_WHOLECHAIN WTD_REVOKE = 1 | |
WTD_CHOICE_FILE WTD_CHOICE = 1 | |
WTD_STATEACTION_VERIFY WTD_STATEACTION = 1 | |
WTD_STATEACTION_CLOSE WTD_STATEACTION = 2 | |
WTD_REVOCATION_CHECK_NONE WTD_FLAGS = 16 | |
WTD_REVOCATION_CHECK_CHAIN WTD_FLAGS = 64 | |
WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT WTD_FLAGS = 128 | |
WTD_CACHE_ONLY_URL_RETRIEVAL WTD_FLAGS = 4096 | |
WTD_UICONTEXT_EXECUTE WTD_UICONTEXT = 0 | |
WTD_UICONTEXT_INSTALL WTD_UICONTEXT = 1 | |
) | |
var ( | |
WINTRUST_ACTION_GENERIC_VERIFY_V2 = syscall.GUID{ | |
Data1: 0xaac56b, | |
Data2: 0xcd44, | |
Data3: 0x11d0, | |
Data4: [8]byte{0x8c, 0xc2, 0x0, 0xc0, 0x4f, 0xc2, 0x95, 0xee}, | |
} | |
modwintrust = windows.NewLazySystemDLL("wintrust.dll") | |
procWinVerifyTrust = modwintrust.NewProc("WinVerifyTrust") | |
) | |
type WinTrustData struct { | |
cbStruct uint32 | |
pPolicyCallbackData uintptr | |
pSIPClientData uintptr | |
dwUIChoice WTD_UI | |
fdwRevocationChecks WTD_REVOKE | |
dwUnionChoice WTD_CHOICE | |
pFile *WINTRUST_FILE_INFO | |
dwStateAction WTD_STATEACTION | |
hWVTStateData syscall.Handle | |
pwszURLReference *uint16 | |
dwProvFlags WTD_FLAGS | |
dwUIContext WTD_UICONTEXT | |
} | |
type WINTRUST_FILE_INFO struct { | |
cbStruct uint32 | |
pcwszFilePath *uint16 | |
hFile syscall.Handle | |
pgKnownSubject *syscall.GUID | |
} | |
func WinVerifyTrust( | |
hwnd syscall.Handle, | |
pgActionID *syscall.GUID, | |
pWVTData *WinTrustData, | |
) error { | |
r1, _, err := syscall.SyscallN( | |
procWinVerifyTrust.Addr(), | |
uintptr(hwnd), | |
uintptr(unsafe.Pointer(pgActionID)), | |
uintptr(unsafe.Pointer(pWVTData)), | |
) | |
if r1 != uintptr(windows.ERROR_SUCCESS) { | |
return err | |
} | |
return nil | |
} | |
func main() { | |
checkRevocation := flag.Bool("check-revocation", false, "Check revocation from the local cache") | |
flag.Usage = func() { | |
fmt.Fprintf(os.Stderr, "Verify the Authenticode signature of a file\n\n") | |
fmt.Fprintf(os.Stderr, "Usage of %s:\n\b", os.Args[0]) | |
fmt.Fprintf(os.Stderr, " %s [flags] path\n\n", filepath.Base(os.Args[0])) | |
fmt.Fprintf(os.Stderr, "Arguments\n") | |
fmt.Fprintf(os.Stderr, " path\n") | |
fmt.Fprintf(os.Stderr, " Path of the file to verify\n") | |
fmt.Fprintln(os.Stderr) | |
fmt.Fprintf(os.Stderr, "Flags:\n") | |
flag.PrintDefaults() | |
} | |
flag.Parse() | |
path := flag.Arg(0) | |
if path == "" { | |
log.Fatal("requires path to verify") | |
} | |
wtd, err := NewWinTrustFileData(path, *checkRevocation) | |
if err != nil { | |
log.Fatal(err) | |
} | |
defer wtd.Close() | |
err = WinVerifyTrust(INVALID_HANDLE_VALUE, &WINTRUST_ACTION_GENERIC_VERIFY_V2, wtd) | |
if err != nil { | |
log.Fatalf("failed to verify %s: %s", path, err) | |
} | |
fmt.Printf("%q is valid\n", path) | |
} | |
func NewWinTrustFileData(path string, checkRevocation bool) (*WinTrustData, error) { | |
var err error | |
fileInfo := new(WINTRUST_FILE_INFO) | |
fileInfo.cbStruct = uint32(unsafe.Sizeof(*fileInfo)) | |
fileInfo.pcwszFilePath, err = syscall.UTF16PtrFromString(path) | |
if err != nil { | |
return nil, err | |
} | |
wtd := new(WinTrustData) | |
wtd.cbStruct = uint32(unsafe.Sizeof(*wtd)) | |
wtd.dwUIChoice = WTD_UI_NONE | |
wtd.fdwRevocationChecks = WTD_REVOKE_NONE | |
wtd.dwUnionChoice = WTD_CHOICE_FILE | |
wtd.dwStateAction = WTD_STATEACTION_VERIFY | |
wtd.pFile = fileInfo | |
if checkRevocation { | |
wtd.dwProvFlags = WTD_CACHE_ONLY_URL_RETRIEVAL | |
} else { | |
wtd.dwProvFlags = WTD_REVOCATION_CHECK_NONE | |
} | |
return wtd, nil | |
} | |
func (wtd *WinTrustData) Close() { | |
wtd.dwStateAction = WTD_STATEACTION_CLOSE | |
WinVerifyTrust(INVALID_HANDLE_VALUE, &WINTRUST_ACTION_GENERIC_VERIFY_V2, wtd) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment