// verify signature on dll, return true if signature is valid, false otherwise static boolean check_dll(const char* dll_path) { // see if the file exists if (_access(dll_path, 0)) { // file doesn't exist, return failure return false; } // Prepare to check Authenticode signature on dll to insure hackers haven't modified the file GUID action_guid = WINTRUST_ACTION_GENERIC_VERIFY_V2; DWORD dwPathLen = strlen(dll_path) + 1; WINTRUST_FILE_INFO file_info; memset(&file_info, 0, sizeof(file_info)); file_info.cbStruct = sizeof(file_info); char* buffer = new char[2*dwPathLen]; file_info.pcwszFilePath = (wchar_t*)buffer; if (!MultiByteToWideChar(CP_ACP, 0, dll_path, dwPathLen, (wchar_t*)buffer, dwPathLen)) { // could not convert path to Unicode, free memory and return failure delete [] buffer; return false; } WINTRUST_DATA trust_data; memset(&trust_data, 0, sizeof(trust_data)); trust_data.cbStruct = sizeof(trust_data); trust_data.dwUIChoice = WTD_UI_NONE; trust_data.fdwRevocationChecks = WTD_REVOKE_NONE; trust_data.dwUnionChoice = WTD_CHOICE_FILE; trust_data.pFile = &file_info; HRESULT result; result = WinVerifyTrust((HWND)INVALID_HANDLE_VALUE, &action_guid, &trust_data); if (result != ERROR_SUCCESS) { // Authenticode check failed, free memory and return failure delete [] buffer; return false; } delete [] buffer; // Authenticode check succeeded, now verify the certificate used to sign the dll is ours and // not some imposter's // open dll HANDLE dll_handle = CreateFile(dll_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS, NULL); if (dll_handle == INVALID_HANDLE_VALUE) { return false; } DWORD cert_count; if (!ImageEnumerateCertificates(dll_handle, CERT_SECTION_TYPE_ANY, &cert_count, NULL, 0)) { CloseHandle(dll_handle); return false; } // there should only be one certificate associated with this dll, ours if (cert_count != 1) { CloseHandle(dll_handle); return false; } // first get the certificate header to get the proper size for certificate structure WIN_CERTIFICATE certHead; certHead.dwLength = 0; certHead.wRevision = WIN_CERT_REVISION_1_0; if (!ImageGetCertificateHeader(dll_handle, 0, &certHead)) { // problem getting certificate information, return failure CloseHandle(dll_handle); return false; } // allocate memory for certificate DWORD cert_len = certHead.dwLength; char* cert = new char[sizeof(WIN_CERTIFICATE) + cert_len]; WIN_CERTIFICATE *cert_p = (WIN_CERTIFICATE*)cert; cert_p->dwLength = cert_len; cert_p->wRevision = WIN_CERT_REVISION_1_0; if (!ImageGetCertificateData(dll_handle, 0, cert_p, &cert_len)) { // problem getting certificate, return failure CloseHandle(dll_handle); delete [] cert; return false; } // done with file handle, close it CloseHandle(dll_handle); // extract the certificate used to sign the dll. Since the signature certificate is a PKCS#7 SignedData object, // we can verify the signature of the object which will have the side-effect of creating the certificate context // of the signing certificate. DWORD decodesize = 0; PCCERT_CONTEXT pCertContext; CRYPT_VERIFY_MESSAGE_PARA vPara; memset(&vPara, 0, sizeof(vPara)); vPara.cbSize = sizeof(vPara); vPara.dwMsgAndCertEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; if (!CryptVerifyMessageSignature(&vPara, 0, cert_p->bCertificate, cert_p->dwLength, NULL, &decodesize, &pCertContext)) { delete [] cert; return false; } // If the certificate that signed the dll matches ours, we're in business! // Compare the subject name, do not compare the entire certificate or the public key as these will change each // year as the certificates are renewed. DWORD subjectSize = CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, NULL, 0); char *subjectName = new char[subjectSize]; CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, subjectName, subjectSize); if (strcmp(subjectName, "YoYoDyne Corporation")) { delete [] subjectName; delete [] cert; return false; } // clean up delete [] subjectName; delete [] cert; CertFreeCertificateContext(pCertContext); return true; }