/*++ Copyright (c) 1997 Microsoft Corporation Module Name: modules.c Abstract: Implements a function that checkes every module listed in MEMDB_CATEGORY_MODULE_CHECK trying to see if all modules listed in IMPORT section are going to be available on NT. The entry point is ProcessModules Author: Calin Negreanu (calinn) 27-Nov-1997 Revision History: mvander 26-Map-1999 Moved MODULESTATUS defines to fileops.h calinn 23-Sep-1998 Added support for NT installed files --*/ #include "pch.h" #include "migdbp.h" #include "migappp.h" #define DBG_MODULES "Modules" #ifdef DEBUG DWORD g_NumEXEs = 0; #endif DWORD g_ModuleRecursionLevel = 0; #define MAX_MODULE_RECURSION_LEVEL 50 #define WIN32_EXE_SET_BITS (IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_32BIT_MACHINE) #define WIN32_EXE_CLEAR_BITS (IMAGE_FILE_DLL) #define WIN32_DLL_SET_BITS (WIN32_EXE_SET_BITS | IMAGE_FILE_DLL) #define WIN32_DLL_CLEAR_BITS 0 #define WIN16_LIBRARY 0x8000 //since we are reading from a file we need that sizeof to give us the accurate result #pragma pack(push,1) typedef struct _NE_HEADER { WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; WORD EntryTableOff; WORD EntryTableLen; ULONG Reserved; WORD Flags; WORD NumberOfDataSeg; WORD SizeOfHeap; WORD SizeOfStack; ULONG CS_IP; ULONG SS_SP; WORD NumEntriesSegTable; WORD NumEntriesModuleTable; WORD NonResNameTableSize; WORD SegTableOffset; WORD ResTableOffset; WORD ResNameTableOffset; WORD ModuleTableOffset; WORD ImportedTableOffset; ULONG NonResNameTableOffset; WORD NumberOfMovableEntryPoints; WORD ShiftCount; WORD NumberOfResourceSegments; BYTE TargetOS; BYTE AdditionalInfo; WORD FastLoadOffset; WORD FastLoadSize; WORD Reserved1; WORD WinVersionExpected; } NE_HEADER, *PNE_HEADER; typedef struct _NE_SEGMENT_ENTRY { WORD SegmentOffset; WORD SegmentLen; WORD SegmentFlags; WORD SegMinAlloc; } NE_SEGMENT_ENTRY, *PNE_SEGMENT_ENTRY; typedef struct _NE_RELOC_ITEM { BYTE AddressType; BYTE RelocType; WORD RelocOffset; WORD ModuleOffset; WORD FunctionOffset; } NE_RELOC_ITEM, *PNE_RELOC_ITEM; #define SEG_CODE_MASK 0x0001 #define SEG_CODE 0x0000 #define SEG_PRELOAD_MASK 0x0040 #define SEG_PRELOAD 0x0040 #define SEG_RELOC_MASK 0x0100 #define SEG_RELOC 0x0100 #define RELOC_IMPORTED_ORDINAL 0x01 #define RELOC_IMPORTED_NAME 0x02 #define RELOC_ADDR_TYPE 0x03 #pragma pack(pop) typedef struct _IMPORT_ENUM32 { /*user area - BEGIN*/ PCSTR ImportModule; PCSTR ImportFunction; ULONG ImportFunctionOrd; /*user area - END*/ PLOADED_IMAGE Image; PIMAGE_IMPORT_DESCRIPTOR ImageDescriptor; DWORD ImportFunctionAddr; PIMAGE_THUNK_DATA ImageData; PIMAGE_IMPORT_BY_NAME ImageName; } IMPORT_ENUM32, *PIMPORT_ENUM32; typedef struct _IMPORT_ENUM16 { /*user area - BEGIN*/ CHAR ImportModule[MAX_MBCHAR_PATH]; CHAR ImportFunction[MAX_MBCHAR_PATH]; ULONG ImportFunctionOrd; /*user area - END*/ PCSTR Image; PDOS_HEADER DosHeader; PNE_HEADER NeHeader; PNE_SEGMENT_ENTRY SegmentEntry; WORD CurrSegEntry; PWORD CurrNrReloc; PNE_RELOC_ITEM RelocItem; WORD CurrRelocItem; } IMPORT_ENUM16, *PIMPORT_ENUM16; typedef struct _MODULE_IMAGE { UINT ModuleType; union { struct { LOADED_IMAGE Image; } W32Data; struct { PCSTR Image; HANDLE FileHandle; HANDLE MapHandle; NE_HEADER Neh; } W16Data; } ModuleData; } MODULE_IMAGE, *PMODULE_IMAGE; static CHAR g_TempKey[MEMDB_MAX]; #define CLEARBUFFER() g_TempKey[0] = 0 #define ISBUFFEREMPTY() (g_TempKey[0] == 0) BOOL LoadModuleData ( IN PCSTR ModuleName, IN OUT PMODULE_IMAGE ModuleImage ) { HANDLE fileHandle; DWORD bytesRead; DOS_HEADER dh; DWORD sign; PWORD signNE = (PWORD)&sign; BOOL result = FALSE; ZeroMemory (ModuleImage, sizeof (MODULE_IMAGE)); ModuleImage->ModuleType = UNKNOWN_MODULE; fileHandle = CreateFile (ModuleName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (fileHandle == INVALID_HANDLE_VALUE) { return FALSE; } __try { __try { if ((!ReadFile (fileHandle, &dh, sizeof (DOS_HEADER), &bytesRead, NULL)) || (bytesRead != sizeof (DOS_HEADER)) ) { __leave; } result = TRUE; if (dh.e_magic != IMAGE_DOS_SIGNATURE) { ModuleImage->ModuleType = UNKNOWN_MODULE; __leave; } ModuleImage->ModuleType = DOS_MODULE; if (SetFilePointer (fileHandle, dh.e_lfanew, NULL, FILE_BEGIN) != (DWORD)dh.e_lfanew) { __leave; } if ((!ReadFile (fileHandle, &sign, sizeof (DWORD), &bytesRead, NULL)) || (bytesRead != sizeof (DWORD)) ) { __leave; } if (sign == IMAGE_PE_SIGNATURE) { ModuleImage->ModuleType = W32_MODULE; result = MapAndLoad ((PSTR)ModuleName, NULL, &ModuleImage->ModuleData.W32Data.Image, FALSE, TRUE); } if (*signNE == IMAGE_NE_SIGNATURE) { ModuleImage->ModuleType = W16_MODULE; ModuleImage->ModuleData.W16Data.Image = MapFileIntoMemory ( ModuleName, &ModuleImage->ModuleData.W16Data.FileHandle, &ModuleImage->ModuleData.W16Data.MapHandle ); if (SetFilePointer (fileHandle, dh.e_lfanew, NULL, FILE_BEGIN) != (DWORD)dh.e_lfanew) { __leave; } if ((!ReadFile (fileHandle, &ModuleImage->ModuleData.W16Data.Neh, sizeof (NE_HEADER), &bytesRead, NULL)) || (bytesRead != sizeof (NE_HEADER)) ) { __leave; } MYASSERT (ModuleImage->ModuleData.W16Data.Neh.Magic == IMAGE_NE_SIGNATURE); result = (ModuleImage->ModuleData.W16Data.Image != NULL); } } __finally { if (fileHandle != INVALID_HANDLE_VALUE) { CloseHandle (fileHandle); } } } __except (EXCEPTION_EXECUTE_HANDLER) { CloseHandle (fileHandle); } return result; } BOOL UnloadModuleData ( IN OUT PMODULE_IMAGE ModuleImage ) { switch (ModuleImage->ModuleType) { case W32_MODULE: UnMapAndLoad (&ModuleImage->ModuleData.W32Data.Image); break; case W16_MODULE: UnmapFile ( (PVOID) ModuleImage->ModuleData.W16Data.Image, ModuleImage->ModuleData.W16Data.FileHandle, ModuleImage->ModuleData.W16Data.MapHandle ); break; default:; } return TRUE; } DWORD GetExeType ( IN PCTSTR ModuleName ) { MODULE_IMAGE moduleImage; DWORD result = EXE_UNKNOWN; DWORD d; __try { if (!LoadModuleData (ModuleName, &moduleImage)) { LOG ((LOG_WARNING, DBG_MODULES":Cannot load image for %s. Error:%ld", ModuleName, GetLastError())); __leave; } if (moduleImage.ModuleType == W32_MODULE) { d = moduleImage.ModuleData.W32Data.Image.Characteristics; result = (d & IMAGE_FILE_DLL) ? EXE_WIN32_DLL : EXE_WIN32_APP; } else if (moduleImage.ModuleType == W16_MODULE) { result = (moduleImage.ModuleData.W16Data.Neh.Flags & WIN16_LIBRARY) ? EXE_WIN16_DLL : EXE_WIN16_APP; } } __finally { UnloadModuleData (&moduleImage); } return result; } BOOL IsNtCompatibleModule ( IN PCTSTR ModuleName ) { if (CheckModule (ModuleName, NULL) == MODULESTATUS_BAD) { return FALSE; } // // other tests? // return TRUE; } PTSTR pBuildModulePaths ( IN PCTSTR ModuleName, IN PCTSTR AppPaths OPTIONAL ) { PTSTR currentPaths; HKEY appPathsKey, currentAppKey; REGKEY_ENUM appPathsEnum; PCTSTR appPathsValue; PTSTR appPathValueExp; PATH_ENUM pathEnum; DWORD attrib; PTSTR pathsPtr; TCHAR modulePath[MAX_PATH]; BOOL b; StringCopy (modulePath, ModuleName); pathsPtr = (PTSTR)GetFileNameFromPath (modulePath); MYASSERT (pathsPtr && *(pathsPtr - 1) == TEXT('\\')); *(pathsPtr - 1) = 0; if (AppPaths) { currentPaths = DuplicateText (AppPaths); b = FALSE; if (EnumFirstPathEx (&pathEnum, currentPaths, NULL, NULL, FALSE)) { do { if (StringIMatch (pathEnum.PtrCurrPath, modulePath)) { b = TRUE; break; } } while (EnumNextPath (&pathEnum)); } if (!b) { pathsPtr = JoinTextEx (NULL, modulePath, currentPaths, ";", 0, NULL); FreeText (currentPaths); currentPaths = pathsPtr; } } else { currentPaths = DuplicateText (modulePath); } appPathsKey = OpenRegKeyStr (S_SKEY_APP_PATHS); if (appPathsKey != NULL) { currentAppKey = OpenRegKey (appPathsKey, GetFileNameFromPath (ModuleName)); if (currentAppKey != NULL) { appPathsValue = GetRegValueString (currentAppKey, TEXT("Path")); if (appPathsValue) { if (EnumFirstPathEx (&pathEnum, appPathsValue, NULL, NULL, FALSE)) { do { MYASSERT (*pathEnum.PtrCurrPath != 0); appPathValueExp = ExpandEnvironmentTextA(pathEnum.PtrCurrPath); _mbsctrim (appPathValueExp, '\\'); attrib = QuietGetFileAttributes (appPathValueExp); if ((attrib != INVALID_ATTRIBUTES) && ((attrib & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY) ) { continue; } pathsPtr = JoinTextEx (NULL, currentPaths, appPathValueExp, ";", 0, NULL); FreeText (currentPaths); currentPaths = pathsPtr; FreeText (appPathValueExp); } while (EnumNextPath (&pathEnum)); } MemFree (g_hHeap, 0, appPathsValue); } appPathsValue = GetRegValueString (currentAppKey, TEXT("UpdatesPath")); if (appPathsValue) { if (EnumFirstPathEx (&pathEnum, appPathsValue, NULL, NULL, FALSE)) { do { MYASSERT (*pathEnum.PtrCurrPath != 0); appPathValueExp = ExpandEnvironmentTextA(pathEnum.PtrCurrPath); _mbsctrim (appPathValueExp, '\\'); attrib = QuietGetFileAttributes (appPathValueExp); if ((attrib != INVALID_ATTRIBUTES) && ((attrib & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY) ) { continue; } pathsPtr = JoinTextEx (NULL, currentPaths, appPathValueExp, ";", 0, NULL); FreeText (currentPaths); currentPaths = pathsPtr; FreeText (appPathValueExp); } while (EnumNextPath (&pathEnum)); } MemFree (g_hHeap, 0, appPathsValue); } CloseRegKey (currentAppKey); } CloseRegKey (appPathsKey); } return currentPaths; } BOOL EnumNextImport16 ( IN OUT PIMPORT_ENUM16 ModuleImports ) { PCSTR currSegmentOffset,importPtr; PWORD moduleNameOffset; BOOL itemFound; ModuleImports->RelocItem ++; ModuleImports->CurrRelocItem ++; itemFound = FALSE; while ((ModuleImports->CurrSegEntry <= ModuleImports->NeHeader->NumEntriesSegTable) && (!itemFound)) { if (((ModuleImports->SegmentEntry->SegmentFlags & SEG_CODE_MASK ) == SEG_CODE ) && ((ModuleImports->SegmentEntry->SegmentFlags & SEG_RELOC_MASK ) == SEG_RELOC ) && ((ModuleImports->SegmentEntry->SegmentFlags & SEG_PRELOAD_MASK) == SEG_PRELOAD) ) { __try { while ((ModuleImports->CurrRelocItem <= *(ModuleImports->CurrNrReloc)) && (!itemFound)) { if (((ModuleImports->RelocItem->AddressType == 0) || (ModuleImports->RelocItem->AddressType == 2) || (ModuleImports->RelocItem->AddressType == 3) || (ModuleImports->RelocItem->AddressType == 5) || (ModuleImports->RelocItem->AddressType == 11) || (ModuleImports->RelocItem->AddressType == 13) ) && ((ModuleImports->RelocItem->RelocType == RELOC_IMPORTED_ORDINAL) || (ModuleImports->RelocItem->RelocType == RELOC_IMPORTED_NAME ) ) ) { itemFound = TRUE; moduleNameOffset = (PWORD) (ModuleImports->Image + ModuleImports->DosHeader->e_lfanew + ModuleImports->NeHeader->ModuleTableOffset + (ModuleImports->RelocItem->ModuleOffset - 1) * sizeof (WORD)); importPtr = ModuleImports->Image + ModuleImports->DosHeader->e_lfanew + ModuleImports->NeHeader->ImportedTableOffset + *moduleNameOffset; strncpy (ModuleImports->ImportModule, importPtr + 1, (BYTE)importPtr[0]); ModuleImports->ImportModule[(BYTE)importPtr[0]] = 0; if (ModuleImports->RelocItem->RelocType == RELOC_IMPORTED_ORDINAL) { ModuleImports->ImportFunction[0] = 0; ModuleImports->ImportFunctionOrd = ModuleImports->RelocItem->FunctionOffset; } else { importPtr = ModuleImports->Image + ModuleImports->DosHeader->e_lfanew + ModuleImports->NeHeader->ImportedTableOffset + ModuleImports->RelocItem->FunctionOffset; strncpy (ModuleImports->ImportFunction, importPtr + 1, (BYTE)importPtr[0]); ModuleImports->ImportFunction[(BYTE)importPtr[0]] = 0; ModuleImports->ImportFunctionOrd = 0; } } if (!itemFound) { ModuleImports->RelocItem ++; ModuleImports->CurrRelocItem ++; } } } __except (1) { itemFound = FALSE; } } if (!itemFound) { ModuleImports->SegmentEntry ++; ModuleImports->CurrSegEntry ++; currSegmentOffset = ModuleImports->Image + (ModuleImports->SegmentEntry->SegmentOffset << ModuleImports->NeHeader->ShiftCount); if (ModuleImports->SegmentEntry->SegmentLen == 0) { currSegmentOffset += 65535; } else { currSegmentOffset += ModuleImports->SegmentEntry->SegmentLen; } ModuleImports->CurrNrReloc = (PWORD) currSegmentOffset; currSegmentOffset += sizeof(WORD); ModuleImports->RelocItem = (PNE_RELOC_ITEM) currSegmentOffset; ModuleImports->CurrRelocItem = 1; } } return itemFound; } BOOL EnumFirstImport16 ( IN PCSTR ModuleImage, IN OUT PIMPORT_ENUM16 ModuleImports ) { PCSTR currSegmentOffset; ZeroMemory (ModuleImports, sizeof (IMPORT_ENUM16)); ModuleImports->Image = ModuleImage; ModuleImports->DosHeader = (PDOS_HEADER) (ModuleImports->Image); ModuleImports->NeHeader = (PNE_HEADER) (ModuleImports->Image + ModuleImports->DosHeader->e_lfanew); ModuleImports->SegmentEntry = (PNE_SEGMENT_ENTRY) (ModuleImports->Image + ModuleImports->DosHeader->e_lfanew + ModuleImports->NeHeader->SegTableOffset ); ModuleImports->CurrSegEntry = 1; currSegmentOffset = ModuleImports->Image + (ModuleImports->SegmentEntry->SegmentOffset << ModuleImports->NeHeader->ShiftCount); if (ModuleImports->SegmentEntry->SegmentLen == 0) { currSegmentOffset += 65535; } else { currSegmentOffset += ModuleImports->SegmentEntry->SegmentLen; } ModuleImports->CurrNrReloc = (PWORD) currSegmentOffset; currSegmentOffset += sizeof(WORD); ModuleImports->RelocItem = (PNE_RELOC_ITEM) currSegmentOffset; ModuleImports->CurrRelocItem = 1; ModuleImports->RelocItem --; ModuleImports->CurrRelocItem --; return EnumNextImport16 (ModuleImports); } BOOL EnumNextImportFunction32 ( IN OUT PIMPORT_ENUM32 ModuleImports ) { if (ModuleImports->ImportFunctionAddr == 0) { return FALSE; } ModuleImports->ImageData = (PIMAGE_THUNK_DATA) ImageRvaToVa ( ModuleImports->Image->FileHeader, ModuleImports->Image->MappedAddress, ModuleImports->ImportFunctionAddr, NULL ); if (ModuleImports->ImageData->u1.AddressOfData) { ModuleImports->ImageName = (PIMAGE_IMPORT_BY_NAME) ImageRvaToVa ( ModuleImports->Image->FileHeader, ModuleImports->Image->MappedAddress, (DWORD)ModuleImports->ImageData->u1.AddressOfData, NULL ); if (ModuleImports->ImageName) { //import by name ModuleImports->ImportFunction = ModuleImports->ImageName->Name; ModuleImports->ImportFunctionOrd = 0; } else { //import by number ModuleImports->ImportFunction = NULL; ModuleImports->ImportFunctionOrd = ModuleImports->ImageData->u1.Ordinal & (~0x80000000); } ModuleImports->ImportFunctionAddr += 4; return TRUE; } else { ModuleImports->ImportFunctionAddr = 0; return FALSE; } } BOOL EnumFirstImportFunction32 ( IN OUT PIMPORT_ENUM32 ModuleImports ) { if ((ModuleImports->ImageDescriptor == NULL) || (ModuleImports->ImportModule == NULL) ) { return FALSE; } ModuleImports->ImportFunctionAddr = ModuleImports->ImageDescriptor->OriginalFirstThunk; return EnumNextImportFunction32 (ModuleImports); } BOOL EnumNextImportModule32 ( IN OUT PIMPORT_ENUM32 ModuleImports ) { if (ModuleImports->ImageDescriptor == NULL) { return FALSE; } ModuleImports->ImageDescriptor ++; if (ModuleImports->ImageDescriptor->Name == 0) { return FALSE; } ModuleImports->ImportModule = (PCSTR) ImageRvaToVa ( ModuleImports->Image->FileHeader, ModuleImports->Image->MappedAddress, ModuleImports->ImageDescriptor->Name, NULL ); return (ModuleImports->ImportModule != NULL); } BOOL EnumFirstImportModule32 ( IN PLOADED_IMAGE ModuleImage, IN OUT PIMPORT_ENUM32 ModuleImports ) { ULONG imageSize; ZeroMemory (ModuleImports, sizeof (IMPORT_ENUM32)); ModuleImports->Image = ModuleImage; ModuleImports->ImageDescriptor = (PIMAGE_IMPORT_DESCRIPTOR) ImageDirectoryEntryToData ( ModuleImage->MappedAddress, FALSE, IMAGE_DIRECTORY_ENTRY_IMPORT, &imageSize ); if (!ModuleImports->ImageDescriptor) { LOG((LOG_WARNING, DBG_MODULES":Cannot load import directory for %s", ModuleImage->ModuleName)); return FALSE; } if (ModuleImports->ImageDescriptor->Name == 0) { return FALSE; } ModuleImports->ImportModule = (PCSTR) ImageRvaToVa ( ModuleImports->Image->FileHeader, ModuleImports->Image->MappedAddress, ModuleImports->ImageDescriptor->Name, NULL ); return (ModuleImports->ImportModule != NULL); } DWORD pCheckDependency ( IN PCSTR CurrentPaths, IN PCSTR ModuleImported) { PSTR tempName = NULL; DWORD memDbValue = 0; PATH_ENUM pathEnum; DWORD result = MODULESTATUS_FILENOTFOUND; DWORD moduleStatus; pathEnum.BufferPtr = NULL; if (EnumFirstPath (&pathEnum, CurrentPaths, g_WinDir, g_SystemDir)) { __try { do { if (*pathEnum.PtrCurrPath == 0) { continue; } tempName = JoinPathsA (pathEnum.PtrCurrPath, ModuleImported); if (SizeOfStringA (tempName) > MAX_PATH) { // // path too long, ignore it // FreePathStringA (tempName); tempName = NULL; continue; } MemDbBuildKey (g_TempKey, MEMDB_CATEGORY_MODULE_CHECK, tempName, NULL, NULL); if (MemDbGetValue (g_TempKey, &memDbValue)) { if ((memDbValue == MODULESTATUS_CHECKED ) || (memDbValue == MODULESTATUS_CHECKING)) { result = MODULESTATUS_CHECKED; __leave; } if (memDbValue == MODULESTATUS_NT_MODULE){ result = MODULESTATUS_NT_MODULE; __leave; } } moduleStatus = GetFileStatusOnNt (tempName); if ((moduleStatus & FILESTATUS_DELETED) == 0) { if ((moduleStatus & FILESTATUS_REPLACED) == FILESTATUS_REPLACED) { result = MODULESTATUS_NT_MODULE; __leave; } if (DoesFileExist (tempName)) { result = CheckModule (tempName, CurrentPaths); __leave; } } if (moduleStatus & FILESTATUS_NTINSTALLED) { result = MODULESTATUS_NT_MODULE; __leave; } } while (EnumNextPath (&pathEnum)); } __finally { EnumPathAbort (&pathEnum); if (tempName) { FreePathStringA (tempName); } } } return result; } BOOL pIsWin9xModule ( IN PCTSTR ModuleName ) { MEMDB_ENUM me; MemDbBuildKey (g_TempKey, MEMDB_CATEGORY_WIN9X_APIS, ModuleName, TEXT("*"), NULL); return MemDbEnumFirstValue (&me, g_TempKey, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY); } DWORD pCheckPEModule ( IN PCSTR CurrentPaths, IN PLOADED_IMAGE ModuleImage ) { IMPORT_ENUM32 e; DWORD result; if (EnumFirstImportModule32 (ModuleImage, &e)) { do { result = pCheckDependency (CurrentPaths, e.ImportModule); if (result == MODULESTATUS_BAD) { LOG(( LOG_WARNING, "%s will be incompatible because %s is incompatible", ModuleImage->ModuleName, e.ImportModule)); return result; } if (result == MODULESTATUS_NT_MODULE) { if (pIsWin9xModule (e.ImportModule)) { if (EnumFirstImportFunction32 (&e)) { do { if (e.ImportFunction) { MemDbBuildKey (g_TempKey, MEMDB_CATEGORY_WIN9X_APIS, e.ImportModule, e.ImportFunction, NULL); if (MemDbGetValue (g_TempKey, NULL)) { LOG(( LOG_WARNING, "%s will be incompatible because %s export will not be available in %s", ModuleImage->ModuleName, e.ImportFunction, e.ImportModule)); return MODULESTATUS_BAD; } } else { wsprintf (g_TempKey, "%s\\%s\\%lu", MEMDB_CATEGORY_WIN9X_APIS, e.ImportModule, e.ImportFunctionOrd); if (MemDbGetValue (g_TempKey, NULL)) { LOG(( LOG_WARNING, "%s will be incompatible because export index %lu will point to a different export in %s", ModuleImage->ModuleName, e.ImportFunctionOrd, e.ImportModule)); return MODULESTATUS_BAD; } } } while (EnumNextImportFunction32 (&e)); } } } if (result == MODULESTATUS_FILENOTFOUND) { LOG (( LOG_WARNING, "Dependency %s of %s not found", e.ImportModule, ModuleImage->ModuleName )); } } while (EnumNextImportModule32 (&e)); } return MODULESTATUS_CHECKED; } DWORD pCheckDependency16 ( IN PCSTR CurrentPaths, IN OUT PCSTR ModuleImported ) { PCTSTR moduleImported; DWORD result = MODULESTATUS_BAD; DWORD memDbValue; MemDbBuildKey (g_TempKey, MEMDB_CATEGORY_MODULE_CHECK, ModuleImported, NULL, NULL); if (MemDbGetValue (g_TempKey, &memDbValue)) { if ((memDbValue == MODULESTATUS_CHECKED ) || (memDbValue == MODULESTATUS_CHECKING)) { result = MODULESTATUS_CHECKED; } if (memDbValue == MODULESTATUS_NT_MODULE){ result = MODULESTATUS_NT_MODULE; } } if (result != MODULESTATUS_BAD) { return result; } moduleImported = JoinText (ModuleImported, ".DLL"); result = pCheckDependency (CurrentPaths, moduleImported); FreeText (moduleImported); if (result != MODULESTATUS_BAD) { return result; } moduleImported = JoinText (ModuleImported, ".EXE"); result = pCheckDependency (CurrentPaths, moduleImported); FreeText (moduleImported); if (result != MODULESTATUS_BAD) { return result; } moduleImported = JoinText (ModuleImported, ".DRV"); result = pCheckDependency (CurrentPaths, moduleImported); FreeText (moduleImported); if (result != MODULESTATUS_BAD) { return result; } return result; } DWORD pCheckNEModule ( IN PCSTR CurrentPaths, IN PCSTR ModuleName, IN PCSTR ModuleImage ) { IMPORT_ENUM16 e; DWORD result; DWORD memDbValue; if (EnumFirstImport16 (ModuleImage, &e)) { do { if (e.ImportModule [0] != 0) { result = pCheckDependency16 (CurrentPaths, e.ImportModule); if (result == MODULESTATUS_BAD) { LOG(( LOG_WARNING, "%s will be incompatible because %s is incompatible", ModuleName, e.ImportModule)); return result; } if (result == MODULESTATUS_NT_MODULE) { if (e.ImportFunctionOrd) { //import by ordinal wsprintf (g_TempKey, "%s\\%s\\%lu", MEMDB_CATEGORY_WIN9X_APIS, e.ImportModule, e.ImportFunctionOrd); if (MemDbGetValue (g_TempKey, NULL)) { LOG(( LOG_WARNING, "%s will be incompatible because export index %lu will point to a different export in %s", ModuleName, e.ImportFunctionOrd, e.ImportModule)); return MODULESTATUS_BAD; } } else { //import by name MemDbBuildKey (g_TempKey, MEMDB_CATEGORY_WIN9X_APIS, e.ImportModule, e.ImportFunction, NULL); if (MemDbGetValue (g_TempKey, &memDbValue)) { LOG(( LOG_WARNING, "%s will be incompatible because %s export will not be available in %s", ModuleName, e.ImportFunction, e.ImportModule)); return MODULESTATUS_BAD; } } } } } while (EnumNextImport16 (&e)); } return MODULESTATUS_CHECKED; } DWORD pCheckModule ( IN PCSTR ModuleName, IN PCSTR AppPaths OPTIONAL ) { MODULE_IMAGE moduleImage; DWORD result = MODULESTATUS_CHECKED; PTSTR CurrentPaths = NULL; __try { if (!LoadModuleData (ModuleName, &moduleImage)) { LOG((LOG_WARNING, DBG_MODULES":Cannot load image for %s. Error:%ld", ModuleName, GetLastError())); __leave; } __try { CurrentPaths = pBuildModulePaths (ModuleName, AppPaths); switch (moduleImage.ModuleType) { case DOS_MODULE: DEBUGMSG((DBG_MODULES, "Examining %s : DOS module.", ModuleName)); break; case W16_MODULE: DEBUGMSG((DBG_MODULES, "Examining %s : W16 module.", ModuleName)); result = pCheckNEModule (CurrentPaths, ModuleName, moduleImage.ModuleData.W16Data.Image); break; case W32_MODULE: DEBUGMSG((DBG_MODULES, "Examining %s : W32 module.", ModuleName)); result = pCheckPEModule (CurrentPaths, &moduleImage.ModuleData.W32Data.Image); break; default: DEBUGMSG((DBG_MODULES, "Examining %s : Unknown module type.", ModuleName)); } } __except (EXCEPTION_EXECUTE_HANDLER) { DWORD rc = _exception_code(); DEBUGMSG((DBG_WARNING, DBG_MODULES":Access violation while checking %s (ec=%#x)", ModuleName, rc)); result = MODULESTATUS_CHECKED; } } __finally { UnloadModuleData (&moduleImage); if (CurrentPaths) { FreeText (CurrentPaths); } } return result; } DWORD GetModuleType ( IN PCSTR ModuleName ) { MODULE_IMAGE moduleImage; DWORD result = UNKNOWN_MODULE; __try { if (!LoadModuleData (ModuleName, &moduleImage)) { LOG((LOG_WARNING, DBG_MODULES":Cannot load image for %s. Error:%ld", ModuleName, GetLastError())); __leave; } result = moduleImage.ModuleType; } __finally { UnloadModuleData (&moduleImage); } return result; } PCSTR Get16ModuleDescription ( IN PCSTR ModuleName ) { MODULE_IMAGE moduleImage; PSTR result = NULL; PDOS_HEADER dosHeader; PNE_HEADER neHeader; PBYTE size; __try { if (!LoadModuleData (ModuleName, &moduleImage)) { LOG((LOG_WARNING, DBG_MODULES":Cannot load image for %s. Error:%ld", ModuleName, GetLastError())); __leave; } if (moduleImage.ModuleType != W16_MODULE) { __leave; } __try { dosHeader = (PDOS_HEADER) (moduleImage.ModuleData.W16Data.Image); neHeader = (PNE_HEADER) (moduleImage.ModuleData.W16Data.Image + dosHeader->e_lfanew); size = (PBYTE) (moduleImage.ModuleData.W16Data.Image + neHeader->NonResNameTableOffset); if (*size == 0) { __leave; } result = AllocPathString (*size + 1); strncpy (result, moduleImage.ModuleData.W16Data.Image + neHeader->NonResNameTableOffset + 1, *size); result [*size] = 0; } __except (1) { DEBUGMSG((DBG_WARNING, DBG_MODULES":Access violation while examining %s.", ModuleName)); if (result != NULL) { FreePathString (result); result = NULL; } __leave; } } __finally { UnloadModuleData (&moduleImage); } return result; } PIMAGE_NT_HEADERS pGetImageNtHeader ( IN PVOID Base ) /*++ Routine Description: This function returns the address of the NT Header. Arguments: Base - Supplies the base of the image. Return Value: Returns the address of the NT Header. --*/ { PIMAGE_NT_HEADERS NtHeaders; if (Base != NULL && Base != (PVOID)-1) { if (((PIMAGE_DOS_HEADER)Base)->e_magic == IMAGE_DOS_SIGNATURE) { NtHeaders = (PIMAGE_NT_HEADERS)((PCHAR)Base + ((PIMAGE_DOS_HEADER)Base)->e_lfanew); if (NtHeaders->Signature == IMAGE_NT_SIGNATURE) { return NtHeaders; } } } return NULL; } ULONG GetPECheckSum ( IN PCSTR ModuleName ) { MODULE_IMAGE moduleImage; ULONG result = 0; PIMAGE_NT_HEADERS NtHeaders; __try { if (!LoadModuleData (ModuleName, &moduleImage)) { LOG((LOG_WARNING, DBG_MODULES":Cannot load image for %s. Error:%ld", ModuleName, GetLastError())); __leave; } if (moduleImage.ModuleType != W32_MODULE) { __leave; } __try { NtHeaders = pGetImageNtHeader(moduleImage.ModuleData.W32Data.Image.MappedAddress); if (NtHeaders) { if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { result = ((PIMAGE_NT_HEADERS32)NtHeaders)->OptionalHeader.CheckSum; } else if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { result = ((PIMAGE_NT_HEADERS64)NtHeaders)->OptionalHeader.CheckSum; } } } __except (1) { DEBUGMSG((DBG_WARNING, DBG_MODULES":Access violation while examining %s.", ModuleName)); result = 0; __leave; } } __finally { UnloadModuleData (&moduleImage); } return result; } DWORD CheckModule ( IN PCSTR ModuleName, IN PCSTR AppPaths OPTIONAL ) { DWORD result; DWORD moduleStatus; MemDbSetValueEx (MEMDB_CATEGORY_MODULE_CHECK, ModuleName, NULL, NULL, MODULESTATUS_CHECKING, NULL); g_ModuleRecursionLevel++; if (g_ModuleRecursionLevel < MAX_MODULE_RECURSION_LEVEL) { result = pCheckModule (ModuleName, AppPaths); if (result == MODULESTATUS_BAD) { moduleStatus = GetFileStatusOnNt (ModuleName); if ((moduleStatus & FILESTATUS_NTINSTALLED) == FILESTATUS_NTINSTALLED) { MarkFileForDelete (ModuleName); result = MODULESTATUS_NT_MODULE; } } } else { result = MODULESTATUS_CHECKED; } g_ModuleRecursionLevel--; MemDbSetValueEx (MEMDB_CATEGORY_MODULE_CHECK, ModuleName, NULL, NULL, result, NULL); return result; } BOOL pProcessModules ( VOID ) { MEMDB_ENUM enumItems; PSTR pathsPtr; DWORD moduleStatus; DWORD attrib; LONG stringId; DWORD status; DWORD Count = 0; MemDbSetValueEx(MEMDB_CATEGORY_MODULE_CHECK,TEXT("KERNEL32"),NULL,NULL,MODULESTATUS_NT_MODULE,NULL); MemDbSetValueEx(MEMDB_CATEGORY_MODULE_CHECK,TEXT("KERNEL" ),NULL,NULL,MODULESTATUS_NT_MODULE,NULL); MemDbSetValueEx(MEMDB_CATEGORY_MODULE_CHECK,TEXT("USER32" ),NULL,NULL,MODULESTATUS_NT_MODULE,NULL); MemDbSetValueEx(MEMDB_CATEGORY_MODULE_CHECK,TEXT("USER" ),NULL,NULL,MODULESTATUS_NT_MODULE,NULL); MemDbSetValueEx(MEMDB_CATEGORY_MODULE_CHECK,TEXT("GDI32" ),NULL,NULL,MODULESTATUS_NT_MODULE,NULL); MemDbSetValueEx(MEMDB_CATEGORY_MODULE_CHECK,TEXT("GDI" ),NULL,NULL,MODULESTATUS_NT_MODULE,NULL); MemDbSetValueEx(MEMDB_CATEGORY_MODULE_CHECK,TEXT("SHELL32" ),NULL,NULL,MODULESTATUS_NT_MODULE,NULL); MemDbSetValueEx(MEMDB_CATEGORY_MODULE_CHECK,TEXT("SHELL" ),NULL,NULL,MODULESTATUS_NT_MODULE,NULL); MemDbSetValueEx(MEMDB_CATEGORY_MODULE_CHECK,TEXT("SOUND32" ),NULL,NULL,MODULESTATUS_NT_MODULE,NULL); MemDbSetValueEx(MEMDB_CATEGORY_MODULE_CHECK,TEXT("SOUND" ),NULL,NULL,MODULESTATUS_NT_MODULE,NULL); MemDbSetValueEx(MEMDB_CATEGORY_MODULE_CHECK,TEXT("DISPLAY" ),NULL,NULL,MODULESTATUS_NT_MODULE,NULL); MemDbSetValueEx(MEMDB_CATEGORY_MODULE_CHECK,TEXT("KEYBOARD"),NULL,NULL,MODULESTATUS_NT_MODULE,NULL); MemDbBuildKey (g_TempKey, MEMDB_CATEGORY_MODULE_CHECK, TEXT("*"), NULL, NULL); if (MemDbEnumFirstValue (&enumItems, g_TempKey, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) { do { if (CANCELLED()) { SetLastError (ERROR_CANCELLED); return FALSE; } #ifdef DEBUG { CHAR DbgBuf[256]; if (GetPrivateProfileString ("MigDb", GetFileNameFromPath (enumItems.szName), "", DbgBuf, 256, g_DebugInfPath)) { DEBUGMSG((DBG_NAUSEA, "Debug point hit in Modules.c")); } } #endif if (enumItems.dwValue == MODULESTATUS_UNCHECKED) { moduleStatus = GetFileStatusOnNt (enumItems.szName); if ((moduleStatus & FILESTATUS_DELETED) == FILESTATUS_DELETED) { continue; } if ((moduleStatus & FILESTATUS_REPLACED) == FILESTATUS_REPLACED) { continue; } g_ModuleRecursionLevel = 0; moduleStatus = CheckModule (enumItems.szName, NULL); if (moduleStatus == MODULESTATUS_BAD) { status = GetFileStatusOnNt (enumItems.szName); if (!(status & FILESTATUS_DELETED)) { RemoveOperationsFromPath (enumItems.szName, ALL_CHANGE_OPERATIONS); MarkFileForExternalDelete (enumItems.szName); } if (!IsFileMarkedForAnnounce (enumItems.szName)) { AnnounceFileInReport (enumItems.szName, 0, ACT_INC_NOBADAPPS); } LOG ((LOG_INFORMATION, (PCSTR)MSG_MODULE_REQUIRES_EXPORT_LOG, enumItems.szName)); } } Count++; if (!(Count % 4)) { TickProgressBar (); } } while (MemDbEnumNextValue (&enumItems)); } DEBUGMSG((DBG_MODULES, "Modules checking : ===========================")); DEBUGMSG((DBG_MODULES, "Number of executables checked : %ld", g_NumEXEs)); DEBUGMSG((DBG_MODULES, "Number of modules in MEMDB tree: %ld", Count)); MemDbDeleteTree (MEMDB_CATEGORY_MODULE_CHECK); return TRUE; } DWORD ProcessModules ( IN DWORD Request ) { switch (Request) { case REQUEST_QUERYTICKS: return TICKS_PROCESS_MODULES; case REQUEST_RUN: if (!pProcessModules ()) { return GetLastError (); } else { return ERROR_SUCCESS; } default: DEBUGMSG ((DBG_ERROR, "Bad parameter in ProcessModules")); } return 0; } BOOL pPrepareProcessModules ( VOID ) { PCTSTR TempStr; TempStr = JoinPaths (g_UpgradeSources, S_E95ONLY_DAT); MemDbImport (TempStr); FreePathString (TempStr); return TRUE; } DWORD PrepareProcessModules ( IN DWORD Request ) { switch (Request) { case REQUEST_QUERYTICKS: return TICKS_PREPARE_PROCESS_MODULES; case REQUEST_RUN: if (!pPrepareProcessModules ()) { return GetLastError (); } else { return ERROR_SUCCESS; } default: DEBUGMSG ((DBG_ERROR, "Bad parameter in PrepareProcessModules")); } return 0; } BOOL SaveExeFiles ( IN PFILE_HELPER_PARAMS Params ) { if (Params->Handled) { return TRUE; } // Save EXE and SCR files to MemDB to enumerate later if ((StringIMatch (Params->Extension, TEXT(".EXE"))) || (StringIMatch (Params->Extension, TEXT(".SCR"))) ) { if (!IsFileMarkedAsKnownGood (Params->FullFileSpec)) { MemDbSetValueEx ( MEMDB_CATEGORY_MODULE_CHECK, Params->FullFileSpec, NULL, NULL, MODULESTATUS_UNCHECKED, NULL); #ifdef DEBUG g_NumEXEs++; #endif } } return TRUE; }