|
|
#include "pch.h"
#include "iedetect.h"
#define VALID_SIGNATURE 0x5c3f3f5c // string "\??\"
#define REMOVE_QUOTES 0x01
#define IGNORE_QUOTES 0x02
CONST CHAR g_cszWininit[] = "wininit.ini"; CONST CHAR g_cszRenameSec[] = "Rename"; CONST CHAR g_cszPFROKey[] = REGSTR_PATH_CURRENT_CONTROL_SET "\\SESSION MANAGER"; CONST CHAR g_cszPFRO[] = "PendingFileRenameOperations";
DWORD CheckFileEx(LPSTR szDir, DETECT_FILES Detect_Files);
DWORD GetStringField(LPSTR szStr, UINT uField, char cDelimiter, LPSTR szBuf, UINT cBufSize) { LPSTR pszBegin = szStr; LPSTR pszEnd; UINT i = 0; DWORD dwToCopy;
if(cBufSize == 0) return 0;
szBuf[0] = 0;
if(szStr == NULL) return 0;
while(*pszBegin != 0 && i < uField) { pszBegin = FindChar(pszBegin, cDelimiter); if(*pszBegin != 0) pszBegin++; i++; }
// we reached end of string, no field
if(*pszBegin == 0) { return 0; }
pszEnd = FindChar(pszBegin, cDelimiter); while(pszBegin <= pszEnd && *pszBegin == ' ') pszBegin++;
while(pszEnd > pszBegin && *(pszEnd - 1) == ' ') pszEnd--;
if(pszEnd > (pszBegin + 1) && *pszBegin == '"' && *(pszEnd-1) == '"') { pszBegin++; pszEnd--; }
dwToCopy = (DWORD)(pszEnd - pszBegin + 1);
if(dwToCopy > cBufSize) dwToCopy = cBufSize;
lstrcpynA(szBuf, pszBegin, dwToCopy);
return dwToCopy - 1; }
DWORD GetIntField(LPSTR szStr, char cDelimiter, UINT uField, DWORD dwDefault) { char szNumBuf[16];
if(GetStringField(szStr, uField, cDelimiter, szNumBuf, sizeof(szNumBuf)) == 0) return dwDefault; else return AtoL(szNumBuf); }
int CompareLocales(LPCSTR pcszLoc1, LPCSTR pcszLoc2) { int ret;
if(pcszLoc1[0] == '*' || pcszLoc2[0] == '*') ret = 0; else ret = lstrcmpi(pcszLoc1, pcszLoc2);
return ret; }
void ConvertVersionStrToDwords(LPSTR pszVer, char cDelimiter, LPDWORD pdwVer, LPDWORD pdwBuild) { DWORD dwTemp1,dwTemp2;
dwTemp1 = GetIntField(pszVer, cDelimiter, 0, 0); dwTemp2 = GetIntField(pszVer, cDelimiter, 1, 0);
*pdwVer = (dwTemp1 << 16) + dwTemp2;
dwTemp1 = GetIntField(pszVer, cDelimiter, 2, 0); dwTemp2 = GetIntField(pszVer, cDelimiter, 3, 0);
*pdwBuild = (dwTemp1 << 16) + dwTemp2; }
LPSTR FindChar(LPSTR pszStr, char ch) { while( *pszStr != 0 && *pszStr != ch ) pszStr++; return pszStr; }
DWORD CompareVersions(DWORD dwAskVer, DWORD dwAskBuild, DWORD dwInstalledVer, DWORD dwInstalledBuild) { DWORD dwRet = DET_NOTINSTALLED; if((dwInstalledVer == dwAskVer) && (dwInstalledBuild == dwAskBuild)) { dwRet = DET_INSTALLED; } else if( (dwInstalledVer > dwAskVer) || ((dwInstalledVer == dwAskVer) && (dwInstalledBuild > dwAskBuild)) )
{ dwRet = DET_NEWVERSIONINSTALLED; } else if( (dwInstalledVer < dwAskVer) || ((dwInstalledVer == dwAskVer) && (dwInstalledBuild < dwAskBuild)) )
{ dwRet = DET_OLDVERSIONINSTALLED; } return dwRet; }
BOOL FRunningOnNT(void) { static BOOL fIsNT = 2 ; OSVERSIONINFO VerInfo;
// If we have calculated this before just pass that back.
// else find it now.
//
if (fIsNT == 2) { VerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&VerInfo);
// Note: We don't check for Win32S on Win 3.1 here -- that should
// have been a blocking check earlier in fn CheckWinVer().
// Also, we don't check for failure on the above call as it
// should succeed if we are on NT 4.0 or Win 9X!
//
fIsNT = (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT); }
return fIsNT; }
BOOL GetVersionFromGuid(LPSTR pszGuid, LPDWORD pdwVer, LPDWORD pdwBuild) { HKEY hKey; char szValue[MAX_PATH]; DWORD dwValue = 0; DWORD dwSize; BOOL bVersion = FALSE;
if (pdwVer && pdwBuild) { *pdwVer = 0; *pdwBuild = 0; lstrcpy(szValue, COMPONENT_KEY); AddPath(szValue, pszGuid); if(RegOpenKeyExA(HKEY_LOCAL_MACHINE, szValue, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { dwSize = sizeof(dwValue); if(RegQueryValueEx(hKey, ISINSTALLED_KEY, 0, NULL, (LPBYTE)&dwValue, &dwSize) == ERROR_SUCCESS) { if (dwValue != 0) { dwSize = sizeof(szValue); if(RegQueryValueEx(hKey, VERSION_KEY, 0, NULL, (LPBYTE)szValue, &dwSize) == ERROR_SUCCESS) { ConvertVersionStrToDwords(szValue, ',', pdwVer, pdwBuild); bVersion = TRUE; } } } RegCloseKey(hKey); } } return bVersion; }
BOOL CompareLocal(LPCSTR pszGuid, LPCSTR pszLocal) { HKEY hKey; char szValue[MAX_PATH]; DWORD dwSize; BOOL bLocal = FALSE; if (lstrcmpi(pszLocal, "*") == 0) { bLocal = TRUE; } else { lstrcpy(szValue, COMPONENT_KEY); AddPath(szValue, pszGuid); if(RegOpenKeyExA(HKEY_LOCAL_MACHINE, szValue, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { dwSize = sizeof(szValue); if(RegQueryValueEx(hKey, LOCALE_KEY, 0, NULL, (LPBYTE)szValue, &dwSize) == ERROR_SUCCESS) { bLocal = (lstrcmpi(szValue, pszLocal) == 0); }
RegCloseKey(hKey); } } return bLocal; }
PSTR GetNextField(PSTR *ppszData, PCSTR pcszDeLims, DWORD dwFlags) // If (dwFlags & IGNORE_QUOTES) is TRUE, then look for any char in pcszDeLims in *ppszData. If found,
// replace it with the '\0' char and set *ppszData to point to the beginning of the next field and return
// pointer to current field.
//
// If (dwFlags & IGNORE_QUOTES) is FALSE, then look for any char in pcszDeLims outside of balanced quoted sub-strings
// in *ppszData. If found, replace it with the '\0' char and set *ppszData to point to the beginning of
// the next field and return pointer to current field.
//
// If (dwFlags & REMOVE_QUOTES) is TRUE, then remove the surrounding quotes and replace two consecutive quotes by one.
//
// NOTE: If IGNORE_QUOTES and REMOVE_QUOTES are both specified, then IGNORE_QUOTES takes precedence over REMOVE_QUOTES.
//
// If you just want to remove the quotes from a string, call this function as
// GetNextField(&pszData, "\"" or "'" or "", REMOVE_QUOTES).
//
// If you call this function as GetNextField(&pszData, "\"" or "'" or "", 0), you will get back the
// entire pszData as the field.
//
{ PSTR pszRetPtr, pszPtr; BOOL fWithinQuotes = FALSE, fRemoveQuote; CHAR chQuote;
if (ppszData == NULL || *ppszData == NULL || **ppszData == '\0') return NULL;
for (pszRetPtr = pszPtr = *ppszData; *pszPtr; pszPtr = CharNext(pszPtr)) { if (!(dwFlags & IGNORE_QUOTES) && (*pszPtr == '"' || *pszPtr == '\'')) { fRemoveQuote = FALSE;
if (*pszPtr == *(pszPtr + 1)) // two consecutive quotes become one
{ pszPtr++;
if (dwFlags & REMOVE_QUOTES) fRemoveQuote = TRUE; else { // if pcszDeLims is '"' or '\'', then *pszPtr == pcszDeLims would
// be TRUE and we would break out of the loop against the design specs;
// to prevent this just continue
continue; } } else if (!fWithinQuotes) { fWithinQuotes = TRUE; chQuote = *pszPtr; // save the quote char
fRemoveQuote = dwFlags & REMOVE_QUOTES; } else { if (*pszPtr == chQuote) // match the correct quote char
{ fWithinQuotes = FALSE; fRemoveQuote = dwFlags & REMOVE_QUOTES; } }
if (fRemoveQuote) { // shift the entire string one char to the left to get rid of the quote char
MoveMemory(pszPtr, pszPtr + 1, lstrlen(pszPtr)); } }
// BUGBUG: Is type casting pszPtr to UNALIGNED necessary? -- copied it from ANSIStrChr
// check if pszPtr is pointing to one of the chars in pcszDeLims
if (!fWithinQuotes && ANSIStrChr(pcszDeLims, (WORD) (IsDBCSLeadByte(*pszPtr) ? *((UNALIGNED WORD *) pszPtr) : *pszPtr)) != NULL) break; }
// NOTE: if fWithinQuotes is TRUE here, then we have an unbalanced quoted string; but we don't care!
// the entire string after the beginning quote becomes the field
if (*pszPtr) // pszPtr is pointing to a char in pcszDeLims
{ *ppszData = CharNext(pszPtr); // save the pointer to the beginning of next field in *ppszData
*pszPtr = '\0'; // replace the DeLim char with the '\0' char
} else *ppszData = pszPtr; // we have reached the end of the string; next call to this function
// would return NULL
return pszRetPtr; }
PSTR GetDataFromWininitOrPFRO(PCSTR pcszWininit, HKEY hkPFROKey, PDWORD pdwLen) { PSTR pszData, pszPtr;
*pdwLen = 0;
if (!FRunningOnNT()) { HANDLE hFile; WIN32_FIND_DATA FileData;
// find the size of pcszWininit
if ((hFile = FindFirstFile(pcszWininit, &FileData)) != INVALID_HANDLE_VALUE) { *pdwLen = FileData.nFileSizeLow; FindClose(hFile); }
if (*pdwLen == 0 || (pszData = (PSTR) LocalAlloc(LPTR, *pdwLen)) == NULL) return NULL;
GetPrivateProfileSection(g_cszRenameSec, pszData, *pdwLen, pcszWininit);
// replace the ='s by \0's
// BUGBUG: assuming that all the lines in wininit.ini have the correct format, i.e., to=from
for (pszPtr = pszData; *pszPtr; pszPtr += lstrlen(pszPtr) + 1) GetNextField(&pszPtr, "=", IGNORE_QUOTES); } else { if (hkPFROKey == NULL) return NULL;
// get the length of value data
RegQueryValueEx(hkPFROKey, g_cszPFRO, NULL, NULL, NULL, pdwLen);
if (*pdwLen == 0 || (pszData = (PSTR) LocalAlloc(LPTR, *pdwLen)) == NULL) return NULL;
// get the data
RegQueryValueEx(hkPFROKey, g_cszPFRO, NULL, NULL, (PBYTE) pszData, pdwLen); }
return pszData; }
VOID ReadFromWininitOrPFRO(PCSTR pcszKey, PSTR pszValue) { CHAR szShortName[MAX_PATH]; CHAR szWininit[MAX_PATH]; PSTR pszData, pszLine, pszFrom, pszTo; DWORD dwLen; HKEY hkPFROKey = NULL;
if (!FRunningOnNT()) { GetWindowsDirectory(szWininit, sizeof(szWininit)); AddPath(szWininit, g_cszWininit); } else RegOpenKeyEx(HKEY_LOCAL_MACHINE, g_cszPFROKey, 0, KEY_READ, &hkPFROKey);
// return empty string if pcszKey could not be found
*pszValue = '\0';
if ((pszData = GetDataFromWininitOrPFRO(szWininit, hkPFROKey, &dwLen)) == NULL) { if (hkPFROKey != NULL) RegCloseKey(hkPFROKey);
return; }
if (!FRunningOnNT()) { GetShortPathName(pcszKey, szShortName, sizeof(szShortName)); pcszKey = szShortName; }
pszLine = pszData; while (*pszLine) { // NOTE: On Win95, the format is (To, From) but on NT4.0, the format is (From, To)
if (!FRunningOnNT()) { // format of GetPrivateProfileSection data is:
//
// to1=from1\0 ; from1 is the Value and to1 is the Key
// to2=from2\0
// NUL=del1\0 ; del1 is the Key
// NUL=del2\0
// .
// .
// .
// to<n>=from<n>\0\0
pszTo = pszLine; // key
pszFrom = pszLine + lstrlen(pszLine) + 1; pszLine = pszFrom + lstrlen(pszFrom) + 1; // point to the next line
} else { // format of the value data for PFRO value name is:
//
// from1\0to1\0 ; from1 is the Value and to1 is the Key
// from2\0to2\0
// del1\0\0 ; del1 is the Key
// del2\0\0
// .
// .
// .
// from<n>\0to<n>\0\0
pszFrom = pszLine; pszTo = pszLine + lstrlen(pszLine) + 1; // key
pszLine = pszTo + lstrlen(pszTo) + 1; // point to the next line
// skip over "\??\"
if (*pszFrom == '\\') // '\\' is not a Leading DBCS byte
{ if (*((PDWORD) pszFrom) == VALID_SIGNATURE) pszFrom += 4; else continue; }
if (*pszTo == '!') // '!' is neither a Leading nor a Trailing DBCS byte
pszTo++;
if (*pszTo == '\\') { if (*((PDWORD) pszTo) == VALID_SIGNATURE) pszTo += 4; else continue; } }
if (lstrcmpi(pcszKey, pszTo) == 0) // if there is more than one entry, return the last one
lstrcpy(pszValue, pszFrom); }
LocalFree(pszData);
if (hkPFROKey != NULL) RegCloseKey(hkPFROKey); }
DWORD CheckFile(DETECT_FILES Detect_Files) { char szFile[MAX_PATH] = { 0 }; DWORD dwRet = DET_NOTINSTALLED; DWORD dwRetLast = DET_NOTINSTALLED; int i =0;
while (Detect_Files.cPath[i]) { switch (Detect_Files.cPath[i]) { case 'S': case 's': GetSystemDirectory( szFile, sizeof(szFile) ); break;
case 'W': case 'w': GetWindowsDirectory( szFile, sizeof(szFile) ); break;
// Windows command folder
case 'C': case 'c': GetWindowsDirectory( szFile, sizeof(szFile) ); AddPath(szFile, "Command"); break;
default: *szFile = '\0'; } if (*szFile) { dwRet = CheckFileEx(szFile, Detect_Files); switch (dwRet) { case DET_NOTINSTALLED: break; case DET_OLDVERSIONINSTALLED: if (dwRetLast == DET_NOTINSTALLED) dwRetLast = dwRet; break;
case DET_INSTALLED: if ((dwRetLast == DET_NOTINSTALLED) || (dwRetLast == DET_OLDVERSIONINSTALLED)) dwRetLast = dwRet; break;
case DET_NEWVERSIONINSTALLED: if ((dwRetLast == DET_NOTINSTALLED) || (dwRetLast == DET_OLDVERSIONINSTALLED) || (dwRetLast == DET_INSTALLED)) dwRetLast = dwRet; break; } }
// go to the next directory letter.
while ((Detect_Files.cPath[i]) && (Detect_Files.cPath[i] != ',')) i++; if (Detect_Files.cPath[i] == ',') i++; } return dwRetLast; }
DWORD CheckFileEx(LPSTR szDir, DETECT_FILES Detect_Files) { char szFile[MAX_PATH]; char szRenameFile[MAX_PATH]; DWORD dwInstalledVer, dwInstalledBuild; DWORD dwRet = DET_NOTINSTALLED;
if (*szDir) { lstrcpy(szFile, szDir); AddPath(szFile, Detect_Files.szFilename); if (Detect_Files.dwMSVer == (DWORD)-1) { if (GetFileAttributes(szFile) != 0xFFFFFFFF) dwRet = DET_INSTALLED; } else { ReadFromWininitOrPFRO(szFile, szRenameFile); if (*szRenameFile != '\0') GetVersionFromFile(szRenameFile, &dwInstalledVer, &dwInstalledBuild, TRUE); else GetVersionFromFile(szFile, &dwInstalledVer, &dwInstalledBuild, TRUE);
if (dwInstalledVer != 0) dwRet = CompareVersions(Detect_Files.dwMSVer, Detect_Files.dwLSVer, dwInstalledVer, dwInstalledBuild); } } return dwRet; }
DWORD WINAPI DetectFile(DETECTION_STRUCT *pDet, LPSTR pszFilename) { DWORD dwRet = DET_NOTINSTALLED; DWORD dwInstalledVer, dwInstalledBuild; char szFile[MAX_PATH]; char szRenameFile[MAX_PATH];
dwInstalledVer = (DWORD) -1; dwInstalledBuild = (DWORD) -1; GetSystemDirectory(szFile, sizeof(szFile)); AddPath(szFile, pszFilename); ReadFromWininitOrPFRO(szFile, szRenameFile); if (*szRenameFile != '\0') GetVersionFromFile(szRenameFile, &dwInstalledVer, &dwInstalledBuild, TRUE); else GetVersionFromFile(szFile, &dwInstalledVer, &dwInstalledBuild, TRUE);
if (dwInstalledVer != 0) dwRet = CompareVersions(pDet->dwAskVer, pDet->dwAskBuild, dwInstalledVer, dwInstalledBuild);
if (pDet->pdwInstalledVer && pDet->pdwInstalledBuild) { *(pDet->pdwInstalledVer) = dwInstalledVer; *(pDet->pdwInstalledBuild) = dwInstalledBuild; } return dwRet; }
|