//////////////////////////////////////////////////////////////////////////////////// // // File: registry.cpp // // History: 21-Mar-00 markder Created. // 13-Dec-00 markder Renamed from appshelp.cpp // // Desc: This file contains all code needed to produce matching info registry // files and setup files (INX) for the Windows 2000 (RTM) shim mechanism. // //////////////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "registry.h" //////////////////////////////////////////////////////////////////////////////////// // // Func: DumpString, DumpDword, DumpBinVersion, InsertString // // Desc: Helper functions for CreateMessageBlob. // void DumpString( DWORD dwId, PBYTE* ppBlob, LONG* pnTotalBytes, CString& csString ) { DWORD dwLen; **(DWORD**)ppBlob = dwId; *ppBlob += sizeof(DWORD); dwLen = csString.GetLength(); **(DWORD**)ppBlob = ( dwLen + 1) * sizeof(WCHAR); *ppBlob += sizeof(DWORD); CopyMemory(*ppBlob, T2W((LPTSTR) (LPCTSTR) csString), (dwLen + 1) * sizeof(WCHAR)); *ppBlob += (dwLen + 1) * sizeof(WCHAR); *pnTotalBytes += ((dwLen + 1) * sizeof(WCHAR) + 2 * sizeof(DWORD)); } void DumpDword( DWORD dwId, PBYTE* ppBlob, LONG* pnTotalBytes, DWORD dwVal ) { **(DWORD**)ppBlob = dwId; *ppBlob += sizeof(DWORD); **(DWORD**)ppBlob = sizeof(DWORD); *ppBlob += sizeof(DWORD); **(DWORD**)ppBlob = dwVal; *ppBlob += sizeof(DWORD); *pnTotalBytes += 3 * sizeof(DWORD); } void DumpBinVersion(DWORD dwId, PBYTE* ppBlob, LONG* pnTotalBytes, ULONGLONG ullVersion) { ULONGLONG ullMask = 0; ULONGLONG ullVer = 0; WORD wVerPart = 0; LONG j; PBYTE pBlob = *ppBlob; for( j = 0; j < 4; j++ ) { wVerPart = (WORD) (ullVersion >> (j*16)); if (wVerPart != 0xFFFF) { ullVer += ((ULONGLONG)wVerPart) << (j*16); ullMask += ((ULONGLONG) 0xFFFF) << (j*16); } } // // id // *(DWORD*)pBlob = dwId; pBlob += sizeof(DWORD); // size *(DWORD*)pBlob = 2 * sizeof(ULONGLONG); pBlob += sizeof(DWORD); // version CopyMemory(pBlob, &ullVer, sizeof(ULONGLONG)); pBlob += sizeof(ULONGLONG); // mask CopyMemory(pBlob, &ullMask, sizeof(ULONGLONG)); pBlob += sizeof(ULONGLONG); *pnTotalBytes += (2 * sizeof(ULONGLONG) + 2 * sizeof(DWORD)); *ppBlob = pBlob; } void InsertString( CString* pcs, DWORD dwIndex, CString csInsertedString ) { *pcs = pcs->Left( dwIndex ) + csInsertedString + pcs->Right( pcs->GetLength() - dwIndex ); } BOOL WriteStringToFile( HANDLE hFile, CString& csString) { CHAR szBuffer[1024]; DWORD dwConvBufReqSize; DWORD dwConvBufSize = sizeof(szBuffer); BOOL b; // this will be set if default char is used, we make no use of this LPSTR szConvBuf = szBuffer; BOOL bAllocated = FALSE; BOOL bSuccess; DWORD dwBytesWritten; dwConvBufReqSize = WideCharToMultiByte(CP_ACP, 0, csString, -1, NULL, NULL, 0, &b); if (dwConvBufReqSize > sizeof(szBuffer)) { szConvBuf = (LPSTR) new CHAR [dwConvBufReqSize]; dwConvBufSize = dwConvBufReqSize; bAllocated = TRUE; } WideCharToMultiByte(CP_ACP, 0, csString, -1, szConvBuf, dwConvBufSize, 0, &b); bSuccess = WriteFile( hFile, szConvBuf, dwConvBufReqSize - 1, &dwBytesWritten, NULL); if (bAllocated) { delete [] szConvBuf; } return bSuccess; } //////////////////////////////////////////////////////////////////////////////////// // // Func: FreeRegistryBlob, CreateRegistryBlob // // Desc: Creates a binary blob in the format of Windows 2000's // Message registry keys. // void FreeRegistryBlob( PBYTE pBlob ) { delete pBlob; } BOOL CreateRegistryBlob( SdbExe* pExe, PBYTE* ppBlob, DWORD* pdwSize, DWORD dwMessageID = 0, // these two are optional DWORD dwBlobType = 6) { USES_CONVERSION; BOOL bSuccess = FALSE; PBYTE pBlob = (PBYTE) new BYTE[4096]; PBYTE pStartOfBlob = pBlob; DWORD dwBufSize = 4096; DWORD dwReqBufSize = 0; LONG nTotalBytes = 0; LONG i, j; LONG nBytes; SdbMatchingFile* pMFile; FILETIME FileTime; CString* pcsFilename; ULONGLONG ullMask = 0; WORD wVerPart = 0; ULONGLONG ullVer = 0; *pdwSize = 0; // Prolog *((DWORD*)pBlob + 0) = 3 * sizeof(DWORD); // message id *((DWORD*)pBlob + 1) = dwMessageID; // type is not shim anymore *((DWORD*)pBlob + 2) = dwBlobType; // shim type pBlob += 3 * sizeof(DWORD); nTotalBytes += 3 * sizeof(DWORD); for( i = 0; i < pExe->m_rgMatchingFiles.GetSize(); i++ ) { pMFile = (SdbMatchingFile *) pExe->m_rgMatchingFiles[i]; if( pMFile->m_csName == _T("*") ) { pcsFilename = &(pExe->m_csName); } else { pcsFilename = &(pMFile->m_csName); } DumpString( VTID_REQFILE, &pBlob, &nTotalBytes, *pcsFilename ); if( pMFile->m_dwMask & SDB_MATCHINGINFO_SIZE ) DumpDword( VTID_FILESIZE, &pBlob, &nTotalBytes, pMFile->m_dwSize ); if( pMFile->m_dwMask & SDB_MATCHINGINFO_CHECKSUM ) DumpDword( VTID_CHECKSUM, &pBlob, &nTotalBytes, pMFile->m_dwChecksum ); if( pMFile->m_dwMask & SDB_MATCHINGINFO_COMPANY_NAME ) DumpString( VTID_COMPANYNAME, &pBlob, &nTotalBytes, pMFile->m_csCompanyName ); if( pMFile->m_dwMask & SDB_MATCHINGINFO_PRODUCT_NAME ) DumpString( VTID_PRODUCTNAME, &pBlob, &nTotalBytes, pMFile->m_csProductName ); if( pMFile->m_dwMask & SDB_MATCHINGINFO_PRODUCT_VERSION ) DumpString( VTID_PRODUCTVERSION, &pBlob, &nTotalBytes, pMFile->m_csProductVersion ); if( pMFile->m_dwMask & SDB_MATCHINGINFO_FILE_DESCRIPTION ) DumpString( VTID_FILEDESCRIPTION, &pBlob, &nTotalBytes, pMFile->m_csFileDescription ); if( pMFile->m_dwMask & SDB_MATCHINGINFO_BIN_FILE_VERSION ) DumpBinVersion(VTID_BINFILEVER, &pBlob, &nTotalBytes, pMFile->m_ullBinFileVersion); if( pMFile->m_dwMask & SDB_MATCHINGINFO_BIN_PRODUCT_VERSION ) DumpBinVersion(VTID_BINPRODUCTVER, &pBlob, &nTotalBytes, pMFile->m_ullBinProductVersion); if (pMFile->m_dwMask & SDB_MATCHINGINFO_MODULE_TYPE) DumpDword( VTID_EXETYPE, &pBlob, &nTotalBytes, pMFile->m_dwModuleType ); if (pMFile->m_dwMask & SDB_MATCHINGINFO_VERFILEDATEHI) DumpDword( VTID_FILEDATEHI, &pBlob, &nTotalBytes, pMFile->m_dwFileDateMS ); if (pMFile->m_dwMask & SDB_MATCHINGINFO_VERFILEDATELO) DumpDword( VTID_FILEDATELO, &pBlob, &nTotalBytes, pMFile->m_dwFileDateLS ); if (pMFile->m_dwMask & SDB_MATCHINGINFO_VERFILEOS) DumpDword( VTID_FILEVEROS, &pBlob, &nTotalBytes, pMFile->m_dwFileOS ); if (pMFile->m_dwMask & SDB_MATCHINGINFO_VERFILETYPE) DumpDword( VTID_FILEVERTYPE, &pBlob, &nTotalBytes, pMFile->m_dwFileType ); if (pMFile->m_dwMask & SDB_MATCHINGINFO_PE_CHECKSUM) DumpDword( VTID_PECHECKSUM, &pBlob, &nTotalBytes, (DWORD)pMFile->m_ulPECheckSum ); if (pMFile->m_dwMask & SDB_MATCHINGINFO_FILE_VERSION) DumpString( VTID_FILEVERSION, &pBlob, &nTotalBytes, pMFile->m_csFileVersion ); if (pMFile->m_dwMask & SDB_MATCHINGINFO_ORIGINAL_FILENAME) DumpString( VTID_ORIGINALFILENAME, &pBlob, &nTotalBytes, pMFile->m_csOriginalFileName ); if (pMFile->m_dwMask & SDB_MATCHINGINFO_INTERNAL_NAME) DumpString( VTID_INTERNALNAME, &pBlob, &nTotalBytes, pMFile->m_csInternalName ); if (pMFile->m_dwMask & SDB_MATCHINGINFO_LEGAL_COPYRIGHT) DumpString( VTID_LEGALCOPYRIGHT, &pBlob, &nTotalBytes, pMFile->m_csLegalCopyright ); if (pMFile->m_dwMask & SDB_MATCHINGINFO_16BIT_DESCRIPTION) DumpString( VTID_16BITDESCRIPTION, &pBlob, &nTotalBytes, pMFile->m_cs16BitDescription ); if (pMFile->m_dwMask & SDB_MATCHINGINFO_UPTO_BIN_PRODUCT_VERSION) DumpBinVersion(VTID_UPTOBINPRODUCTVER, &pBlob, &nTotalBytes, pMFile->m_ullUpToBinProductVersion); if (pMFile->m_dwMask & SDB_MATCHINGINFO_LINK_DATE) { SDBERROR(_T("LINK_DATE not allowed for Win2k registry matching.")); goto eh; } if (pMFile->m_dwMask & SDB_MATCHINGINFO_UPTO_LINK_DATE) { SDBERROR(_T("UPTO_LINK_DATE not allowed for Win2k registry matching.")); goto eh; } } // Terminator *((DWORD*)pBlob) = 0; pBlob += sizeof(DWORD); nTotalBytes += sizeof(DWORD); bSuccess = TRUE; eh: if( bSuccess ) { *pdwSize = nTotalBytes; *ppBlob = pStartOfBlob; } else if( pStartOfBlob ) { FreeRegistryBlob( pStartOfBlob ); *pdwSize = 0; *ppBlob = NULL; } return bSuccess; } BOOL RegistryBlobToString(PBYTE pBlob, DWORD dwBlobSize, CString& csBlob) { DWORD i; CString csTemp; csBlob = ""; for (i = 0; i < dwBlobSize; i++, ++pBlob) { csTemp.Format( _T("%02X"), (DWORD)*pBlob ); if (i == dwBlobSize - 1) { // this is the last char csTemp += _T("\r\n"); } else { if ((i+1) % 27 == 0) { // time to do end of the line ? csTemp += _T(",\\\r\n"); } else { csTemp += _T(","); // just add comma } } csBlob += csTemp; } return(TRUE); } //////////////////////////////////////////////////////////////////////////////////// // // Func: CreateMessageRegEntry, WriteMessageRegistryFiles // // Desc: These functions create Win2k-style registry entries for the old // Message mechanism, which exists in SHELL32!ShellExecute. // BOOL CreateMessageRegEntry( SdbExe* pExe, DWORD dwExeCount, CString& csReg, CString& csInx) { PBYTE pBlob = NULL; BOOL bSuccess = FALSE; DWORD dwBlobSize = 0; CString csRegEntry, csInxEntry; CString csApp; CString csBlob; CString csTemp; if (!CreateRegistryBlob(pExe, &pBlob, &dwBlobSize, (DWORD)_ttol(pExe->m_AppHelpRef.m_pAppHelp->m_csName), pExe->m_AppHelpRef.m_pAppHelp->m_Type)) { SDBERROR(_T("Error in CreateRegistryBlob()")); goto eh; } csApp = pExe->m_pApp->m_csName; csApp.Remove(_T(' ')); csTemp.Format(_T("[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\AppCompatibility\\%s]\r\n\"%05X %s\"=hex:"), pExe->m_csName, dwExeCount, csApp.Left(25)); csRegEntry = csTemp; csTemp.Format(_T("HKLM,\"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\AppCompatibility\\%s\",\"%05X %s\",0x00030003,\\\r\n"), pExe->m_csName, dwExeCount, csApp.Left(25) ); csInxEntry = csTemp; // // now grab the blob // if (!RegistryBlobToString(pBlob, dwBlobSize, csBlob)) { SDBERROR(_T("Error in RegistryBlobToString()")); goto eh; } csRegEntry += csBlob; csInxEntry += csBlob; csReg = csRegEntry; csInx = csInxEntry; bSuccess = TRUE; eh: if (NULL != pBlob) { FreeRegistryBlob( pBlob ); } return(bSuccess); } //////////////////////////////////////////////////////////////////////////////////// // // Func: CreateRegistryBlob, WriteRegistryFiles // // Desc: These functions create a Win2k-style registry entries for both // Message as well as a stub entry for shimming that provides no // additional matching info past EXE name. This allows the 'new' // Win2k version of the shim engine to 'bootstrap' itself into memory // via the original mechanism and then perform more detailed matching // in its own way. // BOOL CreateWin2kExeStubRegistryBlob( SdbExe* pExe, PBYTE* ppBlob, DWORD* pdwSize, DWORD dwMessageID = 0, // these two are optional DWORD dwBlobType = 6) { USES_CONVERSION; BOOL bSuccess = FALSE; DWORD dwBufSize = sizeof(DWORD) * 4; LONG nTotalBytes = 0; PBYTE pStartOfBlob; PBYTE pBlob = (PBYTE) new BYTE[dwBufSize]; pStartOfBlob = pBlob; *pdwSize = 0; if (NULL != pBlob) { // Prolog *((DWORD*)pBlob + 0) = 3 * sizeof(DWORD); // 0x0C 00 00 00 // message id *((DWORD*)pBlob + 1) = dwMessageID; // 0x00 00 00 00 // type is shim *((DWORD*)pBlob + 2) = dwBlobType; // 0x06 00 00 00 pBlob += 3 * sizeof(DWORD); nTotalBytes += 3 * sizeof(DWORD); // Terminator *((DWORD*)pBlob) = 0; pBlob += sizeof(DWORD); nTotalBytes += sizeof(DWORD); *pdwSize = (DWORD)nTotalBytes; *ppBlob = pStartOfBlob; bSuccess = TRUE; } return bSuccess; } BOOL WriteRegistryFiles( SdbDatabase* pDatabase, CString csRegFile, CString csInxFile, BOOL bAddExeStubs) { CString csRegEntry, csInxEntry, csTemp, csCmdLineREG, csCmdLineINX, csTemp1, csApp, csExeName; SdbExe* pExe; SdbApp* pApp; long i, j, l, m; DWORD k, dwBlobSize, dwBytesWritten, dwExeCount = 0; PBYTE pBlob; BOOL b, bSuccess = FALSE; CMapStringToPtr mapNames; SdbApp* pAppValue; HANDLE hRegFile = NULL; HANDLE hInxFile = NULL; hRegFile = CreateFile( csRegFile, GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); hInxFile = CreateFile( csInxFile, GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if( hRegFile == INVALID_HANDLE_VALUE || hInxFile == INVALID_HANDLE_VALUE ) { SDBERROR_FORMAT((_T("Error creating registry files:\n%s\n%s\n"), csRegFile, csInxFile)); goto eh; } if( ! WriteFile( hRegFile, "REGEDIT4\r\n\r\n", strlen("REGEDIT4\r\n\r\n"), &dwBytesWritten, NULL ) ) { SDBERROR(_T("Error writing header to .reg file.\n")); goto eh; } // // loop through all the apps, make apphelp entries // for (i = 0; i < pDatabase->m_rgExes.GetSize(); i++) { pExe = (SdbExe *) pDatabase->m_rgExes[i]; if (pExe->m_AppHelpRef.m_pAppHelp == NULL) { // not an apphelp entry continue; } if (!(pExe->m_dwFilter & g_dwCurrentWriteFilter)) { continue; } b = CreateMessageRegEntry(pExe, dwExeCount, csRegEntry, csInxEntry); if (!b) { SDBERROR(_T("Error creating reg entry.\n")); goto eh; } if (!WriteStringToFile(hRegFile, csRegEntry)) { SDBERROR(_T("Error writing reg entry.\n")); goto eh; } if (!WriteStringToFile(hInxFile, csInxEntry)) { SDBERROR(_T("Error writing inx entry.\n")); goto eh; } ++dwExeCount; } // // Add the Win2k EXE stubs to bootstrap the new shim mechanism // if (bAddExeStubs) { for( i = 0; i < pDatabase->m_rgApps.GetSize(); i++ ) { pApp = (SdbApp *) pDatabase->m_rgApps[i]; csApp = pApp->m_csName; csApp.Remove(_T(' ')); for( j = 0; j < pApp->m_rgExes.GetSize(); j++ ) { pExe = (SdbExe *) pApp->m_rgExes[j]; // // check whether this entry is apphelp-only // if so, skip to the next exe // if (pExe->m_AppHelpRef.m_pAppHelp) { if (pExe->m_AppHelpRef.m_bApphelpOnly) { continue; } } if (pExe->m_bWildcardInName) { continue; } if (!(pExe->m_dwFilter & g_dwCurrentWriteFilter)) { continue; } csExeName = pExe->m_csName; csExeName.MakeUpper(); // now we have to create an application entry -- if we have not hit this // exe name before if (mapNames.Lookup(csExeName, (VOID*&)pAppValue)) { continue; } csRegEntry.Empty(); csInxEntry.Empty(); if (!CreateWin2kExeStubRegistryBlob(pExe, &pBlob, &dwBlobSize)) { SDBERROR(_T("Error creating EXE stub.\n")); goto eh; } // // To reduce the amount of space that we take, we substitute // app name for something short // csApp = _T("x"); csTemp.Format( _T("[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\AppCompatibility\\%s]\r\n\"%s\"=hex:"), pExe->m_csName, csApp.Left(25) ); csRegEntry += csTemp; csTemp.Format( _T("HKLM,\"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\AppCompatibility\\%s\",\"%s\",0x00030003,\\\r\n"), pExe->m_csName, csApp.Left(25) ); csInxEntry += csTemp; RegistryBlobToString(pBlob, dwBlobSize, csTemp); csRegEntry += csTemp; csInxEntry += csTemp; csCmdLineREG.Empty(); csCmdLineINX.Empty(); csTemp.Format( _T("\"DllPatch-%s\"=\"%s\"\r\n"), csApp.Left(25), csCmdLineREG ); csRegEntry += csTemp; csTemp.Format( _T("HKLM,\"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\AppCompatibility\\%s\",\"DllPatch-%s\",0x00000002,\"%s\"\r\n"), pExe->m_csName, csApp.Left(25), csCmdLineINX ); csInxEntry += csTemp; csRegEntry += _T("\r\n"); csInxEntry += _T("\r\n"); if (!WriteStringToFile(hRegFile, csRegEntry)) { SDBERROR(_T("Error writing reg line.\n")); goto eh; } if (!WriteStringToFile(hInxFile, csInxEntry)) { SDBERROR(_T("Error writing inx line.\n")); goto eh; } ++dwExeCount; // now update the map mapNames.SetAt(csExeName, (PVOID)pExe); FreeRegistryBlob( pBlob ); } } } bSuccess = TRUE; eh: if( hRegFile ) CloseHandle( hRegFile ); if( hInxFile ) CloseHandle( hInxFile ); return bSuccess; }