WindowsXP-SP1/windows/appcompat/sdbapi/attributes.c
2020-09-30 16:53:49 +02:00

2177 lines
63 KiB
C

/*++
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_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;
DWORD 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);
}
#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;
HANDLE hFile;
ULONG ulPEChecksum = 0;
ULONG ulChecksum = 0;
DWORD dwModuleType = 0;
UNICODE_STRING ModuleDescription;
DWORD dwLinkerVer;
DWORD dwLinkDate;
BOOL bReturn = FALSE;
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;
}
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) {
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)));
}
break;
case TAG_UPTO_BIN_PRODUCT_VERSION:
case TAG_UPTO_BIN_FILE_VERSION:
bReturn = SdbpCheckUptoVersion(*(ULONGLONG*)pAttribute, pAttrInfo->ullAttr);
if (!bReturn) {
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)));
}
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 * 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;
_stprintf(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;
_stprintf(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.
--*/
{
int nchBuffer = (int)dwBufferSize;
int nch;
TCHAR lpszAttr[MAX_PATH];
#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;
}
nch = _sntprintf(pchBuffer, nchBuffer, TEXT("%s="), SdbTagToString(pAttrInfo->tAttrID));
if (nch < 0) {
DBGPRINT((sdlError,
"SdbFormatAttribute",
"Buffer is too small to accomodate \"%s\"\n",
SdbTagToString(pAttrInfo->tAttrID)));
return FALSE;
}
nchBuffer -= nch; // we advance the pointer past the "name="
pchBuffer += nch;
nch = -1;
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:
nch = _sntprintf(pchBuffer, nchBuffer, 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:
nch = _sntprintf(pchBuffer, nchBuffer, 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) {
nch = _sntprintf(pchBuffer, nchBuffer, TEXT("\"%s [0x%x]\""),
szLanguageName, pAttrInfo->dwAttr);
} else {
nch = _sntprintf(pchBuffer, nchBuffer, 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) {
nch = _sntprintf(pchBuffer, nchBuffer, 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);
nch = _sntprintf(pchBuffer, nchBuffer, TEXT("\"%02d/%02d/%02d %02d:%02d:%02d\""),
TimeFields.Month,
TimeFields.Day,
TimeFields.Year,
TimeFields.Hour,
TimeFields.Minute,
TimeFields.Second);
#endif
break;
case TAG_SIZE:
nch = _sntprintf(pchBuffer, nchBuffer, TEXT("\"%ld\""), pAttrInfo->dwAttr);
break;
default:
switch (GETTAGTYPE(pAttrInfo->tAttrID)) {
case TAG_TYPE_DWORD:
nch = _sntprintf(pchBuffer, nchBuffer, TEXT("\"0x%lX\""),
pAttrInfo->dwAttr);
break;
case TAG_TYPE_QWORD:
//
// This is an unidentified QWORD attribute
//
DBGPRINT((sdlError, "SdbFormatAttribute", "Unexpected qword attribute found\n"));
nch = _sntprintf(pchBuffer, nchBuffer, TEXT("\"0x%I64X\""), pAttrInfo->ullAttr);
break;
case TAG_TYPE_STRINGREF:
if (nchBuffer < 3) {
return FALSE; // not enough room even for " ?
}
*pchBuffer++ = TEXT('\"');
nchBuffer--;
if (!SdbpSanitizeXML(pchBuffer, nchBuffer, pAttrInfo->lpAttr)) {
// handle error please
return FALSE;
}
//
// Once done with this, sanitize further
//
if (!SafeNCat(pchBuffer, nchBuffer, TEXT("\""), -1)) {
return FALSE;
}
nch = 0;
break;
}
}
return (nch >= 0); // 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
--*/
{
BOOL bSuccess;
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