796 lines
29 KiB
C++
796 lines
29 KiB
C++
|
//-----------------------------------------------------------------------------
|
||
|
// America Online for Windows
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Copyright (c) 1987-2001 America Online, Inc. All rights reserved. This
|
||
|
// software contains valuable confidential and proprietary information of
|
||
|
// America Online and is subject to applicable licensing agreements.
|
||
|
// Unauthorized reproduction, transmission, or distribution of this file and
|
||
|
// its contents is a violation of applicable laws.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// $Workfile: AOLInstall.cpp $ $Author: RobrtLarson $
|
||
|
// $Date: 05/02/01 $
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
#include "precomp.h"
|
||
|
|
||
|
#include <Softpub.h>
|
||
|
#include <WinCrypt.h>
|
||
|
#include <WinTrust.h>
|
||
|
#include <ImageHlp.h>
|
||
|
|
||
|
#include "AOLFindBundledInstaller_AOLCode.h"
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
#define new DEBUG_NEW
|
||
|
#undef THIS_FILE
|
||
|
static char THIS_FILE[] = __FILE__;
|
||
|
#endif
|
||
|
|
||
|
#define SWAPWORDS(x) (((x) << 16) | ((x) >> 16))
|
||
|
|
||
|
// define encoding method
|
||
|
#define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)
|
||
|
|
||
|
#define INSTALLER 0x0001
|
||
|
#define CLIENT 0x0002
|
||
|
#define COUNTRY_PICKER 0x0004
|
||
|
#define SERVICE_AOL 0x0010
|
||
|
#define SERVICE_CS 0x0020
|
||
|
|
||
|
// Local function prototypes
|
||
|
BOOL GetExeType(LPSTR lpszExePath, WORD &wExeType);
|
||
|
BOOL ExtractCertificateInfo(LPSTR lpszFileName, HCERTSTORE *hCertStore);
|
||
|
PCCERT_CONTEXT WINAPI CryptGetSignerCertificateCallback(void *pvGetArg,
|
||
|
DWORD dwCertEncodingType, PCERT_INFO pSignerId, HCERTSTORE hCertStore);
|
||
|
BOOL CheckCertificateName(HCERTSTORE hCertStore);
|
||
|
LPSTR GetCommonName(CERT_NAME_BLOB pCertNameBlob);
|
||
|
BOOL VerifyFileInfo(WORD &ExeType, LPSTR lpszInstaller, PBOOL pbOldClient);
|
||
|
BOOL VerifyCertificate(LPSTR lpszInstaller);
|
||
|
|
||
|
_pfn_CertCloseStore g_pfn_CertCloseStore = NULL;
|
||
|
_pfn_CryptVerifyMessageSignature g_pfn_CryptVerifyMessageSignature = NULL;
|
||
|
_pfn_ImageGetCertificateData g_pfn_ImageGetCertificateData = NULL;
|
||
|
_pfn_ImageGetCertificateHeader g_pfn_ImageGetCertificateHeader = NULL;
|
||
|
_pfn_CertGetSubjectCertificateFromStore g_pfn_CertGetSubjectCertificateFromStore = NULL;
|
||
|
_pfn_CertDuplicateStore g_pfn_CertDuplicateStore = NULL;
|
||
|
_pfn_CertEnumCertificatesInStore g_pfn_CertEnumCertificatesInStore = NULL;
|
||
|
_pfn_CertRDNValueToStrA g_pfn_CertRDNValueToStrA = NULL;
|
||
|
_pfn_CertFindRDNAttr g_pfn_CertFindRDNAttr = NULL;
|
||
|
_pfn_CryptDecodeObject g_pfn_CryptDecodeObject = NULL;
|
||
|
_pfn_VerQueryValueA g_pfn_VerQueryValueA = NULL;
|
||
|
_pfn_GetFileVersionInfoA g_pfn_GetFileVersionInfoA = NULL;
|
||
|
_pfn_GetFileVersionInfoSizeA g_pfn_GetFileVersionInfoSizeA = NULL;
|
||
|
_pfn_WinVerifyTrust g_pfn_WinVerifyTrust = NULL;
|
||
|
|
||
|
HMODULE g_hCRYPT32 = NULL;
|
||
|
HMODULE g_hWINTRUST = NULL;
|
||
|
HMODULE g_hVERSION = NULL;
|
||
|
HMODULE g_hIMAGEHLP = NULL;
|
||
|
|
||
|
void UnloadDependencies()
|
||
|
{
|
||
|
g_pfn_CertCloseStore = NULL;
|
||
|
g_pfn_CryptVerifyMessageSignature = NULL;
|
||
|
g_pfn_ImageGetCertificateData = NULL;
|
||
|
g_pfn_ImageGetCertificateHeader = NULL;
|
||
|
g_pfn_CertGetSubjectCertificateFromStore = NULL;
|
||
|
g_pfn_CertDuplicateStore = NULL;
|
||
|
g_pfn_CertEnumCertificatesInStore = NULL;
|
||
|
g_pfn_CertRDNValueToStrA = NULL;
|
||
|
g_pfn_CertFindRDNAttr = NULL;
|
||
|
g_pfn_CryptDecodeObject = NULL;
|
||
|
g_pfn_VerQueryValueA = NULL;
|
||
|
g_pfn_GetFileVersionInfoA = NULL;
|
||
|
g_pfn_GetFileVersionInfoSizeA = NULL;
|
||
|
g_pfn_WinVerifyTrust = NULL;
|
||
|
|
||
|
if (g_hCRYPT32) {
|
||
|
FreeLibrary(g_hCRYPT32);
|
||
|
g_hCRYPT32 = NULL;
|
||
|
}
|
||
|
|
||
|
if (g_hWINTRUST) {
|
||
|
FreeLibrary(g_hWINTRUST);
|
||
|
g_hWINTRUST = NULL;
|
||
|
}
|
||
|
|
||
|
if (g_hVERSION) {
|
||
|
FreeLibrary(g_hVERSION);
|
||
|
g_hVERSION = NULL;
|
||
|
}
|
||
|
|
||
|
if (g_hIMAGEHLP) {
|
||
|
FreeLibrary(g_hIMAGEHLP);
|
||
|
g_hIMAGEHLP = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL LoadDependencies()
|
||
|
{
|
||
|
BOOL bSuccess = FALSE;
|
||
|
|
||
|
if (!(g_hCRYPT32 = LoadLibraryA("CRYPT32.DLL"))) {
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (!(g_hWINTRUST = LoadLibraryA("WINTRUST.DLL"))) {
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (!(g_hVERSION = LoadLibraryA("VERSION.DLL"))) {
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (!(g_hIMAGEHLP = LoadLibraryA("IMAGEHLP.DLL"))) {
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (!(g_pfn_CertCloseStore = (_pfn_CertCloseStore) GetProcAddress(g_hCRYPT32, "CertCloseStore"))) { goto eh; }
|
||
|
if (!(g_pfn_CryptVerifyMessageSignature = (_pfn_CryptVerifyMessageSignature) GetProcAddress(g_hCRYPT32, "CryptVerifyMessageSignature"))) { goto eh; }
|
||
|
if (!(g_pfn_ImageGetCertificateData = (_pfn_ImageGetCertificateData) GetProcAddress(g_hIMAGEHLP, "ImageGetCertificateData"))) { goto eh; }
|
||
|
if (!(g_pfn_ImageGetCertificateHeader = (_pfn_ImageGetCertificateHeader) GetProcAddress(g_hIMAGEHLP, "ImageGetCertificateHeader"))) { goto eh; }
|
||
|
if (!(g_pfn_CertGetSubjectCertificateFromStore = (_pfn_CertGetSubjectCertificateFromStore) GetProcAddress(g_hCRYPT32, "CertGetSubjectCertificateFromStore"))) { goto eh; }
|
||
|
if (!(g_pfn_CertDuplicateStore = (_pfn_CertDuplicateStore) GetProcAddress(g_hCRYPT32, "CertDuplicateStore"))) { goto eh; }
|
||
|
if (!(g_pfn_CertEnumCertificatesInStore = (_pfn_CertEnumCertificatesInStore) GetProcAddress(g_hCRYPT32, "CertEnumCertificatesInStore"))) { goto eh; }
|
||
|
if (!(g_pfn_CertRDNValueToStrA = (_pfn_CertRDNValueToStrA) GetProcAddress(g_hCRYPT32, "CertRDNValueToStrA"))) { goto eh; }
|
||
|
if (!(g_pfn_CertFindRDNAttr = (_pfn_CertFindRDNAttr) GetProcAddress(g_hCRYPT32, "CertFindRDNAttr"))) { goto eh; }
|
||
|
if (!(g_pfn_CryptDecodeObject = (_pfn_CryptDecodeObject) GetProcAddress(g_hCRYPT32, "CryptDecodeObject"))) { goto eh; }
|
||
|
if (!(g_pfn_VerQueryValueA = (_pfn_VerQueryValueA) GetProcAddress(g_hVERSION, "VerQueryValueA"))) { goto eh; }
|
||
|
if (!(g_pfn_GetFileVersionInfoA = (_pfn_GetFileVersionInfoA) GetProcAddress(g_hVERSION, "GetFileVersionInfoA"))) { goto eh; }
|
||
|
if (!(g_pfn_GetFileVersionInfoSizeA = (_pfn_GetFileVersionInfoSizeA) GetProcAddress(g_hVERSION, "GetFileVersionInfoSizeA"))) { goto eh; }
|
||
|
if (!(g_pfn_WinVerifyTrust = (_pfn_WinVerifyTrust) GetProcAddress(g_hWINTRUST, "WinVerifyTrust"))) { goto eh; }
|
||
|
|
||
|
bSuccess = TRUE;
|
||
|
|
||
|
eh:
|
||
|
if (!bSuccess) {
|
||
|
UnloadDependencies();
|
||
|
}
|
||
|
|
||
|
return bSuccess;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// LocateInstaller
|
||
|
// This functions searches for a valid AOL or CompuServe install program
|
||
|
// based on the default value found in a registry key. This install program
|
||
|
// is then validated by checking the Certificates and verifying that the
|
||
|
// program file has not been modified since being signed by America Online.
|
||
|
//
|
||
|
// AOL Registry Key:
|
||
|
// HKLM\Software\America Online\Installers
|
||
|
//
|
||
|
// CompuServe Registry Key:
|
||
|
// HKLM\Software\CompuServe\Installers
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Function parameters:
|
||
|
// LPSTR lpszInstaller Returned installer command line,
|
||
|
// NULL if no valid installer located
|
||
|
// Note: allowance should be made in the
|
||
|
// length of this string for an optional
|
||
|
// parameter on the command line of MAX_PATH
|
||
|
// length.
|
||
|
// UINT uiPathSize Length of lpszInstaller parameter
|
||
|
// BOOL *pbMessage TRUE - display App Compat message
|
||
|
// FALSE - do not display App Compat message
|
||
|
//-----------------------------------------------------------------------------
|
||
|
BOOL LocateInstaller_Internal(LPSTR lpszInstaller, UINT uiPathSize, BOOL *pbMessage)
|
||
|
{
|
||
|
BOOL bResult = FALSE,
|
||
|
bCheckCert = TRUE,
|
||
|
bOldClient = FALSE;
|
||
|
HKEY hKey;
|
||
|
LONG lRet;
|
||
|
CHAR szModuleName[MAX_PATH];
|
||
|
WORD wExeType = 0;
|
||
|
|
||
|
// Default to no App Compat message
|
||
|
*pbMessage = FALSE;
|
||
|
|
||
|
// Get the name of the file that is executing
|
||
|
DWORD dwLen = GetModuleFileNameA(NULL, szModuleName, sizeof(szModuleName));
|
||
|
if (0 == dwLen)
|
||
|
{ return FALSE; }
|
||
|
|
||
|
// Determine the type of exe this is
|
||
|
bResult = GetExeType(szModuleName, wExeType);
|
||
|
if (bResult)
|
||
|
{
|
||
|
// Check if this is the uninstaller calling the client
|
||
|
if ((CLIENT & wExeType) && (NULL != strstr(_strlwr(GetCommandLineA()), "regall")))
|
||
|
{ return FALSE; }
|
||
|
|
||
|
// If the program we are running is valid, then let it run
|
||
|
if (VerifyFileInfo(wExeType, szModuleName, &bOldClient))
|
||
|
{ return FALSE; }
|
||
|
|
||
|
// If this is an client <= 4.0 then display message if not bundled installer found
|
||
|
if (bOldClient)
|
||
|
{ *pbMessage = TRUE; }
|
||
|
|
||
|
// Open registry key
|
||
|
if (SERVICE_AOL & wExeType)
|
||
|
{
|
||
|
lRet = RegOpenKeyA(HKEY_LOCAL_MACHINE,
|
||
|
"Software\\America Online\\Installers", &hKey);
|
||
|
}
|
||
|
else if (SERVICE_CS & wExeType)
|
||
|
{
|
||
|
lRet = RegOpenKeyA(HKEY_LOCAL_MACHINE,
|
||
|
"Software\\CompuServe\\Installers", &hKey);
|
||
|
}
|
||
|
else
|
||
|
{ return FALSE; } // Don't know what this is
|
||
|
|
||
|
if (ERROR_SUCCESS != lRet)
|
||
|
{ return FALSE; } // No bundled version of AOL/CS located in registry
|
||
|
|
||
|
// Get size of registry key data
|
||
|
ULONG cbSize;
|
||
|
DWORD dwType;
|
||
|
lRet = RegQueryValueExA(hKey, NULL, NULL, &dwType, NULL, &cbSize);
|
||
|
if ((ERROR_SUCCESS != lRet) ||
|
||
|
(cbSize > uiPathSize) ||
|
||
|
(REG_SZ != dwType))
|
||
|
{
|
||
|
RegCloseKey(hKey);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// See if we need to check the certificate for the installer
|
||
|
lRet = RegQueryValueExA(hKey, "CC", NULL, &dwType, NULL, &cbSize);
|
||
|
if ((ERROR_SUCCESS == lRet) && (cbSize > 0))
|
||
|
{ bCheckCert = FALSE; }
|
||
|
|
||
|
lpszInstaller[0] = '\"';
|
||
|
// Get registry key data
|
||
|
cbSize = uiPathSize - 1;
|
||
|
lRet = RegQueryValueExA(hKey, NULL, NULL, NULL, (UCHAR *)&lpszInstaller[1], &cbSize);
|
||
|
|
||
|
RegCloseKey(hKey);
|
||
|
if (ERROR_SUCCESS == lRet)
|
||
|
{
|
||
|
// Check for correct installer version
|
||
|
bResult = VerifyFileInfo(wExeType, &lpszInstaller[1], NULL);
|
||
|
if (bResult && bCheckCert)
|
||
|
{
|
||
|
// Get certificate store
|
||
|
HCERTSTORE hCertStore = NULL;
|
||
|
bResult = ExtractCertificateInfo(&lpszInstaller[1], &hCertStore);
|
||
|
if (bResult)
|
||
|
{
|
||
|
// Check certificates for AOL/CS signature
|
||
|
bResult = CheckCertificateName(hCertStore);
|
||
|
if (bResult)
|
||
|
{
|
||
|
// Check that file has not been modified
|
||
|
bResult = VerifyCertificate(&lpszInstaller[1]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Close the certificate store
|
||
|
if (NULL != hCertStore)
|
||
|
{ (*g_pfn_CertCloseStore)(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG); }
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (bResult)
|
||
|
{
|
||
|
StringCchCatA(lpszInstaller, uiPathSize, "\"");
|
||
|
// Check if Message should be displayed to user
|
||
|
if (CLIENT & wExeType)
|
||
|
{ *pbMessage = TRUE; }
|
||
|
else
|
||
|
{
|
||
|
// Add command line parameter
|
||
|
if (COUNTRY_PICKER & wExeType)
|
||
|
{
|
||
|
StringCchPrintfA(lpszInstaller, uiPathSize, "%s -p \"%s\"", lpszInstaller, szModuleName);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{ lpszInstaller[0] = '\0'; }
|
||
|
|
||
|
return bResult;
|
||
|
}
|
||
|
|
||
|
BOOL LocateInstaller(LPSTR lpszInstaller, UINT uiPathSize, BOOL *pbMessage)
|
||
|
{
|
||
|
BOOL bSuccess = FALSE;
|
||
|
if (!LoadDependencies()) {
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (!LocateInstaller_Internal(lpszInstaller, uiPathSize, pbMessage)) {
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
bSuccess = TRUE;
|
||
|
eh:
|
||
|
UnloadDependencies();
|
||
|
|
||
|
return bSuccess;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// GetExeType
|
||
|
// This functions determines whether the executible is an AOL/CS client or
|
||
|
// and AOL/CS installer.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Function parameters:
|
||
|
// LPSTR lpszExePath Fully qualified path to executible
|
||
|
// WORD &wExeType Returned executible type
|
||
|
// AOL or CS
|
||
|
// Client or Installer
|
||
|
//-----------------------------------------------------------------------------
|
||
|
BOOL GetExeType(LPSTR lpszExePath, WORD &wExeType)
|
||
|
{
|
||
|
// Set string to lower case for comparisons
|
||
|
_strlwr(lpszExePath);
|
||
|
|
||
|
BOOL bSuccess = FALSE;
|
||
|
LPSTR pszTemp = strrchr(lpszExePath, '\\');
|
||
|
if (NULL == pszTemp)
|
||
|
{ return FALSE; }
|
||
|
|
||
|
pszTemp++; // Get to beginning of exe name
|
||
|
|
||
|
// Determine if this is an AOL/CS client
|
||
|
if (0 == _stricmp(pszTemp, "waol.exe"))
|
||
|
{
|
||
|
wExeType = SERVICE_AOL | CLIENT;
|
||
|
return TRUE;
|
||
|
}
|
||
|
else if ((0 == _stricmp(pszTemp, "wcs2000.exe")) ||
|
||
|
(0 == _stricmp(pszTemp, "cs3.exe")))
|
||
|
{
|
||
|
wExeType = SERVICE_CS | CLIENT;
|
||
|
return TRUE;
|
||
|
}
|
||
|
else if ((NULL != strstr(pszTemp, "cs2000")) ||
|
||
|
(NULL != strstr(pszTemp, "setupcs2k")) ||
|
||
|
(NULL != strstr(pszTemp, "setupcs2000")) ||
|
||
|
(0 == _stricmp(pszTemp, "d41000b.exe")) ||
|
||
|
(0 == _stricmp(pszTemp, "d41510b.exe")) ||
|
||
|
(0 == _stricmp(pszTemp, "d41540b.exe")))
|
||
|
{
|
||
|
// These are CS installers w/ "America Online, Inc." in version info.
|
||
|
wExeType = SERVICE_CS | INSTALLER;
|
||
|
return TRUE;
|
||
|
}
|
||
|
else if (0 == _stricmp(pszTemp, "wgw.exe"))
|
||
|
{ return FALSE; } // There is no bundled installer for Gateway
|
||
|
else if (0 == _stricmp(pszTemp, "wwm.exe"))
|
||
|
{ return FALSE; } // There is no bundled installer for Wal-Mart
|
||
|
|
||
|
// Determine AOL/CS installer
|
||
|
|
||
|
// Get size of version info in file
|
||
|
DWORD dwHandle = 0;
|
||
|
DWORD dwVerInfoSize = (*g_pfn_GetFileVersionInfoSizeA)(lpszExePath, &dwHandle);
|
||
|
|
||
|
// Allocate memory for version info
|
||
|
BYTE *lpVerInfo = NULL;
|
||
|
__try
|
||
|
{
|
||
|
lpVerInfo = (BYTE *)HeapAlloc(GetProcessHeap(), 0, dwVerInfoSize);
|
||
|
if (NULL == lpVerInfo)
|
||
|
{ __leave; }
|
||
|
|
||
|
// Get version info from file
|
||
|
BOOL bResult = (*g_pfn_GetFileVersionInfoA)(lpszExePath, NULL, dwVerInfoSize, lpVerInfo);
|
||
|
if (!bResult)
|
||
|
{ __leave; }
|
||
|
|
||
|
// Get Language code page
|
||
|
DWORD *pdwTrans;
|
||
|
UINT uiBytes;
|
||
|
DWORD dwLangCodepage = 0;
|
||
|
|
||
|
bResult = (*g_pfn_VerQueryValueA)(lpVerInfo, "\\VarFileInfo\\Translation", (VOID **)&pdwTrans, &uiBytes);
|
||
|
if (bResult)
|
||
|
{ dwLangCodepage = SWAPWORDS(*pdwTrans); } // Translate language code page to something we can use
|
||
|
else
|
||
|
{ dwLangCodepage = 0x040904e4; } // Try English multilanguage code page
|
||
|
|
||
|
// Obtain the "CompanyName" from the version info
|
||
|
CHAR szQuery[MAX_PATH];
|
||
|
PCHAR pszVerInfo;
|
||
|
StringCchPrintfA(szQuery, MAX_PATH,"\\StringFileInfo\\%08X\\CompanyName", dwLangCodepage);
|
||
|
bResult = (*g_pfn_VerQueryValueA)(lpVerInfo, szQuery, (VOID **)&pszVerInfo, &uiBytes);
|
||
|
if (!bResult)
|
||
|
{ __leave; }
|
||
|
|
||
|
// Check "CompanyName"
|
||
|
if ((NULL != strstr(pszVerInfo, "America Online")) ||
|
||
|
(NULL != strstr(pszVerInfo, "AOL")))
|
||
|
{
|
||
|
wExeType = SERVICE_AOL | INSTALLER;
|
||
|
bSuccess = TRUE;
|
||
|
__leave;
|
||
|
}
|
||
|
if (0 == strcmp("CompuServe Interactive Services, Inc.", pszVerInfo))
|
||
|
{
|
||
|
wExeType = SERVICE_CS | INSTALLER;
|
||
|
bSuccess = TRUE;
|
||
|
__leave;
|
||
|
}
|
||
|
}
|
||
|
__finally
|
||
|
{
|
||
|
if (NULL != lpVerInfo)
|
||
|
{ HeapFree(GetProcessHeap(), 0, lpVerInfo); }
|
||
|
}
|
||
|
|
||
|
return bSuccess;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// ExtractCertificateInfo
|
||
|
// This functions obtains and verifies the certificate store for the
|
||
|
// installer.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Function parameters:
|
||
|
// LPSTR lpszFileName Fully qualified path to installer
|
||
|
// HCERTSTORE *hCertStore Handle to the certificate store
|
||
|
//-----------------------------------------------------------------------------
|
||
|
BOOL ExtractCertificateInfo(LPSTR lpszFileName, HCERTSTORE *hCertStore)
|
||
|
{
|
||
|
WIN_CERTIFICATE CertificateHeader;
|
||
|
LPWIN_CERTIFICATE pbCertificate = NULL;
|
||
|
BOOL bResult = FALSE;
|
||
|
HANDLE hFile = NULL;
|
||
|
DWORD dwSize;
|
||
|
CRYPT_VERIFY_MESSAGE_PARA CryptVerifyMessagePara;
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
// Open file
|
||
|
hFile = CreateFileA(lpszFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING,
|
||
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
||
|
if (hFile == INVALID_HANDLE_VALUE)
|
||
|
{ __leave; }
|
||
|
|
||
|
// Get Certificate Header
|
||
|
bResult = (*g_pfn_ImageGetCertificateHeader)(hFile, 0, &CertificateHeader);
|
||
|
if (!bResult)
|
||
|
{ __leave; }
|
||
|
|
||
|
// Allocate Memory for Certificate Blob
|
||
|
pbCertificate = (LPWIN_CERTIFICATE)HeapAlloc(GetProcessHeap(), 0,
|
||
|
CertificateHeader.dwLength);
|
||
|
if (NULL == pbCertificate)
|
||
|
{
|
||
|
bResult = FALSE;
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
// Get Certificate Blob
|
||
|
dwSize = CertificateHeader.dwLength;
|
||
|
bResult = (*g_pfn_ImageGetCertificateData)(hFile, 0, pbCertificate, &dwSize);
|
||
|
if (!bResult)
|
||
|
{ __leave; }
|
||
|
|
||
|
// Zero out CRYPT_VERIFY_MESSAGE_PARA structure
|
||
|
ZeroMemory(&CryptVerifyMessagePara, sizeof(CryptVerifyMessagePara));
|
||
|
|
||
|
CryptVerifyMessagePara.cbSize = sizeof(CryptVerifyMessagePara);
|
||
|
CryptVerifyMessagePara.dwMsgAndCertEncodingType = ENCODING;
|
||
|
CryptVerifyMessagePara.pfnGetSignerCertificate = CryptGetSignerCertificateCallback;
|
||
|
|
||
|
// Pass Address of certificate store to callback
|
||
|
CryptVerifyMessagePara.pvGetArg = (LPVOID)hCertStore;
|
||
|
|
||
|
// Verify the message and call callback
|
||
|
bResult = (*g_pfn_CryptVerifyMessageSignature)(&CryptVerifyMessagePara, 0,
|
||
|
pbCertificate->bCertificate, dwSize, NULL, NULL, NULL);
|
||
|
}
|
||
|
__finally
|
||
|
{
|
||
|
if (NULL != pbCertificate)
|
||
|
{ HeapFree(GetProcessHeap(), 0, pbCertificate); }
|
||
|
|
||
|
if (NULL != hFile)
|
||
|
{ CloseHandle(hFile); }
|
||
|
}
|
||
|
|
||
|
return bResult;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// CryptGetSignerCertificateCallback
|
||
|
// This functions is the callback function for CryptVerifyMessageSignature.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Function parameters:
|
||
|
// See MicroSoft documentation for details.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
PCCERT_CONTEXT WINAPI CryptGetSignerCertificateCallback(void *pvGetArg,
|
||
|
DWORD dwCertEncodingType, PCERT_INFO pSignerId, HCERTSTORE hCertStore)
|
||
|
{
|
||
|
if (NULL == hCertStore)
|
||
|
{ return FALSE; }
|
||
|
|
||
|
*((HCERTSTORE *)pvGetArg) = (*g_pfn_CertDuplicateStore)(hCertStore);
|
||
|
|
||
|
return (*g_pfn_CertGetSubjectCertificateFromStore)(hCertStore, dwCertEncodingType,
|
||
|
pSignerId);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// CheckCertificateName
|
||
|
// This functions checks the certificate name to verify that it is signed by
|
||
|
// America Online.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Function parameters:
|
||
|
// HCERTSTORE hCertStore Handle to the certificate store
|
||
|
//-----------------------------------------------------------------------------
|
||
|
BOOL CheckCertificateName(HCERTSTORE hCertStore)
|
||
|
{
|
||
|
BOOL bReturn = FALSE;
|
||
|
PCCERT_CONTEXT pCertContext = NULL;
|
||
|
PCCERT_CONTEXT pPrevContext = NULL;
|
||
|
LPSTR szSubject = NULL;
|
||
|
|
||
|
if (NULL != hCertStore)
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
pCertContext = (*g_pfn_CertEnumCertificatesInStore)(hCertStore, pPrevContext);
|
||
|
|
||
|
if (NULL != pCertContext)
|
||
|
{
|
||
|
// Get Subject common name, if not then get organization name
|
||
|
szSubject = GetCommonName(pCertContext->pCertInfo->Subject);
|
||
|
if (NULL != szSubject)
|
||
|
{
|
||
|
// Check name of certificate signer
|
||
|
if (0 == strcmp(szSubject, "America Online, Inc."))
|
||
|
{ bReturn = TRUE; }
|
||
|
|
||
|
HeapFree(GetProcessHeap(), 0, szSubject);
|
||
|
}
|
||
|
|
||
|
pPrevContext = pCertContext;
|
||
|
}
|
||
|
} while (pCertContext);
|
||
|
}
|
||
|
|
||
|
return bReturn;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// GetCommonName
|
||
|
// This functions obtains the common name from the certificate store
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Function parameters:
|
||
|
// CERT_NAME_BLOB pCertNameBlob Pointer to the blob that contains the name
|
||
|
//-----------------------------------------------------------------------------
|
||
|
LPSTR GetCommonName(CERT_NAME_BLOB pCertNameBlob)
|
||
|
{
|
||
|
BOOL bReturn = FALSE;
|
||
|
BOOL bResult;
|
||
|
PCERT_NAME_INFO pCertName = NULL;
|
||
|
PCERT_RDN_ATTR pCertAttr;
|
||
|
LPSTR szName = NULL;
|
||
|
DWORD dwSize;
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
// Find out size of decrypted blob
|
||
|
(*g_pfn_CryptDecodeObject)(ENCODING, X509_NAME, pCertNameBlob.pbData,
|
||
|
pCertNameBlob.cbData, 0, NULL, &dwSize);
|
||
|
|
||
|
// Allocate memory for decrypted blob
|
||
|
pCertName = (PCERT_NAME_INFO)HeapAlloc(GetProcessHeap(), 0, dwSize);
|
||
|
if (NULL == pCertName)
|
||
|
{ __leave; }
|
||
|
|
||
|
// Decode the certificate blob
|
||
|
bResult = (*g_pfn_CryptDecodeObject)(ENCODING, X509_NAME, pCertNameBlob.pbData,
|
||
|
pCertNameBlob.cbData, 0, pCertName, &dwSize);
|
||
|
if (!bResult)
|
||
|
{ __leave; }
|
||
|
|
||
|
// Get common name
|
||
|
pCertAttr = (*g_pfn_CertFindRDNAttr)(szOID_COMMON_NAME, pCertName);
|
||
|
if (NULL == pCertAttr)
|
||
|
{
|
||
|
// Get organization name if no common name found
|
||
|
pCertAttr = (*g_pfn_CertFindRDNAttr)(szOID_ORGANIZATION_NAME, pCertName);
|
||
|
if (NULL == pCertAttr)
|
||
|
{ __leave; }
|
||
|
}
|
||
|
|
||
|
// Find out size of name
|
||
|
dwSize = (*g_pfn_CertRDNValueToStrA)(pCertAttr->dwValueType, &pCertAttr->Value, NULL, 0);
|
||
|
|
||
|
// Allocate memory for name
|
||
|
szName = (LPSTR)HeapAlloc(GetProcessHeap(), 0, dwSize);
|
||
|
if (NULL == szName)
|
||
|
{ __leave; }
|
||
|
|
||
|
// Obtain name from decrypted blob
|
||
|
(*g_pfn_CertRDNValueToStrA)(pCertAttr->dwValueType, &pCertAttr->Value, szName, dwSize);
|
||
|
bReturn = TRUE;
|
||
|
}
|
||
|
__finally
|
||
|
{
|
||
|
if (NULL != pCertName)
|
||
|
{ HeapFree(GetProcessHeap(), 0, pCertName); }
|
||
|
|
||
|
if (!bReturn)
|
||
|
{
|
||
|
if (NULL != szName)
|
||
|
{ HeapFree(GetProcessHeap(), 0, szName); }
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (bReturn)
|
||
|
{ return szName; }
|
||
|
else
|
||
|
{ return NULL; }
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// VerifyFileInfo
|
||
|
// This functions verifies that the installer is valid based on the version
|
||
|
// information stored in the file.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Function parameters:
|
||
|
// INSTALLER_TYPE InstallerType Specifies whether to look for AOL or CS
|
||
|
// LPSTR lpszInstaller Fully qualified path to installer
|
||
|
// PBOOL pbOldClient Is is a client older then 5.0
|
||
|
//-----------------------------------------------------------------------------
|
||
|
BOOL VerifyFileInfo(WORD &wExeType, LPSTR lpszInstaller, PBOOL pbOldClient)
|
||
|
{
|
||
|
BOOL bReturn = FALSE;
|
||
|
BOOL bResult;
|
||
|
BYTE *lpVerInfo = NULL;
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
// Get size of version info in file
|
||
|
DWORD dwHandle = 0;
|
||
|
DWORD dwVerInfoSize = (*g_pfn_GetFileVersionInfoSizeA)(lpszInstaller, &dwHandle);
|
||
|
|
||
|
// Allocate memory for version info
|
||
|
lpVerInfo = (BYTE *)HeapAlloc(GetProcessHeap(), 0, dwVerInfoSize);
|
||
|
if (NULL == lpVerInfo)
|
||
|
{ __leave; }
|
||
|
|
||
|
// Get version info from file
|
||
|
bResult = (*g_pfn_GetFileVersionInfoA)(lpszInstaller, NULL, dwVerInfoSize, lpVerInfo);
|
||
|
if (!bResult)
|
||
|
{ __leave; }
|
||
|
|
||
|
// Get Language code page
|
||
|
DWORD *pdwTrans;
|
||
|
UINT uiBytes;
|
||
|
DWORD dwLangCodepage = 0;
|
||
|
|
||
|
bResult = (*g_pfn_VerQueryValueA)(lpVerInfo, "\\VarFileInfo\\Translation", (VOID **)&pdwTrans, &uiBytes);
|
||
|
if (bResult)
|
||
|
{ dwLangCodepage = SWAPWORDS(*pdwTrans); } // Translate language code page to something we can use
|
||
|
else
|
||
|
{ dwLangCodepage = 0x040904e4; } // Try English multilanguage code page
|
||
|
|
||
|
// Obtain the "CompanyName" from the version info
|
||
|
CHAR szQuery[MAX_PATH];
|
||
|
PCHAR pszVerInfo;
|
||
|
StringCchPrintfA(szQuery, MAX_PATH, "\\StringFileInfo\\%08X\\CompanyName", dwLangCodepage);
|
||
|
bResult = (*g_pfn_VerQueryValueA)(lpVerInfo, szQuery, (VOID **)&pszVerInfo, &uiBytes);
|
||
|
if (!bResult)
|
||
|
{ __leave; }
|
||
|
|
||
|
// Check "CompanyName"
|
||
|
if (SERVICE_AOL & wExeType)
|
||
|
{
|
||
|
if ((NULL == strstr(pszVerInfo, "America Online")) &&
|
||
|
(NULL == strstr(pszVerInfo, "AOL")))
|
||
|
{ __leave; }
|
||
|
}
|
||
|
else if (SERVICE_CS & wExeType)
|
||
|
{
|
||
|
if (0 != strcmp("CompuServe Interactive Services, Inc.", pszVerInfo))
|
||
|
{ __leave; }
|
||
|
}
|
||
|
else
|
||
|
{ __leave; }
|
||
|
|
||
|
// Get fixed file info
|
||
|
VS_FIXEDFILEINFO* pVS_FFI;
|
||
|
bResult = (*g_pfn_VerQueryValueA)(lpVerInfo, "\\", (VOID **)&pVS_FFI, &uiBytes);
|
||
|
if (!bResult)
|
||
|
{ __leave; }
|
||
|
|
||
|
// Check if this is the Country Picker
|
||
|
StringCchPrintfA(szQuery, MAX_PATH, "\\StringFileInfo\\%08X\\ProductName", dwLangCodepage);
|
||
|
bResult = (*g_pfn_VerQueryValueA)(lpVerInfo, szQuery, (VOID **)&pszVerInfo, &uiBytes);
|
||
|
if ((bResult) && (NULL != strstr(pszVerInfo, "Country Picker")))
|
||
|
{
|
||
|
wExeType |= COUNTRY_PICKER;
|
||
|
if (0x00010005 > pVS_FFI->dwProductVersionMS)
|
||
|
{ __leave; }
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ((0x00060000 > pVS_FFI->dwProductVersionMS) ||
|
||
|
((0x00060000 >= pVS_FFI->dwProductVersionMS) &&
|
||
|
(0x00020000 > pVS_FFI->dwProductVersionLS)))
|
||
|
{
|
||
|
if ((NULL != pbOldClient) &&
|
||
|
(CLIENT & wExeType) &&
|
||
|
(0x00050000 > pVS_FFI->dwProductVersionMS))
|
||
|
{ *pbOldClient = TRUE; }
|
||
|
|
||
|
__leave;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bReturn = TRUE;
|
||
|
}
|
||
|
__finally
|
||
|
{
|
||
|
if (NULL != lpVerInfo)
|
||
|
{ HeapFree(GetProcessHeap(), 0, lpVerInfo); }
|
||
|
}
|
||
|
|
||
|
return bReturn;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// VerifyCertificate
|
||
|
// This functions verifies that the install has not been modified since
|
||
|
// being signed by America Online.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Function parameters:
|
||
|
// LPSTR lpszInstaller Fully qualified path to installer
|
||
|
//-----------------------------------------------------------------------------
|
||
|
BOOL VerifyCertificate(LPSTR lpszInstaller)
|
||
|
{
|
||
|
GUID ActionGUID = WIN_SPUB_ACTION_PUBLISHED_SOFTWARE;
|
||
|
GUID SubjectPeImage = WIN_TRUST_SUBJTYPE_PE_IMAGE;
|
||
|
|
||
|
WIN_TRUST_SUBJECT_FILE Subject;
|
||
|
|
||
|
// Subject.lpPath is a WCHAR string, must convert
|
||
|
LPWSTR lpwszInstaller = NULL;
|
||
|
int cchUnicodeSize = 0;
|
||
|
cchUnicodeSize = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
|
||
|
lpszInstaller, -1, NULL, 0);
|
||
|
|
||
|
lpwszInstaller = (LPWSTR)malloc(cchUnicodeSize * sizeof(WCHAR));
|
||
|
|
||
|
if (0 == MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, lpszInstaller,
|
||
|
-1, lpwszInstaller, cchUnicodeSize))
|
||
|
{
|
||
|
if (lpwszInstaller)
|
||
|
{ free(lpwszInstaller); }
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
Subject.lpPath = lpwszInstaller;
|
||
|
Subject.hFile = INVALID_HANDLE_VALUE; // Open the using the lpPath field
|
||
|
|
||
|
WIN_TRUST_ACTDATA_CONTEXT_WITH_SUBJECT ActionData;
|
||
|
|
||
|
ActionData.Subject = &Subject;
|
||
|
ActionData.hClientToken = NULL;
|
||
|
|
||
|
ActionData.SubjectType = &SubjectPeImage;
|
||
|
|
||
|
// Verify the file has not be changed since being signed
|
||
|
HRESULT hr = (*g_pfn_WinVerifyTrust)((HWND)INVALID_HANDLE_VALUE, &ActionGUID, (WINTRUST_DATA *) &ActionData);
|
||
|
|
||
|
if (lpwszInstaller)
|
||
|
{ free(lpwszInstaller); }
|
||
|
|
||
|
if (S_OK == hr)
|
||
|
{ return TRUE; }
|
||
|
else
|
||
|
{ return FALSE; }
|
||
|
}
|