|
|
/*++
Copyright (c) 1989-2000 Microsoft Corporation
Module Name:
attributes.c
Abstract:
This file contains complete implementation of attribute retrieval and caching.
Author:
vadimb created sometime in 2000
Revision History:
several people contributed (clupu, dmunsil...)
--*/
//
// Obtain tag information
//
#define _WANT_TAG_INFO
#include "sdbp.h"
#include <stddef.h>
#include <time.h>
#if defined(KERNEL_MODE) && defined(ALLOC_DATA_PRAGMA)
#pragma data_seg()
#endif // KERNEL_MODE && ALLOC_DATA_PRAGMA
//
// Attribute tags
// The attributes are checked in the order they are listed below.
//
TAG g_rgAttributeTags[] = { TAG_SIZE, TAG_CHECKSUM, TAG_BIN_FILE_VERSION, TAG_BIN_PRODUCT_VERSION, TAG_PRODUCT_VERSION, TAG_FILE_DESCRIPTION, TAG_COMPANY_NAME, TAG_PRODUCT_NAME, TAG_FILE_VERSION, TAG_ORIGINAL_FILENAME, TAG_INTERNAL_NAME, TAG_LEGAL_COPYRIGHT, TAG_VERDATEHI, TAG_VERDATELO, TAG_VERFILEOS, TAG_VERFILETYPE, TAG_MODULE_TYPE, TAG_PE_CHECKSUM, TAG_LINKER_VERSION, #ifndef KERNEL_MODE
TAG_16BIT_DESCRIPTION, TAG_16BIT_MODULE_NAME, #endif
TAG_UPTO_BIN_FILE_VERSION, TAG_UPTO_BIN_PRODUCT_VERSION, TAG_LINK_DATE, TAG_UPTO_LINK_DATE, TAG_VER_LANGUAGE };
#define ATTRIBUTE_COUNT ARRAYSIZE(g_rgAttributeTags)
static TAG_INFO gaTagInfo[] = { {TAG_DATABASE ,TEXT("DATABASE")}, {TAG_LIBRARY ,TEXT("LIBRARY")}, {TAG_INEXCLUDE ,TEXT("INEXCLUDE")}, {TAG_SHIM ,TEXT("SHIM")}, {TAG_PATCH ,TEXT("PATCH")}, {TAG_FLAG ,TEXT("FLAG")}, {TAG_APP ,TEXT("APP")}, {TAG_EXE ,TEXT("EXE")}, {TAG_MATCHING_FILE ,TEXT("MATCHING_FILE")}, {TAG_SHIM_REF ,TEXT("SHIM_REF")}, {TAG_PATCH_REF ,TEXT("PATCH_REF")}, {TAG_FLAG_REF ,TEXT("FLAG_REF")}, {TAG_LAYER ,TEXT("LAYER")}, {TAG_FILE ,TEXT("FILE")}, {TAG_APPHELP ,TEXT("APPHELP")}, {TAG_LINK ,TEXT("LINK")}, {TAG_DATA ,TEXT("DATA")}, {TAG_ACTION ,TEXT("ACTION")}, {TAG_MSI_TRANSFORM ,TEXT("MSI TRANSFORM")}, {TAG_MSI_TRANSFORM_REF ,TEXT("MSI TRANSFORM REF")}, {TAG_MSI_PACKAGE ,TEXT("MSI PACKAGE")}, {TAG_MSI_CUSTOM_ACTION ,TEXT("MSI CUSTOM ACTION")},
{TAG_NAME ,TEXT("NAME")}, {TAG_DESCRIPTION ,TEXT("DESCRIPTION")}, {TAG_MODULE ,TEXT("MODULE")}, {TAG_API ,TEXT("API")}, {TAG_VENDOR ,TEXT("VENDOR")}, {TAG_APP_NAME ,TEXT("APP_NAME")}, {TAG_DLLFILE ,TEXT("DLLFILE")}, {TAG_COMMAND_LINE ,TEXT("COMMAND_LINE")}, {TAG_ACTION_TYPE ,TEXT("ACTION_TYPE")}, {TAG_COMPANY_NAME ,TEXT("COMPANY_NAME")}, {TAG_WILDCARD_NAME ,TEXT("WILDCARD_NAME")}, {TAG_PRODUCT_NAME ,TEXT("PRODUCT_NAME")}, {TAG_PRODUCT_VERSION ,TEXT("PRODUCT_VERSION")}, {TAG_FILE_DESCRIPTION ,TEXT("FILE_DESCRIPTION")}, {TAG_FILE_VERSION ,TEXT("FILE_VERSION")}, {TAG_ORIGINAL_FILENAME ,TEXT("ORIGINAL_FILENAME")}, {TAG_INTERNAL_NAME ,TEXT("INTERNAL_NAME")}, {TAG_LEGAL_COPYRIGHT ,TEXT("LEGAL_COPYRIGHT")}, {TAG_16BIT_DESCRIPTION ,TEXT("S16BIT_DESCRIPTION")}, {TAG_APPHELP_DETAILS ,TEXT("PROBLEM_DETAILS")}, {TAG_LINK_URL ,TEXT("LINK_URL")}, {TAG_LINK_TEXT ,TEXT("LINK_TEXT")}, {TAG_APPHELP_TITLE ,TEXT("APPHELP_TITLE")}, {TAG_APPHELP_CONTACT ,TEXT("APPHELP_CONTACT")}, {TAG_SXS_MANIFEST ,TEXT("SXS_MANIFEST")}, {TAG_DATA_STRING ,TEXT("DATA_STRING")}, {TAG_MSI_TRANSFORM_FILE ,TEXT("MSI_TRANSFORM_FILE")}, {TAG_16BIT_MODULE_NAME ,TEXT("S16BIT_MODULE_NAME")}, {TAG_LAYER_DISPLAYNAME ,TEXT("LAYER_DISPLAYNAME")}, {TAG_COMPILER_VERSION ,TEXT("COMPILER_VERSION")}, {TAG_SIZE ,TEXT("SIZE")}, {TAG_OFFSET ,TEXT("OFFSET")}, {TAG_CHECKSUM ,TEXT("CHECKSUM")}, {TAG_SHIM_TAGID ,TEXT("SHIM_TAGID")}, {TAG_PATCH_TAGID ,TEXT("PATCH_TAGID")}, {TAG_LAYER_TAGID ,TEXT("LAYER_TAGID")}, {TAG_FLAG_TAGID ,TEXT("FLAG_TAGID")}, {TAG_MODULE_TYPE ,TEXT("MODULE_TYPE")}, {TAG_VERDATEHI ,TEXT("VERFILEDATEHI")}, {TAG_VERDATELO ,TEXT("VERFILEDATELO")}, {TAG_VERFILEOS ,TEXT("VERFILEOS")}, {TAG_VERFILETYPE ,TEXT("VERFILETYPE")}, {TAG_PE_CHECKSUM ,TEXT("PE_CHECKSUM")}, {TAG_LINKER_VERSION ,TEXT("LINKER_VERSION")}, {TAG_LINK_DATE ,TEXT("LINK_DATE")}, {TAG_UPTO_LINK_DATE ,TEXT("UPTO_LINK_DATE")}, {TAG_OS_SERVICE_PACK ,TEXT("OS_SERVICE_PACK")}, {TAG_VER_LANGUAGE ,TEXT("VER_LANGUAGE")},
{TAG_PREVOSMAJORVER ,TEXT("PREVOSMAJORVERSION")}, {TAG_PREVOSMINORVER ,TEXT("PREVOSMINORVERSION")}, {TAG_PREVOSPLATFORMID ,TEXT("PREVOSPLATFORMID")}, {TAG_PREVOSBUILDNO ,TEXT("PREVOSBUILDNO")}, {TAG_PROBLEMSEVERITY ,TEXT("PROBLEM_SEVERITY")}, {TAG_HTMLHELPID ,TEXT("HTMLHELPID")}, {TAG_INDEX_FLAGS ,TEXT("INDEXFLAGS")}, {TAG_LANGID ,TEXT("APPHELP_LANGID")}, {TAG_ENGINE ,TEXT("ENGINE")}, {TAG_FLAGS ,TEXT("FLAGS") }, {TAG_DATA_VALUETYPE ,TEXT("VALUETYPE")}, {TAG_DATA_DWORD ,TEXT("DATA_DWORD")}, {TAG_MSI_TRANSFORM_TAGID,TEXT("MSI_TRANSFORM_TAGID")}, {TAG_RUNTIME_PLATFORM, TEXT("RUNTIME_PLATFORM")}, {TAG_OS_SKU, TEXT("OS_SKU")},
{TAG_INCLUDE ,TEXT("INCLUDE")}, {TAG_GENERAL ,TEXT("GENERAL")}, {TAG_MATCH_LOGIC_NOT ,TEXT("MATCH_LOGIC_NOT")}, {TAG_APPLY_ALL_SHIMS ,TEXT("APPLY_ALL_SHIMS")}, {TAG_USE_SERVICE_PACK_FILES ,TEXT("USE_SERVICE_PACK_FILES")},
{TAG_TIME ,TEXT("TIME")}, {TAG_BIN_FILE_VERSION ,TEXT("BIN_FILE_VERSION")}, {TAG_BIN_PRODUCT_VERSION,TEXT("BIN_PRODUCT_VERSION")}, {TAG_MODTIME ,TEXT("MODTIME")}, {TAG_FLAG_MASK_KERNEL ,TEXT("FLAG_MASK_KERNEL")}, {TAG_FLAG_MASK_USER ,TEXT("FLAG_MASK_USER")}, {TAG_FLAG_MASK_SHELL ,TEXT("FLAG_MASK_SHELL")}, {TAG_FLAG_MASK_FUSION ,TEXT("FLAG_MASK_FUSION")}, {TAG_UPTO_BIN_PRODUCT_VERSION, TEXT("UPTO_BIN_PRODUCT_VERSION")}, {TAG_UPTO_BIN_FILE_VERSION, TEXT("UPTO_BIN_FILE_VERSION")}, {TAG_DATA_QWORD ,TEXT("DATA_QWORD")}, {TAG_FLAGS_NTVDM1 ,TEXT("FLAGS_NTVDM1")}, {TAG_FLAGS_NTVDM2 ,TEXT("FLAGS_NTVDM2")}, {TAG_FLAGS_NTVDM3 ,TEXT("FLAGS_NTVDM3")},
{TAG_PATCH_BITS ,TEXT("PATCH_BITS")}, {TAG_FILE_BITS ,TEXT("FILE_BITS")}, {TAG_EXE_ID ,TEXT("EXE_ID(GUID)")}, {TAG_DATA_BITS ,TEXT("DATA_BITS")}, {TAG_MSI_PACKAGE_ID ,TEXT("MSI_PACKAGE_ID(GUID)")}, {TAG_DATABASE_ID ,TEXT("DATABASE_ID(GUID)")}, {TAG_MATCH_MODE ,TEXT("MATCH_MODE")},
//
// Internal types defined in shimdb.h
//
{TAG_STRINGTABLE ,TEXT("STRINGTABLE")}, {TAG_INDEXES ,TEXT("INDEXES")}, {TAG_INDEX ,TEXT("INDEX")}, {TAG_INDEX_TAG ,TEXT("INDEX_TAG")}, {TAG_INDEX_KEY ,TEXT("INDEX_KEY")}, {TAG_INDEX_BITS ,TEXT("INDEX_BITS")}, {TAG_STRINGTABLE_ITEM ,TEXT("STRTAB_ITEM")}, {TAG_TAG ,TEXT("TAG")}, {TAG_TAGID ,TEXT("TAGID")},
{TAG_NULL ,TEXT("")} // always needs to be last item
};
static MOD_TYPE_STRINGS g_rgModTypeStrings[] = { {MT_UNKNOWN_MODULE, TEXT("NONE")}, {MT_W16_MODULE, TEXT("WIN16")}, {MT_W32_MODULE, TEXT("WIN32")}, {MT_DOS_MODULE, TEXT("DOS")} };
//
// Version Strings for stringref attributes
//
typedef struct _VER_STRINGS { TAG tTag; LPTSTR szName; } VER_STRINGS;
static VER_STRINGS g_rgVerStrings[] = { {TAG_PRODUCT_VERSION, TEXT("ProductVersion") }, {TAG_FILE_DESCRIPTION, TEXT("FileDescription") }, {TAG_COMPANY_NAME, TEXT("CompanyName") }, {TAG_PRODUCT_NAME, TEXT("ProductName") }, {TAG_FILE_VERSION, TEXT("FileVersion") }, {TAG_ORIGINAL_FILENAME, TEXT("OriginalFilename") }, {TAG_INTERNAL_NAME, TEXT("InternalName") }, {TAG_LEGAL_COPYRIGHT, TEXT("LegalCopyright") } };
//
// Binary version tags (DWORDs and QWORDs)
//
//
static TAG g_rgBinVerTags[] = { TAG_VERDATEHI, TAG_VERDATELO, TAG_VERFILEOS, TAG_VERFILETYPE, TAG_BIN_PRODUCT_VERSION, TAG_BIN_FILE_VERSION, TAG_UPTO_BIN_PRODUCT_VERSION, TAG_UPTO_BIN_FILE_VERSION };
//
// Binary header tags (retrieval requires opening a file).
//
static TAG g_rgHeaderTags[] = { TAG_MODULE_TYPE, TAG_PE_CHECKSUM, TAG_LINKER_VERSION, TAG_CHECKSUM, TAG_16BIT_DESCRIPTION, TAG_16BIT_MODULE_NAME, TAG_LINK_DATE, TAG_UPTO_LINK_DATE };
//
// Basic information tags (size).
//
TAG g_rgDirectoryTags[] = { TAG_SIZE, 0 };
//
// Invalid tag token
//
static TCHAR s_szInvalidTag[] = _T("InvalidTag");
#if defined(KERNEL_MODE) && defined(ALLOC_PRAGMA)
#pragma alloc_text(PAGE, TagToIndex)
#pragma alloc_text(PAGE, SdbTagToString)
#pragma alloc_text(PAGE, SdbpModuleTypeToString)
#pragma alloc_text(PAGE, SdbpSetAttribute)
#pragma alloc_text(PAGE, SdbpQueryStringVersionInformation)
#pragma alloc_text(PAGE, SdbpQueryBinVersionInformation)
#pragma alloc_text(PAGE, SdbpGetVersionAttributesNT)
#pragma alloc_text(PAGE, SdbpGetHeaderAttributes)
#pragma alloc_text(PAGE, SdbpGetAttribute)
#pragma alloc_text(PAGE, SdbpCheckAttribute)
#pragma alloc_text(PAGE, FindFileInfo)
#pragma alloc_text(PAGE, CreateFileInfo)
#pragma alloc_text(PAGE, SdbFreeFileInfo)
#pragma alloc_text(PAGE, SdbpCleanupAttributeMgr)
#pragma alloc_text(PAGE, SdbpCheckAllAttributes)
#pragma alloc_text(PAGE, SdbpQueryVersionString)
#pragma alloc_text(PAGE, SdbpGetModuleType)
#pragma alloc_text(PAGE, SdbpGetModulePECheckSum)
#pragma alloc_text(PAGE, SdbpGetImageNTHeader)
#pragma alloc_text(PAGE, SdbpGetFileChecksum)
#pragma alloc_text(PAGE, SdbpCheckVersion)
#pragma alloc_text(PAGE, SdbpCheckUptoVersion)
#endif // KERNEL_MODE && ALLOC_PRAGMA
int TagToIndex( IN TAG tag // the tag
) /*++
Return: The index in the attribute info array (g_rgAttributeTags).
Desc: Self explanatory. --*/ { int i;
for (i = 0; i < ATTRIBUTE_COUNT; i++) { if (tag == g_rgAttributeTags[i]) { return i; } }
DBGPRINT((sdlError, "TagToIndex", "Invalid attribute 0x%x.\n", tag));
return -1; }
LPCTSTR SdbTagToString( TAG tag ) /*++
Return: The pointer to the string name for the specified tag.
Desc: Self explanatory. --*/ { int i;
for (i = 0; i < ARRAYSIZE(gaTagInfo); ++i) { if (gaTagInfo[i].tWhich == tag) { return gaTagInfo[i].szName; } }
return s_szInvalidTag; }
LPCTSTR SdbpModuleTypeToString( DWORD dwModuleType ) { int i;
for (i = 0; i < ARRAYSIZE(g_rgModTypeStrings); ++i) { if (g_rgModTypeStrings[i].dwModuleType == dwModuleType) { return g_rgModTypeStrings[i].szModuleType; } }
//
// The first element is the "UNKNOWN" type -- NONE
//
return g_rgModTypeStrings[0].szModuleType; }
BOOL SdbpSetAttribute( OUT PFILEINFO pFileInfo, // pointer to the FILEINFO structure.
IN TAG AttrID, // Attribute ID (tag, as in TAG_SIZE
IN PVOID pValue // value
) /*++
Return: TRUE on success, FALSE otherwise.
Desc: This function sets the value for the specified attribute. If pValue is NULL it means that the specified attribute is not available for the file. --*/ { int nAttrInd; PATTRINFO pAttrInfo;
nAttrInd = TagToIndex(AttrID);
if (nAttrInd < 0) { DBGPRINT((sdlError, "SdbpSetAttribute", "Invalid attribute %d.\n", nAttrInd)); return FALSE; }
pAttrInfo = &pFileInfo->Attributes[nAttrInd];
if (pValue == NULL) { //
// No value. Mark and exit.
//
pAttrInfo->dwFlags = (pAttrInfo->dwFlags & ~ATTRIBUTE_AVAILABLE) | ATTRIBUTE_FAILED; return TRUE; }
switch (GETTAGTYPE(AttrID)) { case TAG_TYPE_DWORD: pAttrInfo->dwAttr = *(DWORD*)pValue; break;
case TAG_TYPE_QWORD: pAttrInfo->ullAttr = *(ULONGLONG*)pValue; break;
case TAG_TYPE_STRINGREF: pAttrInfo->lpAttr = (LPTSTR)pValue; break; }
pAttrInfo->tAttrID = AttrID; pAttrInfo->dwFlags |= ATTRIBUTE_AVAILABLE;
return TRUE; }
//
// This is a guard against bad code in version.dll that stomps over the
// buffer size for Unicode apis on 16-bit exes.
//
#define VERSIONINFO_BUFFER_PAD 16
void SdbpQueryStringVersionInformation( IN PSDBCONTEXT pContext, IN PFILEINFO pFileInfo, OUT LPVOID pVersionInfo ) /*++
Return: void.
Desc: Sets all the version string info available for the specified file. --*/ { int i; LPTSTR szVerString; PLANGANDCODEPAGE pLangCodePage = NULL; UINT cbLangCP = 0; int nTranslations = 0;
if (!pContext->pfnVerQueryValue(pVersionInfo, TEXT("\\VarFileInfo\\Translation"), (LPVOID)&pLangCodePage, &cbLangCP)) { DBGPRINT((sdlError, "SdbpQueryStringVersionInformation", "VerQueryValue failed for translation\n")); pLangCodePage = NULL; }
nTranslations = cbLangCP / sizeof(*pLangCodePage);
for (i = 0; i < ARRAYSIZE(g_rgVerStrings); ++i) { szVerString = SdbpQueryVersionString(pContext, pVersionInfo, pLangCodePage, nTranslations, g_rgVerStrings[i].szName);
SdbpSetAttribute(pFileInfo, g_rgVerStrings[i].tTag, szVerString); }
#ifndef KERNEL_MODE
//
// Set the attribute for Language
//
if (pLangCodePage != NULL && nTranslations == 1) {
DWORD dwLanguage = (DWORD)pLangCodePage->wLanguage;
SdbpSetAttribute(pFileInfo, TAG_VER_LANGUAGE, &dwLanguage); } else { SdbpSetAttribute(pFileInfo, TAG_VER_LANGUAGE, NULL); }
#endif // KERNEL_MODE
}
VOID SdbpQueryBinVersionInformation( IN PSDBCONTEXT pContext, IN PFILEINFO pFileInfo, OUT VS_FIXEDFILEINFO* pFixedInfo ) /*++
Return: void.
Desc: Sets all the version string info available for the specified file from the fixed size resources. --*/ { LARGE_INTEGER liVerData;
SdbpSetAttribute(pFileInfo, TAG_VERDATEHI, &pFixedInfo->dwFileDateMS); SdbpSetAttribute(pFileInfo, TAG_VERDATELO, &pFixedInfo->dwFileDateLS); SdbpSetAttribute(pFileInfo, TAG_VERFILEOS, &pFixedInfo->dwFileOS); SdbpSetAttribute(pFileInfo, TAG_VERFILETYPE, &pFixedInfo->dwFileType);
liVerData.LowPart = pFixedInfo->dwProductVersionLS; liVerData.HighPart = pFixedInfo->dwProductVersionMS; SdbpSetAttribute(pFileInfo, TAG_BIN_PRODUCT_VERSION, &liVerData.QuadPart); SdbpSetAttribute(pFileInfo, TAG_UPTO_BIN_PRODUCT_VERSION, &liVerData.QuadPart);
liVerData.LowPart = pFixedInfo->dwFileVersionLS; liVerData.HighPart = pFixedInfo->dwFileVersionMS; SdbpSetAttribute(pFileInfo, TAG_BIN_FILE_VERSION, &liVerData.QuadPart); SdbpSetAttribute(pFileInfo, TAG_UPTO_BIN_FILE_VERSION, &liVerData.QuadPart); UNREFERENCED_PARAMETER(pContext); }
#if defined(NT_MODE) || defined(KERNEL_MODE)
BOOL SdbpGetVersionAttributesNT( IN PSDBCONTEXT pContext, OUT PFILEINFO pFileInfo, IN PIMAGEFILEDATA pImageData ) /*++
Return: TRUE on success, FALSE otherwise.
Desc: This function retrieves all of the Version-related attributes Imports apis from version.dll if called for the first time --*/ { BOOL bSuccess; LPVOID pVersionInfo = NULL; VS_FIXEDFILEINFO* pFixedInfo = NULL; int i;
//
// First retrieve the version info.
//
bSuccess = SdbpGetFileVersionInformation(pImageData, &pVersionInfo, &pFixedInfo);
if (!bSuccess) { DBGPRINT((sdlInfo, "SdbpGetVersionAttributesNT", "No version info.\n")); goto ErrHandle; }
//
// Version information available.
//
//
// Set the pointer to our internal function.
//
pContext->pfnVerQueryValue = SdbpVerQueryValue;
for (i = 0; i < ARRAYSIZE(g_rgVerStrings); ++i) { SdbpSetAttribute(pFileInfo, g_rgVerStrings[i].tTag, NULL); }
SdbpSetAttribute(pFileInfo, TAG_VER_LANGUAGE, NULL);
//
// Query binary stuff
//
SdbpQueryBinVersionInformation(pContext, pFileInfo, pFixedInfo);
pFileInfo->pVersionInfo = pVersionInfo;
return TRUE;
ErrHandle: //
// Reset all the string info.
//
for (i = 0; i < ARRAYSIZE(g_rgBinVerTags); ++i) { SdbpSetAttribute(pFileInfo, g_rgBinVerTags[i], NULL); }
for (i = 0; i < ARRAYSIZE(g_rgVerStrings); ++i) { SdbpSetAttribute(pFileInfo, g_rgVerStrings[i].tTag, NULL); }
return FALSE; }
#endif // NT_MODE || KERNEL_MODE
BOOL SdbpGetHeaderAttributes( IN PSDBCONTEXT pContext, OUT PFILEINFO pFileInfo ) /*++
Return: TRUE on success, FALSE otherwise.
Desc: This function retrieves the header attributes for the specified file. --*/ { IMAGEFILEDATA ImageData; ULONG ulPEChecksum = 0; ULONG ulChecksum = 0; DWORD dwModuleType = 0; DWORD dwLinkerVer; DWORD dwLinkDate; BOOL bSuccess; int i;
ImageData.dwFlags = 0;
if (pFileInfo->hFile != INVALID_HANDLE_VALUE) { ImageData.hFile = pFileInfo->hFile; ImageData.dwFlags |= IMAGEFILEDATA_HANDLEVALID; }
if (pFileInfo->pImageBase != NULL) { ImageData.pBase = pFileInfo->pImageBase; ImageData.ViewSize = (SIZE_T) pFileInfo->dwImageSize; ImageData.FileSize = (ULONGLONG)pFileInfo->dwImageSize; ImageData.dwFlags |= IMAGEFILEDATA_PBASEVALID; }
//
// SdbpOpenAndMapFile uses DOS_PATH type as an argument
// In kernel mode this parameter is ignored.
//
if (SdbpOpenAndMapFile(pFileInfo->FilePath, &ImageData, DOS_PATH)) {
bSuccess = SdbpGetModuleType(&dwModuleType, &ImageData); SdbpSetAttribute(pFileInfo, TAG_MODULE_TYPE, bSuccess ? (PVOID)&dwModuleType : NULL);
bSuccess = SdbpGetModulePECheckSum(&ulPEChecksum, &dwLinkerVer, &dwLinkDate, &ImageData); SdbpSetAttribute(pFileInfo, TAG_PE_CHECKSUM, bSuccess ? (PVOID)&ulPEChecksum : NULL); SdbpSetAttribute(pFileInfo, TAG_LINKER_VERSION, bSuccess ? (PVOID)&dwLinkerVer : NULL); SdbpSetAttribute(pFileInfo, TAG_LINK_DATE, bSuccess ? (PVOID)&dwLinkDate : NULL); SdbpSetAttribute(pFileInfo, TAG_UPTO_LINK_DATE, bSuccess ? (PVOID)&dwLinkDate : NULL);
bSuccess = SdbpGetFileChecksum(&ulChecksum, &ImageData); SdbpSetAttribute(pFileInfo, TAG_CHECKSUM, bSuccess ? (PVOID)&ulChecksum : NULL);
#ifndef KERNEL_MODE
//
// Now retrieve 16-bit description string, it's max size is 256 bytes.
//
// This attribute is not available in kernel mode.
//
bSuccess = SdbpGet16BitDescription(&pFileInfo->pDescription16, &ImageData); SdbpSetAttribute(pFileInfo, TAG_16BIT_DESCRIPTION, pFileInfo->pDescription16); bSuccess = SdbpGet16BitModuleName(&pFileInfo->pModuleName16, &ImageData); SdbpSetAttribute(pFileInfo, TAG_16BIT_MODULE_NAME, pFileInfo->pModuleName16);
#if defined(NT_MODE)
//
// Hit this case only on current platform
//
if (pFileInfo->hFile != INVALID_HANDLE_VALUE || pFileInfo->pImageBase != NULL) {
SdbpGetVersionAttributesNT(pContext, pFileInfo, &ImageData); } #endif // NT_MODE
#else // KERNEL_MODE
//
// When we are running in kernel mode retrieve version-related
// data now as well.
//
SdbpGetVersionAttributesNT(pContext, pFileInfo, &ImageData);
//
// Retrieve file directory attributes.
//
SdbpGetFileDirectoryAttributesNT(pFileInfo, &ImageData);
#endif // KERNEL_MODE
SdbpUnmapAndCloseFile(&ImageData);
return TRUE; }
for (i = 0; i < ARRAYSIZE(g_rgHeaderTags); ++i) { SdbpSetAttribute(pFileInfo, g_rgHeaderTags[i], NULL); }
#ifdef KERNEL_MODE
//
// Reset all the version attributes here as well.
//
for (i = 0; i < ARRAYSIZE(g_rgBinVerTags); ++i) { SdbpSetAttribute(pFileInfo, g_rgBinVerTags[i], NULL); }
for (i = 0; i < ARRAYSIZE(g_rgVerStrings); ++i) { SdbpSetAttribute(pFileInfo, g_rgVerStrings[i].tTag, NULL); } #endif // KERNEL_MODE
return FALSE; UNREFERENCED_PARAMETER(pContext); }
BOOL SdbpGetAttribute( IN PSDBCONTEXT pContext, OUT PFILEINFO pFileInfo, IN TAG AttrID ) /*++
Return: TRUE on success, FALSE otherwise.
Desc: Retrieve an attribute for a given file. We retrieve all the attributes of the same class. --*/ { BOOL bReturn = FALSE;
switch (AttrID) { //
// The tags below require checking the file and making a directory query.
//
case TAG_SIZE:
#ifndef KERNEL_MODE // in kernel mode we fall through to header attributes
bReturn = SdbpGetFileDirectoryAttributes(pFileInfo); break;
#endif // KERNEL_MODE
//
// The tags below require retrieving version resources.
//
case TAG_VERDATEHI: case TAG_VERDATELO: case TAG_VERFILEOS: case TAG_VERFILETYPE: case TAG_UPTO_BIN_PRODUCT_VERSION: case TAG_UPTO_BIN_FILE_VERSION: case TAG_BIN_FILE_VERSION: case TAG_BIN_PRODUCT_VERSION: case TAG_PRODUCT_VERSION: case TAG_FILE_DESCRIPTION: case TAG_COMPANY_NAME: case TAG_PRODUCT_NAME: case TAG_FILE_VERSION: case TAG_ORIGINAL_FILENAME: case TAG_INTERNAL_NAME: case TAG_LEGAL_COPYRIGHT: case TAG_VER_LANGUAGE:
//
// In KERNEL_MODE we fall through and do the attributes using the
// header attributes.
//
#ifndef KERNEL_MODE
//
// Version attributes are retrieved through the header attributes if
// caller provided a handle/image base
//
if (pFileInfo->hFile == INVALID_HANDLE_VALUE && pFileInfo->pImageBase == NULL) { bReturn = SdbpGetVersionAttributes(pContext, pFileInfo); break; }
#endif // KERNEL_MODE
//
// The tags below require opening a file and mapping it into memory.
//
case TAG_CHECKSUM: case TAG_PE_CHECKSUM: case TAG_LINKER_VERSION: case TAG_16BIT_DESCRIPTION: case TAG_16BIT_MODULE_NAME: case TAG_MODULE_TYPE: case TAG_UPTO_LINK_DATE: case TAG_LINK_DATE: bReturn = SdbpGetHeaderAttributes(pContext, pFileInfo); break; }
return bReturn; }
BOOL SdbpCheckAttribute( IN PSDBCONTEXT pContext, // Database Context pointer
IN PVOID pFileData, // pointer returned from CheckFile
IN TAG AttrID, // Attribute ID
IN PVOID pAttribute // attribute value ptr (see above for description)
) /*++
Return: TRUE if the value for given attribute matches the file's attribute, FALSE otherwise.
Desc: Check an attribute against a given value. This function retrieves attributes as necessary. --*/ { int nAttrIndex; PATTRINFO pAttrInfo; BOOL bReturn = FALSE; PFILEINFO pFileInfo = (PFILEINFO)pFileData;
if (pAttribute == NULL) { DBGPRINT((sdlError, "SdbpCheckAttribute", "Invalid parameter.\n")); return FALSE; }
nAttrIndex = TagToIndex(AttrID);
if (nAttrIndex < 0) { DBGPRINT((sdlError, "SdbpCheckAttribute", "Bad Attribute ID 0x%x\n", AttrID)); return FALSE; }
//
// Now see if this attribute is any good.
//
pAttrInfo = &pFileInfo->Attributes[nAttrIndex];
if (!(pAttrInfo->dwFlags & ATTRIBUTE_AVAILABLE)) { //
// See if we have tried already
//
if (pAttrInfo->dwFlags & ATTRIBUTE_FAILED) { DBGPRINT((sdlInfo, "SdbpCheckAttribute", "Already tried to get attr ID 0x%x.\n", AttrID)); return FALSE; }
//
// The attribute has not been retrieved yet, do it now then.
//
// Try to obtain this attribute from the file.
//
if (!SdbpGetAttribute(pContext, pFileInfo, AttrID)) { DBGPRINT((sdlWarning, "SdbpCheckAttribute", "Failed to get attribute \"%s\" for \"%s\"\n", SdbTagToString(AttrID), pFileInfo->FilePath)); //
// ATTRIBUTE_FAILED is set by the SdbpGetAttribute
//
return FALSE; } }
//
// Check again here in case we had to retrieve the attribute.
//
if (!(pAttrInfo->dwFlags & ATTRIBUTE_AVAILABLE)) { return FALSE; }
switch (AttrID) {
case TAG_BIN_PRODUCT_VERSION: case TAG_BIN_FILE_VERSION:
bReturn = SdbpCheckVersion(*(ULONGLONG*)pAttribute, pAttrInfo->ullAttr);
if (!bReturn) { #ifdef _DEBUG_SPEW
ULONGLONG qwDBFileVer = *(ULONGLONG*)pAttribute; ULONGLONG qwBinFileVer = pAttrInfo->ullAttr;
DBGPRINT((sdlInfo, "SdbpCheckAttribute", "\"%s\" mismatch file: \"%s\". Expected %d.%d.%d.%d, Found %d.%d.%d.%d\n", SdbTagToString(AttrID), pFileInfo->FilePath, (WORD)(qwDBFileVer >> 48), (WORD)(qwDBFileVer >> 32), (WORD)(qwDBFileVer >> 16), (WORD)(qwDBFileVer), (WORD)(qwBinFileVer >> 48), (WORD)(qwBinFileVer >> 32), (WORD)(qwBinFileVer >> 16), (WORD)(qwBinFileVer))); #endif
} break;
case TAG_UPTO_BIN_PRODUCT_VERSION: case TAG_UPTO_BIN_FILE_VERSION:
bReturn = SdbpCheckUptoVersion(*(ULONGLONG*)pAttribute, pAttrInfo->ullAttr);
if (!bReturn) { #ifdef _DEBUG_SPEW
ULONGLONG qwDBFileVer = *(ULONGLONG*)pAttribute; ULONGLONG qwBinFileVer = pAttrInfo->ullAttr;
DBGPRINT((sdlInfo, "SdbpCheckAttribute", "\"%s\" mismatch file: \"%s\". Expected %d.%d.%d.%d, Found %d.%d.%d.%d\n", SdbTagToString(AttrID), pFileInfo->FilePath, (WORD)(qwDBFileVer >> 48), (WORD)(qwDBFileVer >> 32), (WORD)(qwDBFileVer >> 16), (WORD)(qwDBFileVer), (WORD)(qwBinFileVer >> 48), (WORD)(qwBinFileVer >> 32), (WORD)(qwBinFileVer >> 16), (WORD)(qwBinFileVer))); #endif
} break;
case TAG_UPTO_LINK_DATE: bReturn = (*(DWORD*)pAttribute >= pAttrInfo->dwAttr);
if (!bReturn) { DBGPRINT((sdlInfo, "SdbpCheckAttribute", "\"%s\" mismatch file \"%s\". Expected less than 0x%x Found 0x%x\n", SdbTagToString(AttrID), pFileInfo->FilePath, *(DWORD*)pAttribute, pAttrInfo->dwAttr)); } break;
default:
switch (GETTAGTYPE(AttrID)) { case TAG_TYPE_DWORD: //
// This is likely to be hit first.
//
bReturn = (*(DWORD*)pAttribute == pAttrInfo->dwAttr);
if (!bReturn) { DBGPRINT((sdlInfo, "SdbpCheckAttribute", "\"%s\" mismatch file \"%s\". Expected 0x%x Found 0x%x\n", SdbTagToString(AttrID), pFileInfo->FilePath, *(DWORD*)pAttribute, pAttrInfo->dwAttr)); } break;
case TAG_TYPE_STRINGREF: bReturn = SdbpPatternMatch((LPCTSTR)pAttribute, (LPCTSTR)pAttrInfo->lpAttr);
if (!bReturn) { DBGPRINT((sdlInfo, "SdbpCheckAttribute", "\"%s\" mismatch file \"%s\". Expected \"%s\" Found \"%s\"\n", SdbTagToString(AttrID), pFileInfo->FilePath, pAttribute, pAttrInfo->lpAttr));
} break;
case TAG_TYPE_QWORD: bReturn = (*(ULONGLONG*)pAttribute == pAttrInfo->ullAttr);
if (!bReturn) { DBGPRINT((sdlInfo, "SdbpCheckAttribute", "\"%s\" mismatch file \"%s\". Expected 0x%I64x Found 0x%I64x\n", SdbTagToString(AttrID), pFileInfo->FilePath, *(ULONGLONG*)pAttribute, pAttrInfo->ullAttr)); }
break; } break; }
return bReturn; }
PFILEINFO FindFileInfo( IN PSDBCONTEXT pContext, IN LPCTSTR FilePath ) /*++
Return: A pointer to the cached FILEINFO structure if one is found or NULL otherwise.
Desc: This function performs a search in the file cache to determine whether a given file has already been touched. --*/ { PFILEINFO pFileInfo = (PFILEINFO)pContext->pFileAttributeCache; // global cache
while (pFileInfo != NULL) { if (ISEQUALSTRING(pFileInfo->FilePath, FilePath)) { DBGPRINT((sdlInfo, "FindFileInfo", "FILEINFO for \"%s\" found in the cache.\n", FilePath)); return pFileInfo; }
pFileInfo = pFileInfo->pNext; }
return NULL; }
PFILEINFO CreateFileInfo( IN PSDBCONTEXT pContext, IN LPCTSTR FullPath, IN DWORD dwLength OPTIONAL, // length (in characters) of FullPath string
IN HANDLE hFile OPTIONAL, // file handle
IN LPVOID pImageBase OPTIONAL, IN DWORD dwImageSize OPTIONAL, IN BOOL bNoCache ) /*++
Return: A pointer to the allocated FILEINFO structure.
Desc: Allocates the FILEINFO structure for the specified file. --*/ { PFILEINFO pFileInfo; SIZE_T sizeBase; SIZE_T size; DWORD nPathLen;
nPathLen = dwLength ? dwLength : (DWORD)_tcslen(FullPath);
sizeBase = sizeof(*pFileInfo) + (ATTRIBUTE_COUNT - 1) * sizeof(ATTRINFO); size = sizeBase + (nPathLen + 1) * sizeof(*FullPath);
pFileInfo = (PFILEINFO)SdbAlloc(size);
if (pFileInfo == NULL) { DBGPRINT((sdlError, "CreateFileInfo", "Failed to allocate %d bytes for FILEINFO structure.\n", size)); return NULL; }
RtlZeroMemory(pFileInfo, size);
pFileInfo->FilePath = (LPTSTR)((PBYTE)pFileInfo + sizeBase);
RtlCopyMemory(pFileInfo->FilePath, FullPath, nPathLen * sizeof(*FullPath));
pFileInfo->FilePath[nPathLen] = TEXT('\0');
pFileInfo->hFile = hFile; pFileInfo->pImageBase = pImageBase; pFileInfo->dwImageSize = dwImageSize;
//
// Now link it in if we use the cache.
//
if (!bNoCache) { pFileInfo->pNext = (PFILEINFO)pContext->pFileAttributeCache; pContext->pFileAttributeCache = (PVOID)pFileInfo; }
return pFileInfo; }
void SdbFreeFileInfo( IN PVOID pFileData // pointer returned from SdbpGetFileAttributes
) /*++
Return: void.
Desc: Self explanatory. Use this only after calling GetFileInfo with bNoCache set to TRUE. --*/ { PFILEINFO pFileInfo = (PFILEINFO)pFileData;
if (pFileInfo == NULL) { DBGPRINT((sdlError, "SdbFreeFileInfo", "Invalid parameter.\n")); return; }
if (pFileInfo->pVersionInfo != NULL) { SdbFree(pFileInfo->pVersionInfo); }
if (pFileInfo->pDescription16 != NULL) { SdbFree(pFileInfo->pDescription16); }
if (pFileInfo->pModuleName16 != NULL) { SdbFree(pFileInfo->pModuleName16); }
SdbFree(pFileInfo); }
void SdbpCleanupAttributeMgr( IN PSDBCONTEXT pContext // database context
) /*++
Return: void.
Desc: This function should be called afer we are done checking a given exe it performs cleanup tasks, such as: . unload dynamically linked dll (version.dll) . cleanup file cache --*/ { PFILEINFO pFileInfo = (PFILEINFO)pContext->pFileAttributeCache; PFILEINFO pNext;
while (pFileInfo != NULL) { pNext = pFileInfo->pNext; SdbFreeFileInfo(pFileInfo); pFileInfo = pNext; }
//
// Reset the cache pointer.
//
pContext->pFileAttributeCache = NULL; }
BOOL SdbpCheckAllAttributes( IN PSDBCONTEXT pContext, // pointer to the database channel
IN PDB pdb, // pointer to the Shim Database that we're checking against
IN TAGID tiMatch, // TAGID for a given file(exe) to be checked
IN PVOID pFileData // pointer returned from CheckFile
) /*++
Return: TRUE if all the file's attributes match the ones described in the database for this file, FALSE otherwise.
Desc: TBD --*/ { int i; TAG tAttrID; PVOID pAttribute; TAGID tiTemp; DWORD dwAttribute; ULONGLONG ullAttribute; BOOL bReturn = TRUE; // match by default
assert(tiMatch != TAGID_NULL);
if (pFileData == NULL) { //
// No file was passed in. This can happen if LOGIC="NOT" is used.
//
return FALSE; }
for (i = 0; i < ATTRIBUTE_COUNT && bReturn; ++i) {
tAttrID = g_rgAttributeTags[i]; tiTemp = SdbFindFirstTag(pdb, tiMatch, tAttrID);
if (tiTemp != TAGID_NULL) { pAttribute = NULL;
switch (GETTAGTYPE(tAttrID)) {
case TAG_TYPE_DWORD: dwAttribute = SdbReadDWORDTag(pdb, tiTemp, 0); pAttribute = &dwAttribute; break;
case TAG_TYPE_QWORD: ullAttribute = SdbReadQWORDTag(pdb, tiTemp, 0); pAttribute = &ullAttribute; break;
case TAG_TYPE_STRINGREF: pAttribute = SdbGetStringTagPtr(pdb, tiTemp); break; }
//
// Now check the attribute.
//
bReturn = SdbpCheckAttribute(pContext, pFileData, tAttrID, pAttribute);
//
// we bail out if !bReturn via the condition in FOR loop above
//
} }
return bReturn; }
//
// VERSION DATA
//
/*--
Search order is:
- Language neutral, Unicode (0x000004B0) - Language neutral, Windows-multilingual (0x000004e4) - US English, Unicode (0x040904B0) - US English, Windows-multilingual (0x040904E4)
If none of those exist, it's not likely we're going to get good matching info from what does exist.
--*/
LPTSTR SdbpQueryVersionString( IN PSDBCONTEXT pContext, // the database channel
IN PVOID pVersionData, // Version data buffer
IN PLANGANDCODEPAGE pTranslations, IN DWORD TranslationCount, IN LPCTSTR szString // String to search for; see VerQueryValue in MSDN
) /*++
Return: The pointer to the string if found, NULL if not.
Desc: Gets a pointer to a particular string in the StringFileInfo section of a version resource. Lookup is performed for known english-language resources followed up by a lookup in the available translations section (if such was found) --*/ { TCHAR szTemp[128]; LPTSTR szReturn = NULL; int i;
static DWORD adwLangs[] = {0x000004B0, 0x000004E4, 0x040904B0, 0x040904E4};
assert(pVersionData && szString);
for (i = 0; i < ARRAYSIZE(adwLangs); ++i) { UINT unLen;
StringCchPrintf(szTemp, CHARCOUNT(szTemp), _T("\\StringFileInfo\\%08X\\%s"), adwLangs[i], szString);
if (pContext->pfnVerQueryValue(pVersionData, szTemp, (PVOID*)&szReturn, &unLen)) { return szReturn; } }
if (pTranslations != NULL) { for (i = 0; i < (int)TranslationCount; ++i, ++pTranslations) { UINT unLen;
StringCchPrintf(szTemp, CHARCOUNT(szTemp), _T("\\StringFileInfo\\%04X%04X\\%s"), (DWORD)pTranslations->wLanguage, (DWORD)pTranslations->wCodePage, szString);
if (pContext->pfnVerQueryValue(pVersionData, szTemp, (PVOID*)&szReturn, &unLen)) { return szReturn; } } }
return NULL; // none found
}
BOOL SdbpGetModuleType( OUT LPDWORD lpdwModuleType, IN PIMAGEFILEDATA pImageData ) /*++
Return: TRUE on success, FALSE otherwise.
Desc: Gets a pointer to a particular string in the StringFileInfo section of a version resource. --*/ { PIMAGE_DOS_HEADER pDosHeader; DWORD dwModuleType = MT_UNKNOWN_MODULE; LPBYTE lpSignature; DWORD OffsetNew;
pDosHeader = (PIMAGE_DOS_HEADER)pImageData->pBase; if (pDosHeader == NULL || pDosHeader == (PIMAGE_DOS_HEADER)-1) { return FALSE; }
//
// Check size and read signature.
//
if (pImageData->ViewSize < sizeof(*pDosHeader) || pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { return FALSE; }
//
// Assume DOS module.
//
dwModuleType = MT_DOS_MODULE; OffsetNew = (DWORD)pDosHeader->e_lfanew;
//
// New header signature. Check offset.
//
if (pImageData->ViewSize < OffsetNew + sizeof(DWORD)) { return FALSE; }
lpSignature = ((LPBYTE)pImageData->pBase + OffsetNew);
if (IMAGE_NT_SIGNATURE == *(LPDWORD)lpSignature) { dwModuleType = MT_W32_MODULE; } else if (IMAGE_OS2_SIGNATURE == *(PWORD)lpSignature) { dwModuleType = MT_W16_MODULE; }
if (lpdwModuleType != NULL) { *lpdwModuleType = dwModuleType; }
return TRUE; }
BOOL SdbpGetImageNTHeader( OUT PIMAGE_NT_HEADERS* ppHeader, IN PIMAGEFILEDATA pImageData ) /*++
Return: TRUE on success, FALSE otherwise.
Desc: Gets a pointer to the IMAGE_NT_HEADERS. --*/ { PIMAGE_DOS_HEADER pDosHeader; PIMAGE_NT_HEADERS pNtHeaders = NULL; DWORD ModuleType;
if (!SdbpGetModuleType(&ModuleType, pImageData)) { return FALSE; }
if (ModuleType != MT_W32_MODULE) { return FALSE; }
//
// Header is valid.
//
pDosHeader = (PIMAGE_DOS_HEADER)pImageData->pBase; pNtHeaders = (PIMAGE_NT_HEADERS)((LPBYTE)pImageData->pBase + pDosHeader->e_lfanew);
if (pImageData->ViewSize >= pDosHeader->e_lfanew + sizeof(*pNtHeaders)) { // not too short?
*ppHeader = pNtHeaders; return TRUE; }
return FALSE; }
BOOL SdbpGetModulePECheckSum( OUT PULONG pChecksum, OUT LPDWORD pdwLinkerVersion, OUT LPDWORD pdwLinkDate, IN PIMAGEFILEDATA pImageData ) /*++
Return: TRUE on success, FALSE otherwise.
Desc: Gets the checksum from the PE headers. --*/ { PIMAGE_NT_HEADERS pNtHeader; PIMAGE_DOS_HEADER pDosHeader; ULONG ulChecksum = 0;
if (!SdbpGetImageNTHeader(&pNtHeader, pImageData)) { DBGPRINT((sdlError, "SdbpGetModulePECheckSum", "Failed to get Image NT header.\n")); return FALSE; }
pDosHeader = (PIMAGE_DOS_HEADER)pImageData->pBase;
//
// Fill in the linker version (as it used to calculated in ntuser).
//
*pdwLinkerVersion = (pNtHeader->OptionalHeader.MinorImageVersion & 0xFF) + ((pNtHeader->OptionalHeader.MajorImageVersion & 0xFF) << 16);
*pdwLinkDate = pNtHeader->FileHeader.TimeDateStamp;
switch (pNtHeader->OptionalHeader.Magic) { case IMAGE_NT_OPTIONAL_HDR32_MAGIC: if (pImageData->ViewSize >= pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS32)) { ulChecksum = ((PIMAGE_NT_HEADERS32)pNtHeader)->OptionalHeader.CheckSum; *pChecksum = ulChecksum; return TRUE; } break;
case IMAGE_NT_OPTIONAL_HDR64_MAGIC: //
// Do an additional check.
//
if (pImageData->ViewSize >= pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS64)) { ulChecksum = ((PIMAGE_NT_HEADERS64)pNtHeader)->OptionalHeader.CheckSum; *pChecksum = ulChecksum; return TRUE; } break;
default: //
// Unknown image type ?
//
DBGPRINT((sdlError, "SdbpGetModulePECheckSum", "Bad image type 0x%x\n", pNtHeader->OptionalHeader.Magic)); *pChecksum = 0; break; }
return FALSE; }
#define CHECKSUM_SIZE 4096
#define CHECKSUM_START 512
BOOL SdbpGetFileChecksum( OUT PULONG pChecksum, IN PIMAGEFILEDATA pImageData ) /*++
Return: TRUE on success, FALSE otherwise.
Desc: Calculates a checksum for the file. --*/ { ULONG size = CHECKSUM_SIZE; ULONG StartAddress = CHECKSUM_START; ULONG ulChecksum = 0; LPDWORD lpdw; int i;
if ((SIZE_T)pImageData->FileSize < (SIZE_T)size) { StartAddress = 0; size = (ULONG)pImageData->FileSize; // this is safe (size is rather small)
} else if ((SIZE_T)(size + StartAddress) > (SIZE_T)pImageData->FileSize) { //
// The cast here is safe (FileSize is small)
//
StartAddress = (ULONG)(pImageData->FileSize - size); }
if (size >= sizeof(DWORD)) {
ULONG ulCarry;
lpdw = (LPDWORD)((LPBYTE)pImageData->pBase + StartAddress);
for (i = 0; i < (INT)(size/sizeof(DWORD)); ++i) {
if (PtrToUlong(lpdw) & 0x3) { // alignment fault fixup
ulChecksum += *((DWORD UNALIGNED*)lpdw); lpdw++; } else { ulChecksum += *lpdw++; }
ulCarry = ulChecksum & 1; ulChecksum >>= 1;
if (ulCarry) { ulChecksum |= 0x80000000; } } }
*pChecksum = ulChecksum; return TRUE; }
BOOL SdbpCheckVersion( IN ULONGLONG qwDBFileVer, IN ULONGLONG qwBinFileVer ) /*++
Return: TRUE if the versions match, FALSE if they don't.
Desc: Checks a binary version from the db against the version from the file, including allowing for wildcards, which are represented in the DB by using FFFF for that word-sized portion of the version. --*/ { WORD wDBSegment, wFileSegment; int i;
for (i = 3; i >= 0; --i) { //
// Get the appropriate word out of the QWORD
//
wDBSegment = (WORD)(qwDBFileVer >> (16 * i)); wFileSegment = (WORD)(qwBinFileVer >> (16 * i));
//
// The DB segment may be 0xFFFF, in which case it matches on
// everything.
//
if (wDBSegment != wFileSegment && wDBSegment != 0xFFFF) { return FALSE; } }
return TRUE; }
BOOL SdbpCheckUptoVersion( IN ULONGLONG qwDBFileVer, IN ULONGLONG qwBinFileVer ) /*++
Return: TRUE if the versions match, FALSE if they don't.
Desc: Checks a binary version from the db against the version from the file, including allowing for wildcards, which are represented in the DB by using FFFF for that word-sized portion of the version. --*/ { WORD wDBSegment, wFileSegment; BOOL bReturn = TRUE; int i;
for (i = 3; i >= 0; --i) { //
// Get the appropriate word out of the QWORD
//
wDBSegment = (WORD)(qwDBFileVer >> (16 * i)); wFileSegment = (WORD)(qwBinFileVer >> (16 * i));
if (wDBSegment == wFileSegment || wDBSegment == 0xFFFF) { continue; }
//
// At this point we know that the two values don't match
// the wFileSegment has to be less than wDBSegment to satisfy this
// test - so set bReturn and exit
//
bReturn = (wDBSegment > wFileSegment); break;
}
return bReturn; }
#ifndef KERNEL_MODE
BOOL SdbFormatAttribute( IN PATTRINFO pAttrInfo, // pointer to the attribute information
OUT LPTSTR pchBuffer, // receives XML corresponding to the given attribute
IN DWORD dwBufferSize // size in wide characters of the buffer pchBuffer
) /*++
Return: FALSE if the buffer is too small or attribute not available.
Desc: TBD. --*/ { size_t cchRemaining; TCHAR* pszEnd = NULL; HRESULT hr;
#if defined(WIN32A_MODE) || defined(WIN32U_MODE)
struct tm* ptm; time_t tt; #else
LARGE_INTEGER liTime; TIME_FIELDS TimeFields; #endif
if (!(pAttrInfo->dwFlags & ATTRIBUTE_AVAILABLE)) { return FALSE; }
hr = StringCchPrintfEx(pchBuffer, (int)dwBufferSize, &pszEnd, &cchRemaining, 0, TEXT("%s="), SdbTagToString(pAttrInfo->tAttrID));
if (FAILED(hr)) { DBGPRINT((sdlError, "SdbFormatAttribute", "Buffer is too small to accomodate \"%s\"\n", SdbTagToString(pAttrInfo->tAttrID))); return FALSE; }
switch (pAttrInfo->tAttrID) { case TAG_BIN_PRODUCT_VERSION: case TAG_BIN_FILE_VERSION: case TAG_UPTO_BIN_PRODUCT_VERSION: case TAG_UPTO_BIN_FILE_VERSION: hr = StringCchPrintf(pszEnd, cchRemaining, TEXT("\"%d.%d.%d.%d\""), (WORD)(pAttrInfo->ullAttr >> 48), (WORD)(pAttrInfo->ullAttr >> 32), (WORD)(pAttrInfo->ullAttr >> 16), (WORD)(pAttrInfo->ullAttr)); break;
case TAG_MODULE_TYPE: hr = StringCchPrintf(pszEnd, cchRemaining, TEXT("\"%s\""), SdbpModuleTypeToString(pAttrInfo->dwAttr)); break;
case TAG_VER_LANGUAGE: //
// language is a dword attribute that we shall make a string out of
//
{ TCHAR szLanguageName[MAX_PATH]; DWORD dwLength;
szLanguageName[0] = TEXT('\0');
dwLength = VerLanguageName((LANGID)pAttrInfo->dwAttr, szLanguageName, CHARCOUNT(szLanguageName));
if (dwLength) { hr = StringCchPrintf(pszEnd, cchRemaining, TEXT("\"%s [0x%x]\""), szLanguageName, pAttrInfo->dwAttr); } else { hr = StringCchPrintf(pszEnd, cchRemaining, TEXT("\"0x%x\""), pAttrInfo->dwAttr); }
} break;
case TAG_LINK_DATE: case TAG_UPTO_LINK_DATE:
#if defined(WIN32A_MODE) || defined(WIN32U_MODE)
tt = (time_t) pAttrInfo->dwAttr; ptm = gmtime(&tt); if (ptm) { hr = StringCchPrintf(pszEnd, cchRemaining, TEXT("\"%02d/%02d/%02d %02d:%02d:%02d\""), ptm->tm_mon+1, ptm->tm_mday, ptm->tm_year+1900, ptm->tm_hour, ptm->tm_min, ptm->tm_sec); } #else
RtlSecondsSince1970ToTime((ULONG)pAttrInfo->dwAttr, &liTime); RtlTimeToTimeFields(&liTime, &TimeFields); hr = StringCchPrintf(pszEnd, cchRemaining, TEXT("\"%02d/%02d/%02d %02d:%02d:%02d\""), TimeFields.Month, TimeFields.Day, TimeFields.Year, TimeFields.Hour, TimeFields.Minute, TimeFields.Second);
#endif
break;
case TAG_SIZE: hr = StringCchPrintf(pszEnd, cchRemaining, TEXT("\"%ld\""), pAttrInfo->dwAttr); break;
default:
switch (GETTAGTYPE(pAttrInfo->tAttrID)) { case TAG_TYPE_DWORD: hr = StringCchPrintf(pszEnd, cchRemaining, TEXT("\"0x%lX\""), pAttrInfo->dwAttr); break;
case TAG_TYPE_QWORD: //
// This is an unidentified QWORD attribute
//
DBGPRINT((sdlError, "SdbFormatAttribute", "Unexpected qword attribute found\n")); hr = StringCchPrintf(pszEnd, cchRemaining, TEXT("\"0x%I64X\""), pAttrInfo->ullAttr); break;
case TAG_TYPE_STRINGREF: if (cchRemaining < 3) { return FALSE; // not enough room even for " ?
}
*pszEnd++ = TEXT('\"'); cchRemaining--;
if (!SdbpSanitizeXML(pszEnd, (int)cchRemaining, pAttrInfo->lpAttr)) { // handle error please
return FALSE; }
//
// Once done with this, sanitize further
//
if (!SafeNCat(pszEnd, (int)cchRemaining, TEXT("\""), -1)) { return FALSE; }
hr = S_OK; break; } }
return (hr == S_OK); // evaluates to TRUE when we successfully printed the value into the buffer
}
BOOL SdbpGetVersionAttributes( IN PSDBCONTEXT pContext, OUT PFILEINFO pFileInfo ) /*++
Return: TRUE on success, FALSE otherwise.
Desc: This function retrieves all of the Version-related attributes Imports apis from version.dll if called for the first time --*/ { DWORD dwNull = 0; VS_FIXEDFILEINFO* pFixedInfo = NULL; // fixed info ptr
UINT FixedInfoSize = 0; PVOID pBuffer = NULL; // version data buffer
DWORD dwBufferSize; // version data buffer size
int i;
#ifdef NT_MODE
//
// check to see whether we need to run NT routine
//
if (pFileInfo->hFile != INVALID_HANDLE_VALUE || pFileInfo->pImageBase != NULL) {
//
// not an error -- this case is handled in header attributes
//
goto err; }
#endif // NT_MODE
if (pContext == NULL) { //
// Special case when it's called with null context.
// In this case we use an internal structure allocated from the stack.
//
STACK_ALLOC(pContext, sizeof(SDBCONTEXT));
if (pContext == NULL) { DBGPRINT((sdlError, "SdbpGetVersionAttributes", "Failed to allocate %d bytes from stack\n", sizeof(SDBCONTEXT))); goto err; }
RtlZeroMemory(pContext, sizeof(SDBCONTEXT)); }
#ifdef WIN32A_MODE
pContext->pfnGetFileVersionInfoSize = GetFileVersionInfoSizeA; pContext->pfnGetFileVersionInfo = GetFileVersionInfoA; pContext->pfnVerQueryValue = VerQueryValueA;
#else
pContext->pfnGetFileVersionInfoSize = GetFileVersionInfoSizeW; pContext->pfnGetFileVersionInfo = GetFileVersionInfoW; pContext->pfnVerQueryValue = VerQueryValueW;
#endif
dwBufferSize = pContext->pfnGetFileVersionInfoSize(pFileInfo->FilePath, &dwNull);
if (dwBufferSize == 0) { DBGPRINT((sdlInfo, "SdbpGetVersionAttributes", "No version info.\n")); //
// We have failed to obtain version attributes
//
goto err; }
pBuffer = SdbAlloc(dwBufferSize + VERSIONINFO_BUFFER_PAD);
if (pBuffer == NULL) { DBGPRINT((sdlError, "SdbpGetVersionAttributes", "Failed to allocate %d bytes for version info buffer.\n", dwBufferSize + VERSIONINFO_BUFFER_PAD)); goto err; }
if (!pContext->pfnGetFileVersionInfo(pFileInfo->FilePath, 0, dwBufferSize, pBuffer)) { DBGPRINT((sdlError, "SdbpGetVersionAttributes", "Failed to retrieve version info for file \"%s\"", pFileInfo->FilePath)); goto err; }
if (!pContext->pfnVerQueryValue(pBuffer, TEXT("\\"), (PVOID*)&pFixedInfo, &FixedInfoSize)) { DBGPRINT((sdlError, "SdbpGetVersionAttributes", "Failed to query for fixed version info size for \"%s\"\n", pFileInfo->FilePath)); goto err; }
//
// Retrieve string attributes.
//
SdbpQueryStringVersionInformation(pContext, pFileInfo, pBuffer);
//
// Now retrieve other attributes.
//
if (FixedInfoSize >= sizeof(VS_FIXEDFILEINFO)) {
SdbpQueryBinVersionInformation(pContext, pFileInfo, pFixedInfo);
} else { //
// No other version attributes are available. Set the rest of the
// attributes as being not available.
//
for (i = 0; i < ARRAYSIZE(g_rgBinVerTags); ++i) { SdbpSetAttribute(pFileInfo, g_rgBinVerTags[i], NULL); } }
//
// Store the pointer to the version info buffer.
//
pFileInfo->pVersionInfo = pBuffer; return TRUE;
err: //
// We are here ONLY when we failed to obtain version info
// through apis -- regardless of the state of other value we might have
// obtained
if (pBuffer != NULL) { SdbFree(pBuffer); }
for (i = 0; i < ARRAYSIZE(g_rgBinVerTags); ++i) { SdbpSetAttribute(pFileInfo, g_rgBinVerTags[i], NULL); }
for (i = 0; i < ARRAYSIZE(g_rgVerStrings); ++i) { SdbpSetAttribute(pFileInfo, g_rgVerStrings[i].tTag, NULL); }
return FALSE; }
BOOL SdbpGetFileDirectoryAttributes( OUT PFILEINFO pFileInfo ) /*++
Return: TRUE on success, FALSE otherwise.
Desc: This function retrieves the file directory attributes for the specified file. --*/ { BOOL bSuccess = FALSE; FILEDIRECTORYATTRIBUTES fda; int i;
bSuccess = SdbpQueryFileDirectoryAttributes(pFileInfo->FilePath, &fda);
if (!bSuccess) { DBGPRINT((sdlInfo, "SdbpGetFileDirectoryAttributes", "No file directory attributes available.\n")); goto Done; }
if (fda.dwFlags & FDA_FILESIZE) { assert(fda.dwFileSizeHigh == 0); SdbpSetAttribute(pFileInfo, TAG_SIZE, &fda.dwFileSizeLow); }
Done:
if (!bSuccess) { for (i = 0; g_rgDirectoryTags[i] != 0; ++i) { SdbpSetAttribute(pFileInfo, g_rgDirectoryTags[i], NULL); } }
return bSuccess; }
BOOL SdbGetFileAttributes( IN LPCTSTR lpwszFileName, // the file for which attributes are requested
OUT PATTRINFO* ppAttrInfo, // receives allocated pointer to the attribute array
OUT LPDWORD lpdwAttrCount // receives the number of entries in an attributes table
) /*++
Return: FALSE if the file does not exist or some other severe error had occured. Note that each attribute has it's own flag ATTRIBUTE_AVAILABLE that allows for checking whether an attribute has been retrieved successfully Not all attributes might be present for all files.
Desc: TBD --*/ { PFILEINFO pFileInfo; BOOL bReturn;
//
// The call below allocates the structure, context is not used
//
pFileInfo = SdbGetFileInfo(NULL, lpwszFileName, INVALID_HANDLE_VALUE, NULL, 0, TRUE);
if (pFileInfo == NULL) { DBGPRINT((sdlError, "SdbGetFileAttributes", "Error retrieving FILEINFO structure\n")); return FALSE; }
//
// The three calls below, even when fail do not produce a fatal condition
// as the exe may not have all the attributes available.
//
bReturn = SdbpGetFileDirectoryAttributes(pFileInfo); if (!bReturn) { DBGPRINT((sdlInfo, "SdbGetFileAttributes", "Error retrieving directory attributes\n")); }
bReturn = SdbpGetVersionAttributes(NULL, pFileInfo); if (!bReturn) { DBGPRINT((sdlInfo, "SdbGetFileAttributes", "Error retrieving version attributes\n")); }
bReturn = SdbpGetHeaderAttributes(NULL, pFileInfo); if (!bReturn) { DBGPRINT((sdlInfo, "SdbGetFileAttributes", "Error retrieving header attributes\n")); }
pFileInfo->dwMagic = FILEINFO_MAGIC;
//
// Now that we are done, put the return pointer.
//
if (lpdwAttrCount != NULL) { *lpdwAttrCount = ATTRIBUTE_COUNT; }
if (ppAttrInfo != NULL) {
//
// Return the pointer to the attribute info itself.
// It is the same pointer we expect to get in a complimentary
// call to SdbFreeFileInfo.
//
*ppAttrInfo = &pFileInfo->Attributes[0];
} else {
//
// Pointer is not needed. Release the memory.
//
SdbFreeFileInfo(pFileInfo); }
return TRUE; }
BOOL SdbFreeFileAttributes( IN PATTRINFO pFileAttributes // pointer returned by SdbGetFileAttributes
) /*++
Return: FALSE if a wrong pointer was passed in (not the one from SdbGetFileAttributes).
Desc: Self explanatory. --*/ { PFILEINFO pFileInfo;
//
// We are assuming the pointer that was passed in points inside of a
// larger structure FILEINFO. To verify that we step back a pre-determined number
// of bytes (calculated below as an offset) and check the "magic" signature.
//
pFileInfo = (PFILEINFO)((PBYTE)pFileAttributes - OFFSETOF(FILEINFO, Attributes));
if (pFileInfo->dwMagic != FILEINFO_MAGIC) { DBGPRINT((sdlError, "SdbFreeFileAttributes", "Bad pointer to attributes.\n")); return FALSE; }
SdbFreeFileInfo(pFileInfo);
return TRUE; }
BOOL SdbpQuery16BitDescription( OUT LPSTR szBuffer, // min length 256 chars !
IN PIMAGEFILEDATA pImageData ) /*++
Return: TRUE on success, FALSE otherwise.
Desc: Gets the 16 bit description for a DOS executable. --*/ { PIMAGE_DOS_HEADER pDosHeader; PIMAGE_OS2_HEADER pNEHeader; PBYTE pSize; DWORD ModuleType;
if (!SdbpGetModuleType(&ModuleType, pImageData)) { return FALSE; }
if (ModuleType != MT_W16_MODULE) { return FALSE; }
pDosHeader = (PIMAGE_DOS_HEADER)pImageData->pBase; pNEHeader = (PIMAGE_OS2_HEADER)((PBYTE)pImageData->pBase + pDosHeader->e_lfanew);
//
// Now we know that pNEHeader is valid, just have to make sure that
// the next offset is valid as well, make a check against file size.
//
if (pImageData->ViewSize < pDosHeader->e_lfanew + sizeof(*pNEHeader)) { return FALSE; }
if (pImageData->ViewSize < pNEHeader->ne_nrestab + sizeof(*pSize)) { return FALSE; }
pSize = (PBYTE)((PBYTE)pImageData->pBase + pNEHeader->ne_nrestab);
if (*pSize == 0) { return FALSE; }
//
// Now check for the string size.
//
if (pImageData->ViewSize < pNEHeader->ne_nrestab + sizeof(*pSize) + *pSize) { return FALSE; }
RtlCopyMemory(szBuffer, pSize + 1, *pSize); szBuffer[*pSize] = '\0';
return TRUE; }
BOOL SdbpQuery16BitModuleName( OUT LPSTR szBuffer, IN PIMAGEFILEDATA pImageData ) { PIMAGE_DOS_HEADER pDosHeader; PIMAGE_OS2_HEADER pNEHeader; PBYTE pSize; DWORD ModuleType;
if (!SdbpGetModuleType(&ModuleType, pImageData)) { return FALSE; }
if (ModuleType != MT_W16_MODULE) { return FALSE; }
pDosHeader = (PIMAGE_DOS_HEADER)pImageData->pBase; pNEHeader = (PIMAGE_OS2_HEADER)((PBYTE)pImageData->pBase + pDosHeader->e_lfanew);
//
// Now we know that pNEHeader is valid, just have to make sure that
// the next offset is valid as well, make a check against file size.
//
if (pImageData->ViewSize < pDosHeader->e_lfanew + sizeof(*pNEHeader)) { return FALSE; }
if (pImageData->ViewSize < pNEHeader->ne_restab + sizeof(*pSize)) { return FALSE; }
pSize = (PBYTE)((PBYTE)pImageData->pBase + pDosHeader->e_lfanew + pNEHeader->ne_restab);
if (*pSize == 0) { return FALSE; }
//
// Now check for the string size.
//
if (pImageData->ViewSize < pDosHeader->e_lfanew + pNEHeader->ne_restab + sizeof(*pSize) + *pSize) {
return FALSE; }
RtlCopyMemory(szBuffer, pSize + 1, *pSize); szBuffer[*pSize] = '\0';
return TRUE; }
#endif // KERNEL_MODE
|