// Copyright 2011-2020 Molecular Matters GmbH, all rights reserved. #pragma once #if LC_VERSION == 1 // BEGIN EPIC MOD #include "CoreTypes.h" // END EPIC MOD #include "LC_PointerUtil.h" #include "LC_MemoryMappedFile.h" #include "LC_Hashing.h" // BEGIN EPIC MOD #include #include "Windows/WindowsHWrapper.h" // END EPIC MOD namespace executable { #if LC_64_BIT typedef uint64_t PreferredBase; #else typedef uint32_t PreferredBase; #endif struct Header { uint64_t sizeOnDisk; IMAGE_FILE_HEADER imageHeader; IMAGE_OPTIONAL_HEADER optionalHeader; }; typedef Filesystem::MemoryMappedFile Image; struct ImageSection { uint32_t rva; uint32_t size; uint32_t rawDataRva; uint32_t rawDataSize; }; struct ImageSectionDB { std::vector sections; }; struct ImportModule { char path[MAX_PATH]; }; struct ImportModuleDB { std::vector modules; }; struct PdbInfo { char path[MAX_PATH]; // can be an absolute or relative path GUID guid; uint32_t age; }; Image* OpenImage(const wchar_t* filename, Filesystem::OpenMode::Enum openMode); void CloseImage(Image*& image); void RebaseImage(Image* image, PreferredBase preferredBase); ImageSectionDB* GatherImageSectionDB(const Image* image); void DestroyImageSectionDB(ImageSectionDB* database); ImportModuleDB* GatherImportModuleDB(const Image* image, const ImageSectionDB* imageSections); void DestroyImportModuleDB(ImportModuleDB* database); // reads the PDB info stored in the image's debug directories (if available) PdbInfo* GatherPdbInfo(const Image* image, const ImageSectionDB* imageSections); void DestroyPdbInfo(PdbInfo* pdbInfo); // returns the RVA of the entry point of the image when loaded into memory uint32_t GetEntryPointRva(const Image* image); // returns the preferred address at which the image is to be loaded into memory PreferredBase GetPreferredBase(const Image* image); // returns the image's header Header GetHeader(const Image* image); // checks whether a header is valid bool IsValidHeader(const Header& header); // returns the size of the image when loaded into memory uint32_t GetSize(const Image* image); // helper functions uint32_t RvaToFileOffset(const ImageSectionDB* database, uint32_t rva); void ReadFromFileOffset(const Image* file, uint32_t offset, void* destination, size_t byteCount); void WriteToFileOffset(Image* file, uint32_t offset, const void* source, size_t byteCount); // helper function to directly read from an RVA in the given image template inline T ReadFromImage(const Image* image, const ImageSectionDB* database, uint32_t rva) { const uint32_t fileOffset = RvaToFileOffset(database, rva); if (fileOffset == 0u) { // don't try to read from sections without data in the image, e.g. .bss return T(0); } const T* address = pointer::Offset(Filesystem::GetMemoryMappedFileData(image), fileOffset); return *address; } void CallDllEntryPoint(void* moduleBase, uint32_t entryPointRva); } // specializations to allow executable::Header to be used as key in maps and sets namespace std { template <> struct hash { inline std::size_t operator()(const executable::Header& header) const { const uint32_t hash1 = Hashing::Hash32(&header.imageHeader, sizeof(executable::Header::imageHeader), 0u); const uint32_t hash2 = Hashing::Hash32(&header.optionalHeader, sizeof(executable::Header::optionalHeader), hash1); return hash2; } }; template <> struct equal_to { inline bool operator()(const executable::Header& lhs, const executable::Header& rhs) const { // comparing just the size on disk is fastest if (lhs.sizeOnDisk != rhs.sizeOnDisk) { return false; } // comparing the image header is the second-best option else if (::memcmp(&lhs.imageHeader, &rhs.imageHeader, sizeof(executable::Header::imageHeader)) != 0) { return false; } // comparing the optional header is slowest else if (::memcmp(&lhs.optionalHeader, &rhs.optionalHeader, sizeof(executable::Header::optionalHeader)) != 0) { return false; } return true; } }; } #endif // LC_VERSION