diff options
Diffstat (limited to 'src/inc/pedecoder.h')
-rw-r--r-- | src/inc/pedecoder.h | 478 |
1 files changed, 478 insertions, 0 deletions
diff --git a/src/inc/pedecoder.h b/src/inc/pedecoder.h new file mode 100644 index 0000000000..d5bae87bb7 --- /dev/null +++ b/src/inc/pedecoder.h @@ -0,0 +1,478 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// -------------------------------------------------------------------------------- +// PEDecoder.h +// + +// -------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------- +// PEDecoder - Utility class for reading and verifying PE files. +// +// Note that the Check step is optional if you are willing to trust the +// integrity of the image. +// (Or at any rate can be factored into an initial verification step.) +// +// Functions which access the memory of the PE file take a "flat" flag - this +// indicates whether the PE images data has been loaded flat the way it resides in the file, +// or if the sections have been mapped into memory at the proper base addresses. +// +// Finally, some functions take an optional "size" argument, which can be used for +// range verification. This is an optional parameter, but if you omit it be sure +// you verify the size in some other way. +// -------------------------------------------------------------------------------- + + +#ifndef PEDECODER_H_ +#define PEDECODER_H_ + +// -------------------------------------------------------------------------------- +// Required headers +// -------------------------------------------------------------------------------- + +#include "windows.h" +#include "clrtypes.h" +#include "check.h" +#include "contract.h" +#include "cor.h" +#include "corhdr.h" + +#ifdef FEATURE_PREJIT +#include "corcompile.h" +#else // FEATURE_PREJIT +typedef DPTR(struct COR_ILMETHOD) PTR_COR_ILMETHOD; +struct CORCOMPILE_HEADER { int dummy_field; }; +typedef DPTR(struct CORCOMPILE_HEADER) PTR_CORCOMPILE_HEADER; +#define CORCOMPILE_IS_POINTER_TAGGED(fixup) (false) +#endif // FEATURE_PREJIT + +#include "readytorun.h" +typedef DPTR(struct READYTORUN_HEADER) PTR_READYTORUN_HEADER; + +typedef DPTR(IMAGE_COR20_HEADER) PTR_IMAGE_COR20_HEADER; + +// -------------------------------------------------------------------------------- +// Forward declared types +// -------------------------------------------------------------------------------- + +class Module; + +// -------------------------------------------------------------------------------- +// RVA definition +// -------------------------------------------------------------------------------- + +// Needs to be DWORD to avoid conflict with <imagehlp.h> +typedef DWORD RVA; + +#ifdef _MSC_VER +// Wrapper to suppress ambigous overload problems with MSVC. +inline CHECK CheckOverflow(RVA value1, COUNT_T value2) +{ + WRAPPER_NO_CONTRACT; + CHECK(CheckOverflow((UINT32) value1, (UINT32) value2)); + CHECK_OK; +} +#endif // _MSC_VER + +// -------------------------------------------------------------------------------- +// IMAGE_FILE_MACHINE_NATIVE +// -------------------------------------------------------------------------------- + +#if defined(_TARGET_X86_) +#define IMAGE_FILE_MACHINE_NATIVE IMAGE_FILE_MACHINE_I386 +#elif defined(_TARGET_AMD64_) +#define IMAGE_FILE_MACHINE_NATIVE IMAGE_FILE_MACHINE_AMD64 +#elif defined(_TARGET_ARM_) +#define IMAGE_FILE_MACHINE_NATIVE IMAGE_FILE_MACHINE_ARMNT +#elif defined(_TARGET_ARM64_) +#define IMAGE_FILE_MACHINE_NATIVE IMAGE_FILE_MACHINE_ARM64 +#else +#error "port me" +#endif + +// Machine code for native images +#if defined(__APPLE__) +#define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0x4644 +#elif defined(__FreeBSD__) +#define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0xADC4 +#elif defined(__linux__) +#define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0x7B79 +#elif defined(__NetBSD__) +#define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0x1993 +#else +#define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0 +#endif + +#define IMAGE_FILE_MACHINE_NATIVE_NI (IMAGE_FILE_MACHINE_NATIVE ^ IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE) + +// -------------------------------------------------------------------------------- +// Types +// -------------------------------------------------------------------------------- + +typedef DPTR(class PEDecoder) PTR_PEDecoder; + +class PEDecoder +{ + public: + + // ------------------------------------------------------------ + // Public API + // ------------------------------------------------------------ + + // Access functions are divided into 3 categories: + // Has - check if the element is present + // Check - Do consistency checks on the element (requires Has). + // This step is optional if you are willing to trust the integrity of the + // image. (It is asserted in a checked build.) + // Get - Access the element (requires Has and Check) + + PEDecoder(); + PEDecoder(void *flatBase, COUNT_T size); // flatBase is the raw disk layout data (using MapViewOfFile) + PEDecoder(PTR_VOID mappedBase, bool relocated = FALSE); // mappedBase is the mapped/expanded file (using LoadLibrary) + + void Init(void *flatBase, COUNT_T size); + HRESULT Init(void *mappedBase, bool relocated = FALSE); + void Reset(); //make sure you don't have a thread race + + PTR_VOID GetBase() const; // Currently loaded base, as opposed to GetPreferredBase() + BOOL IsMapped() const; + BOOL IsRelocated() const; + BOOL IsFlat() const; + BOOL HasContents() const; + COUNT_T GetSize() const; // size of file on disk, as opposed to GetVirtualSize() + + // High level image checks: + + CHECK CheckFormat() const; // Check whatever is present + CHECK CheckNTFormat() const; // Check a PE file image + CHECK CheckCORFormat() const; // Check a COR image (IL or native) + CHECK CheckILFormat() const; // Check a managed image + CHECK CheckILOnlyFormat() const; // Check an IL only image + CHECK CheckNativeFormat() const; // Check a native image + + // NT header access + + BOOL HasNTHeaders() const; + CHECK CheckNTHeaders() const; + + IMAGE_NT_HEADERS32 *GetNTHeaders32() const; + IMAGE_NT_HEADERS64 *GetNTHeaders64() const; + BOOL Has32BitNTHeaders() const; + + const void *GetHeaders(COUNT_T *pSize = NULL) const; + + BOOL IsDll() const; + BOOL HasBaseRelocations() const; + const void *GetPreferredBase() const; // OptionalHeaders.ImageBase + COUNT_T GetVirtualSize() const; // OptionalHeaders.SizeOfImage - size of mapped/expanded image in memory + WORD GetSubsystem() const; + WORD GetDllCharacteristics() const; + DWORD GetTimeDateStamp() const; + DWORD GetCheckSum() const; + WORD GetMachine() const; + WORD GetCharacteristics() const; + DWORD GetFileAlignment() const; + DWORD GetSectionAlignment() const; + SIZE_T GetSizeOfStackReserve() const; + SIZE_T GetSizeOfStackCommit() const; + SIZE_T GetSizeOfHeapReserve() const; + SIZE_T GetSizeOfHeapCommit() const; + UINT32 GetLoaderFlags() const; + UINT32 GetWin32VersionValue() const; + COUNT_T GetNumberOfRvaAndSizes() const; + COUNT_T GetNumberOfSections() const; + IMAGE_SECTION_HEADER *FindFirstSection() const; + IMAGE_SECTION_HEADER *FindSection(LPCSTR sectionName) const; + + DWORD GetImageIdentity() const; + + // Directory entry access + + BOOL HasDirectoryEntry(int entry) const; + CHECK CheckDirectoryEntry(int entry, int forbiddenFlags = 0, IsNullOK ok = NULL_NOT_OK) const; + IMAGE_DATA_DIRECTORY *GetDirectoryEntry(int entry) const; + TADDR GetDirectoryEntryData(int entry, COUNT_T *pSize = NULL) const; + + // IMAGE_DATA_DIRECTORY access + + CHECK CheckDirectory(IMAGE_DATA_DIRECTORY *pDir, int forbiddenFlags = 0, IsNullOK ok = NULL_NOT_OK) const; + TADDR GetDirectoryData(IMAGE_DATA_DIRECTORY *pDir) const; + TADDR GetDirectoryData(IMAGE_DATA_DIRECTORY *pDir, COUNT_T *pSize) const; + + // Basic RVA access + + CHECK CheckRva(RVA rva, IsNullOK ok = NULL_NOT_OK) const; + CHECK CheckRva(RVA rva, COUNT_T size, int forbiddenFlags=0, IsNullOK ok = NULL_NOT_OK) const; + TADDR GetRvaData(RVA rva, IsNullOK ok = NULL_NOT_OK) const; + // Called with ok=NULL_OK only for mapped fields (RVA statics) + + CHECK CheckData(const void *data, IsNullOK ok = NULL_NOT_OK) const; + CHECK CheckData(const void *data, COUNT_T size, IsNullOK ok = NULL_NOT_OK) const; + RVA GetDataRva(const TADDR data) const; + BOOL PointerInPE(PTR_CVOID data) const; + + // Flat mapping utilities - using PointerToRawData instead of (Relative)VirtualAddress + CHECK CheckOffset(COUNT_T fileOffset, IsNullOK ok = NULL_NOT_OK) const; + CHECK CheckOffset(COUNT_T fileOffset, COUNT_T size, IsNullOK ok = NULL_NOT_OK) const; + TADDR GetOffsetData(COUNT_T fileOffset, IsNullOK ok = NULL_NOT_OK) const; + // Called with ok=NULL_OK only for mapped fields (RVA statics) + + // Mapping between RVA and file offsets + COUNT_T RvaToOffset(RVA rva) const; + RVA OffsetToRva(COUNT_T fileOffset) const; + + // Base intra-image pointer access + // (These are for pointers retrieved out of the PE image) + + CHECK CheckInternalAddress(SIZE_T address, IsNullOK ok = NULL_NOT_OK) const; + CHECK CheckInternalAddress(SIZE_T address, COUNT_T size, IsNullOK ok = NULL_NOT_OK) const; + TADDR GetInternalAddressData(SIZE_T address) const; + + // CLR loader IL Image verification - these checks apply to IL_ONLY images. + + BOOL IsILOnly() const; + CHECK CheckILOnly() const; + + void LayoutILOnly(void *base, BOOL allowFullPE = FALSE) const; + + // Strong name & hashing support + + BOOL HasStrongNameSignature() const; + CHECK CheckStrongNameSignature() const; + PTR_CVOID GetStrongNameSignature(COUNT_T *pSize = NULL) const; + + // CorHeader flag support + + // IsStrongNameSigned indicates whether the signature has been filled in. + // (otherwise if it has a signature it is delay signed.) + BOOL IsStrongNameSigned() const; // TRUE if the COMIMAGE_FLAGS_STRONGNAMESIGNED flag is set + + // TLS + + BOOL HasTls() const; + CHECK CheckTls() const; + PTR_VOID GetTlsRange(COUNT_T *pSize = NULL) const; + UINT32 GetTlsIndex() const; + +#ifndef FEATURE_PAL + // Win32 resources + void *GetWin32Resource(LPCWSTR lpName, LPCWSTR lpType, COUNT_T *pSize = NULL) const; +#endif // FEATURE_PAL + + // COR header fields + + BOOL HasCorHeader() const; + CHECK CheckCorHeader() const; + IMAGE_COR20_HEADER *GetCorHeader() const; + + PTR_CVOID GetMetadata(COUNT_T *pSize = NULL) const; + + const void *GetResources(COUNT_T *pSize = NULL) const; + CHECK CheckResource(COUNT_T offset) const; + const void *GetResource(COUNT_T offset, COUNT_T *pSize = NULL) const; + + BOOL HasManagedEntryPoint() const; + ULONG GetEntryPointToken() const; + IMAGE_COR_VTABLEFIXUP *GetVTableFixups(COUNT_T *pCount = NULL) const; + + // Native header access + BOOL HasNativeHeader() const; + CHECK CheckNativeHeader() const; + CORCOMPILE_HEADER *GetNativeHeader() const; + BOOL IsNativeMachineFormat() const; + BOOL IsI386() const; + + void GetPEKindAndMachine(DWORD * pdwPEKind, DWORD *pdwMachine); // Returns CorPEKind flags + BOOL IsPlatformNeutral(); // Returns TRUE for IL-only platform neutral images + + // + // Verifies that the IL is within the bounds of the image. + // + CHECK CheckILMethod(RVA rva); + + // + // Compute size of IL blob. Assumes that the IL is within the bounds of the image - make sure + // to call CheckILMethod before calling this method. + // + static SIZE_T ComputeILMethodSize(TADDR pIL); + + // Debug directory access, returns NULL if no such entry + PTR_IMAGE_DEBUG_DIRECTORY GetDebugDirectoryEntry(UINT index) const; + +#ifdef FEATURE_PREJIT + CHECK CheckNativeHeaderVersion() const; + + // ManagedNative fields + CORCOMPILE_CODE_MANAGER_ENTRY *GetNativeCodeManagerTable() const; + CORCOMPILE_EE_INFO_TABLE *GetNativeEEInfoTable() const; + void *GetNativeHelperTable(COUNT_T *pSize = NULL) const; + CORCOMPILE_VERSION_INFO *GetNativeVersionInfo() const; + CORCOMPILE_VERSION_INFO *GetNativeVersionInfoMaybeNull(bool skipCheckNativeHeader = false) const; + BOOL HasNativeDebugMap() const; + TADDR GetNativeDebugMap(COUNT_T *pSize = NULL) const; + Module *GetPersistedModuleImage(COUNT_T *pSize = NULL) const; + PCODE GetNativeHotCode(COUNT_T * pSize = NULL) const; + PCODE GetNativeCode(COUNT_T * pSize = NULL) const; + PCODE GetNativeColdCode(COUNT_T * pSize = NULL) const; + + CORCOMPILE_METHOD_PROFILE_LIST *GetNativeProfileDataList(COUNT_T *pSize = NULL) const; + PTR_CVOID GetNativeManifestMetadata(COUNT_T *pSize = NULL) const; + const void *GetNativePreferredBase() const; + BOOL GetNativeILHasSecurityDirectory() const; + BOOL GetNativeILIsIbcOptimized() const; + BOOL GetNativeILHasReadyToRunHeader() const; + BOOL IsNativeILILOnly() const; + BOOL IsNativeILDll() const; + void GetNativeILPEKindAndMachine(DWORD* pdwKind, DWORD* pdwMachine) const; + CORCOMPILE_DEPENDENCY * GetNativeDependencies(COUNT_T *pCount = NULL) const; + + COUNT_T GetNativeImportTableCount() const; + CORCOMPILE_IMPORT_TABLE_ENTRY *GetNativeImportFromIndex(COUNT_T index) const; + CHECK CheckNativeImportFromIndex(COUNT_T index) const; + + PTR_CORCOMPILE_IMPORT_SECTION GetNativeImportSections(COUNT_T *pCount = NULL) const; + PTR_CORCOMPILE_IMPORT_SECTION GetNativeImportSectionFromIndex(COUNT_T index) const; + PTR_CORCOMPILE_IMPORT_SECTION GetNativeImportSectionForRVA(RVA rva) const; + + TADDR GetStubsTable(COUNT_T *pSize = NULL) const; + TADDR GetVirtualSectionsTable(COUNT_T *pSize = NULL) const; +#endif // FEATURE_PREJIT + + BOOL HasReadyToRunHeader() const; + READYTORUN_HEADER *GetReadyToRunHeader() const; + + void GetEXEStackSizes(SIZE_T *PE_SizeOfStackReserve, SIZE_T *PE_SizeOfStackCommit) const; + + CHECK CheckWillCreateGuardPage() const; + + // Native DLLMain Entrypoint + BOOL HasNativeEntryPoint() const; + void *GetNativeEntryPoint() const; + +#ifdef _DEBUG + // Stress mode for relocations + static BOOL GetForceRelocs(); + static BOOL ForceRelocForDLL(LPCWSTR lpFileName); +#endif + +#ifdef DACCESS_COMPILE + void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, bool enumThis); +#endif + + protected: + + // ------------------------------------------------------------ + // Protected API for subclass use + // ------------------------------------------------------------ + + // Checking utilites + static CHECK CheckBounds(RVA rangeBase, COUNT_T rangeSize, RVA rva); + static CHECK CheckBounds(RVA rangeBase, COUNT_T rangeSize, RVA rva, COUNT_T size); + + static CHECK CheckBounds(const void *rangeBase, COUNT_T rangeSize, const void *pointer); + static CHECK CheckBounds(PTR_CVOID rangeBase, COUNT_T rangeSize, PTR_CVOID pointer, COUNT_T size); + + protected: + + // Flat mapping utilities - using PointerToRawData instead of (Relative)VirtualAddress + IMAGE_SECTION_HEADER *RvaToSection(RVA rva) const; + IMAGE_SECTION_HEADER *OffsetToSection(COUNT_T fileOffset) const; + + void SetRelocated(); + + private: + + // ------------------------------------------------------------ + // Internal functions + // ------------------------------------------------------------ + + enum METADATA_SECTION_TYPE + { + METADATA_SECTION_FULL, +#ifdef FEATURE_PREJIT + METADATA_SECTION_MANIFEST +#endif + }; + + IMAGE_DATA_DIRECTORY *GetMetaDataHelper(METADATA_SECTION_TYPE type) const; + + static PTR_IMAGE_SECTION_HEADER FindFirstSection(IMAGE_NT_HEADERS * pNTHeaders); + + IMAGE_NT_HEADERS *FindNTHeaders() const; + IMAGE_COR20_HEADER *FindCorHeader() const; + CORCOMPILE_HEADER *FindNativeHeader() const; + READYTORUN_HEADER *FindReadyToRunHeader() const; + + // Flat mapping utilities + RVA InternalAddressToRva(SIZE_T address) const; + + // NT header subchecks + CHECK CheckSection(COUNT_T previousAddressEnd, COUNT_T addressStart, COUNT_T addressSize, + COUNT_T previousOffsetEnd, COUNT_T offsetStart, COUNT_T offsetSize) const; + + // Pure managed subchecks + CHECK CheckILOnlyImportDlls() const; + CHECK CheckILOnlyImportByNameTable(RVA rva) const; + CHECK CheckILOnlyBaseRelocations() const; + CHECK CheckILOnlyEntryPoint() const; + + // ------------------------------------------------------------ + // Instance members + // ------------------------------------------------------------ + + enum + { + FLAG_MAPPED = 0x01, // the file is mapped/hydrated (vs. the raw disk layout) + FLAG_CONTENTS = 0x02, // the file has contents + FLAG_RELOCATED = 0x04, // relocs have been applied + FLAG_NT_CHECKED = 0x10, + FLAG_COR_CHECKED = 0x20, + FLAG_IL_ONLY_CHECKED = 0x40, + FLAG_NATIVE_CHECKED = 0x80, + + FLAG_HAS_NO_READYTORUN_HEADER = 0x100, + }; + + TADDR m_base; + COUNT_T m_size; // size of file on disk, as opposed to OptionalHeaders.SizeOfImage + ULONG m_flags; + + PTR_IMAGE_NT_HEADERS m_pNTHeaders; + PTR_IMAGE_COR20_HEADER m_pCorHeader; + PTR_CORCOMPILE_HEADER m_pNativeHeader; + PTR_READYTORUN_HEADER m_pReadyToRunHeader; +}; + +// +// MethodSectionIterator class is used to iterate hot (or) cold method section in an ngen image. +// It can also iterate nibble maps generated by the JIT in a regular HeapList. +// +class MethodSectionIterator +{ + private: + PTR_DWORD m_codeTableStart; + PTR_DWORD m_codeTable; + PTR_DWORD m_codeTableEnd; + + BYTE *m_code; + + DWORD m_dword; + DWORD m_index; + + BYTE *m_current; + + public: + + //If code is a target pointer, then GetMethodCode and FindMethodCode return + //target pointers. codeTable may be a pointer of either type, since it is + //converted internally into a host pointer. + MethodSectionIterator(const void *code, SIZE_T codeSize, + const void *codeTable, SIZE_T codeTableSize); + BOOL Next(); + BYTE *GetMethodCode() { return m_current; } // Get the start of method code of the current method in the iterator +}; + +#include "pedecoder.inl" + +#endif // PEDECODER_H_ |