/*++ Copyright (c) 1994-96 Microsoft Corporation Module Name: map.c Abstract: Implementation for the MapAndLoad API Author: Revision History: --*/ #include #include BOOL MapAndLoad( LPSTR ImageName, LPSTR DllPath, PLOADED_IMAGE LoadedImage, BOOL DotDll, BOOL ReadOnly ) { HANDLE hFile; HANDLE hMappedFile; CHAR SearchBuffer[MAX_PATH]; DWORD dw; LPSTR FilePart; LPSTR OpenName; // open and map the file. // then fill in the loaded image descriptor LoadedImage->hFile = INVALID_HANDLE_VALUE; OpenName = ImageName; dw = 0; retry: hFile = CreateFile( OpenName, ReadOnly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, g.OSVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ? (FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE) : (FILE_SHARE_READ | FILE_SHARE_WRITE), NULL, OPEN_EXISTING, 0, NULL ); if ( hFile == INVALID_HANDLE_VALUE ) { if ( !dw ) { // // open failed try to find the file on the search path // dw = SearchPath( DllPath, ImageName, DotDll ? ".dll" : ".exe", MAX_PATH, SearchBuffer, &FilePart ); if ( dw && dw < MAX_PATH ) { OpenName = SearchBuffer; goto retry; } } return FALSE; } if (MapIt(hFile, LoadedImage, ReadOnly) == FALSE) { CloseHandle(hFile); return FALSE; } else { LoadedImage->ModuleName = (LPSTR) MemAlloc( strlen(OpenName)+16 ); if (!LoadedImage->ModuleName) { return FALSE; } strcpy( LoadedImage->ModuleName, OpenName ); // If readonly, no need to keep the file open.. if (ReadOnly) { CloseHandle(hFile); } return TRUE; } } BOOL MapIt( HANDLE hFile, PLOADED_IMAGE LoadedImage, BOOL ReadOnly ) { HANDLE hMappedFile; hMappedFile = CreateFileMapping( hFile, NULL, ReadOnly ? PAGE_READONLY : PAGE_READWRITE, 0, 0, NULL ); if ( !hMappedFile ) { return FALSE; } LoadedImage->MappedAddress = (PUCHAR) MapViewOfFile( hMappedFile, ReadOnly ? FILE_MAP_READ : FILE_MAP_WRITE, 0, 0, 0 ); CloseHandle(hMappedFile); LoadedImage->SizeOfImage = GetFileSize(hFile, NULL); if (!LoadedImage->MappedAddress || !CalculateImagePtrs(LoadedImage)) { return(FALSE); } if (ReadOnly) { LoadedImage->hFile = INVALID_HANDLE_VALUE; } else { LoadedImage->hFile = hFile; } return(TRUE); } BOOL CalculateImagePtrs( PLOADED_IMAGE LoadedImage ) { PIMAGE_DOS_HEADER DosHeader; PIMAGE_NT_HEADERS NtHeaders; PIMAGE_FILE_HEADER FileHeader; BOOL fRC; // Everything is mapped. Now check the image and find nt image headers fRC = TRUE; // Assume the best __try { DosHeader = (PIMAGE_DOS_HEADER)LoadedImage->MappedAddress; if ((DosHeader->e_magic != IMAGE_DOS_SIGNATURE) && (DosHeader->e_magic != IMAGE_NT_SIGNATURE)) { fRC = FALSE; goto tryout; } if (DosHeader->e_magic == IMAGE_DOS_SIGNATURE) { if (DosHeader->e_lfanew == 0) { LoadedImage->fDOSImage = TRUE; fRC = FALSE; goto tryout; } LoadedImage->FileHeader = (PIMAGE_NT_HEADERS)((ULONG_PTR)DosHeader + DosHeader->e_lfanew); if ( // If IMAGE_NT_HEADERS would extend past the end of file... (PBYTE)LoadedImage->FileHeader + sizeof(IMAGE_NT_HEADERS) > (PBYTE)LoadedImage->MappedAddress + LoadedImage->SizeOfImage || // ..or if it would begin in, or before the IMAGE_DOS_HEADER... (PBYTE)LoadedImage->FileHeader < (PBYTE)LoadedImage->MappedAddress + sizeof(IMAGE_DOS_HEADER) ) { // ...then e_lfanew is not as expected. // (Several Win95 files are in this category.) fRC = FALSE; goto tryout; } } else { // No DOS header indicates an image built w/o a dos stub LoadedImage->FileHeader = (PIMAGE_NT_HEADERS)((ULONG_PTR)DosHeader); } NtHeaders = LoadedImage->FileHeader; if ( NtHeaders->Signature != IMAGE_NT_SIGNATURE ) { if ( (USHORT)NtHeaders->Signature == (USHORT)IMAGE_OS2_SIGNATURE || (USHORT)NtHeaders->Signature == (USHORT)IMAGE_OS2_SIGNATURE_LE ) { LoadedImage->fDOSImage = TRUE; } fRC = FALSE; goto tryout; } else { LoadedImage->fDOSImage = FALSE; } FileHeader = &NtHeaders->FileHeader; // No optional header indicates an object... if ( FileHeader->SizeOfOptionalHeader == 0 ) { fRC = FALSE; goto tryout; } if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { // 32-bit image. Do some tests. if (((PIMAGE_NT_HEADERS32)NtHeaders)->OptionalHeader.ImageBase >= 0x80000000) { LoadedImage->fSystemImage = TRUE; } else { LoadedImage->fSystemImage = FALSE; } if (((PIMAGE_NT_HEADERS32)NtHeaders)->OptionalHeader.MajorLinkerVersion < 3 && ((PIMAGE_NT_HEADERS32)NtHeaders)->OptionalHeader.MinorLinkerVersion < 5) { fRC = FALSE; goto tryout; } } else { LoadedImage->fSystemImage = FALSE; } LoadedImage->Sections = IMAGE_FIRST_SECTION(NtHeaders); InitializeListHead( &LoadedImage->Links ); LoadedImage->Characteristics = FileHeader->Characteristics; LoadedImage->NumberOfSections = FileHeader->NumberOfSections; LoadedImage->LastRvaSection = LoadedImage->Sections; tryout: if (fRC == FALSE) { UnmapViewOfFile(LoadedImage->MappedAddress); SetLastError(ERROR_BAD_FORMAT); } } __except ( EXCEPTION_EXECUTE_HANDLER ) { fRC = FALSE; } return fRC; } BOOL UnMapAndLoad( PLOADED_IMAGE pLi ) { UnMapIt(pLi); if (pLi->hFile != INVALID_HANDLE_VALUE) { CloseHandle(pLi->hFile); } return TRUE; } BOOL GrowMap ( PLOADED_IMAGE pLi, LONG lSizeOfDelta ) { if (pLi->hFile == INVALID_HANDLE_VALUE) { // Can't grow read/only files. return FALSE; } else { HANDLE hMappedFile; FlushViewOfFile(pLi->MappedAddress, pLi->SizeOfImage); UnmapViewOfFile(pLi->MappedAddress); pLi->SizeOfImage += lSizeOfDelta; SetFilePointer(pLi->hFile, pLi->SizeOfImage, NULL, FILE_BEGIN); SetEndOfFile(pLi->hFile); hMappedFile = CreateFileMapping( pLi->hFile, NULL, PAGE_READWRITE, 0, pLi->SizeOfImage, NULL ); if ( !hMappedFile ) { CloseHandle(pLi->hFile); pLi->hFile = INVALID_HANDLE_VALUE; return FALSE; } pLi->MappedAddress = (PUCHAR) MapViewOfFile( hMappedFile, FILE_MAP_WRITE, 0, 0, 0 ); CloseHandle(hMappedFile); if (!pLi->MappedAddress) { CloseHandle(pLi->hFile); pLi->hFile = INVALID_HANDLE_VALUE; return(FALSE); } // Win95 doesn't zero fill when it extends. Do it here. if (lSizeOfDelta > 0) { memset(pLi->MappedAddress + pLi->SizeOfImage - lSizeOfDelta, 0, lSizeOfDelta); } // Recalc the LoadedImage struct (remapping may have changed the map address) if (!CalculateImagePtrs(pLi)) { CloseHandle(pLi->hFile); pLi->hFile = INVALID_HANDLE_VALUE; return(FALSE); } return TRUE; } } VOID UnMapIt( PLOADED_IMAGE pLi ) { DWORD HeaderSum, CheckSum; BOOL bl; DWORD dw; PIMAGE_NT_HEADERS NtHeaders; // Test for read-only if (pLi->hFile == INVALID_HANDLE_VALUE) { UnmapViewOfFile(pLi->MappedAddress); } else { CheckSumMappedFile( pLi->MappedAddress, pLi->SizeOfImage, &HeaderSum, &CheckSum ); NtHeaders = pLi->FileHeader; if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ((PIMAGE_NT_HEADERS32)NtHeaders)->OptionalHeader.CheckSum = CheckSum; } else { if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { ((PIMAGE_NT_HEADERS64)NtHeaders)->OptionalHeader.CheckSum = CheckSum; } } FlushViewOfFile(pLi->MappedAddress, pLi->SizeOfImage); UnmapViewOfFile(pLi->MappedAddress); if (pLi->SizeOfImage != GetFileSize(pLi->hFile, NULL)) { dw = SetFilePointer(pLi->hFile, pLi->SizeOfImage, NULL, FILE_BEGIN); dw = GetLastError(); bl = SetEndOfFile(pLi->hFile); dw = GetLastError(); } } } BOOL GetImageConfigInformation( PLOADED_IMAGE LoadedImage, PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigInformation ) { PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData; ULONG i; ImageConfigData = (PIMAGE_LOAD_CONFIG_DIRECTORY) ImageDirectoryEntryToData( LoadedImage->MappedAddress, FALSE, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &i ); if (ImageConfigData != NULL && i == sizeof( *ImageConfigData )) { memcpy( ImageConfigInformation, ImageConfigData, sizeof( *ImageConfigData ) ); return TRUE; } else { return FALSE; } } BOOL SetImageConfigInformation( PLOADED_IMAGE LoadedImage, PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigInformation ) { PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData; ULONG i; ULONG DirectoryAddress; PIMAGE_NT_HEADERS NtHeaders; PIMAGE_DATA_DIRECTORY pLoadCfgDataDir; if (LoadedImage->hFile == INVALID_HANDLE_VALUE) { return FALSE; } ImageConfigData = (PIMAGE_LOAD_CONFIG_DIRECTORY) ImageDirectoryEntryToData( LoadedImage->MappedAddress, FALSE, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &i ); if (ImageConfigData != NULL && i == sizeof( *ImageConfigData )) { memcpy( ImageConfigData, ImageConfigInformation, sizeof( *ImageConfigData ) ); return TRUE; } DirectoryAddress = GetImageUnusedHeaderBytes( LoadedImage, &i ); if (i < sizeof(*ImageConfigData)) { return FALSE; } NtHeaders = LoadedImage->FileHeader; if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { pLoadCfgDataDir = &((PIMAGE_NT_HEADERS32)NtHeaders)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG]; } else { pLoadCfgDataDir = &((PIMAGE_NT_HEADERS64)NtHeaders)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG]; } pLoadCfgDataDir->VirtualAddress = DirectoryAddress; pLoadCfgDataDir->Size = sizeof(*ImageConfigData); ImageConfigData = (PIMAGE_LOAD_CONFIG_DIRECTORY) ((PCHAR)LoadedImage->MappedAddress + DirectoryAddress); memcpy( ImageConfigData, ImageConfigInformation, sizeof( *ImageConfigData ) ); return TRUE; } BOOLEAN ImageLoadInit; LIST_ENTRY ImageLoadList; PLOADED_IMAGE ImageLoad( LPSTR DllName, LPSTR DllPath ) { PLIST_ENTRY Head,Next; PLOADED_IMAGE LoadedImage; CHAR Drive[_MAX_DRIVE]; CHAR Dir[_MAX_DIR]; CHAR Filename[_MAX_FNAME]; CHAR Ext[_MAX_EXT]; CHAR LoadedModuleName[_MAX_PATH]; BOOL fFileNameOnly; if (!ImageLoadInit) { InitializeListHead( &ImageLoadList ); ImageLoadInit = TRUE; } Head = &ImageLoadList; Next = Head->Flink; _splitpath(DllName, Drive, Dir, Filename, Ext); if (!strlen(Drive) && !strlen(Dir)) { // The user only specified a filename (no drive/path). fFileNameOnly = TRUE; } else { fFileNameOnly = FALSE; } while (Next != Head) { LoadedImage = CONTAINING_RECORD( Next, LOADED_IMAGE, Links ); if (fFileNameOnly) { _splitpath(LoadedImage->ModuleName, NULL, NULL, Filename, Ext); strcpy(LoadedModuleName, Filename); strcat(LoadedModuleName, Ext); } else { strcpy(LoadedModuleName, LoadedImage->ModuleName); } if (!_stricmp( DllName, LoadedModuleName )) { return LoadedImage; } Next = Next->Flink; } LoadedImage = (PLOADED_IMAGE) MemAlloc( sizeof( *LoadedImage ) + strlen( DllName ) + 1 ); if (LoadedImage != NULL) { LoadedImage->ModuleName = (LPSTR)(LoadedImage + 1); strcpy( LoadedImage->ModuleName, DllName ); if (MapAndLoad( DllName, DllPath, LoadedImage, TRUE, TRUE )) { InsertTailList( &ImageLoadList, &LoadedImage->Links ); return LoadedImage; } MemFree( LoadedImage ); LoadedImage = NULL; } return LoadedImage; } BOOL ImageUnload( PLOADED_IMAGE LoadedImage ) { if (!IsListEmpty( &LoadedImage->Links )) { RemoveEntryList( &LoadedImage->Links ); } UnMapAndLoad( LoadedImage ); MemFree( LoadedImage ); return TRUE; } BOOL UnloadAllImages() { PLIST_ENTRY Head,Next; PLOADED_IMAGE LoadedImage; if (!ImageLoadInit) { return(TRUE); } Head = &ImageLoadList; Next = Head->Flink; while (Next != Head) { LoadedImage = CONTAINING_RECORD( Next, LOADED_IMAGE, Links ); Next = Next->Flink; ImageUnload(LoadedImage); } ImageLoadInit = FALSE; return (TRUE); }