| 1 | // Licensed to the .NET Foundation under one or more agreements. |
| 2 | // The .NET Foundation licenses this file to you under the MIT license. |
| 3 | // See the LICENSE file in the project root for more information. |
| 4 | |
| 5 | #include "stdafx.h" |
| 6 | |
| 7 | #include <windows.h> |
| 8 | #include <corhdr.h> |
| 9 | #include "corerror.h" |
| 10 | #include "pedecoder.h" |
| 11 | |
| 12 | |
| 13 | static const char g_szCORMETA[] = ".cormeta" ; |
| 14 | |
| 15 | |
| 16 | HRESULT CLiteWeightStgdbRW::FindImageMetaData(PVOID pImage, DWORD dwFileLength, BOOL bMappedImage, PVOID *ppMetaData, ULONG *pcbMetaData) |
| 17 | { |
| 18 | #ifndef DACCESS_COMPILE |
| 19 | PEDecoder pe; |
| 20 | |
| 21 | // We need to use different PEDecoder initialization based on the type of data we give it. |
| 22 | // We use the one with a 'bool' as the second argument when dealing with a mapped file, |
| 23 | // and we use the one that takes a COUNT_T as the second argument when dealing with a |
| 24 | // flat file. |
| 25 | if (bMappedImage) |
| 26 | { |
| 27 | if (FAILED(pe.Init(pImage, false)) || |
| 28 | !pe.CheckNTHeaders()) |
| 29 | { |
| 30 | return COR_E_BADIMAGEFORMAT; |
| 31 | } |
| 32 | } |
| 33 | else |
| 34 | { |
| 35 | pe.Init(pImage, (COUNT_T)dwFileLength); |
| 36 | } |
| 37 | |
| 38 | // Minimally validate image |
| 39 | if (!pe.CheckCorHeader()) |
| 40 | return COR_E_BADIMAGEFORMAT; |
| 41 | |
| 42 | |
| 43 | COUNT_T size = 0; |
| 44 | |
| 45 | *ppMetaData = (void *)pe.GetMetadata(&size); |
| 46 | |
| 47 | // Couldn't find any IL metadata in this image |
| 48 | if (*ppMetaData == NULL) |
| 49 | return CLDB_E_NO_DATA; |
| 50 | |
| 51 | if (pcbMetaData != NULL) |
| 52 | *pcbMetaData = size; |
| 53 | |
| 54 | return S_OK; |
| 55 | #else |
| 56 | DacNotImpl(); |
| 57 | return E_NOTIMPL; |
| 58 | #endif |
| 59 | } // CLiteWeightStgdbRW::FindImageMetaData |
| 60 | |
| 61 | // |
| 62 | // Note: Remove once defined in winnt.h |
| 63 | // |
| 64 | typedef struct { |
| 65 | WORD ; // Must be IMAGE_FILE_MACHINE_UNKNOWN |
| 66 | WORD ; // Must be 0xffff |
| 67 | WORD ; // >= 2 (implies the CLSID field, Flags and metadata info are present) |
| 68 | WORD ; |
| 69 | DWORD ; |
| 70 | CLSID ; // Used to invoke CoCreateInstance |
| 71 | DWORD ; // Size of data that follows the header |
| 72 | DWORD ; |
| 73 | DWORD ; // Size of CLR metadata |
| 74 | DWORD ; // Offset of CLR metadata |
| 75 | } ; |
| 76 | |
| 77 | #define ANON_OBJECT_HAS_CORMETA 0x00000001 |
| 78 | #define ANON_OBJECT_IS_PUREMSIL 0x00000002 |
| 79 | |
| 80 | HRESULT CLiteWeightStgdbRW::FindObjMetaData(PVOID pImage, DWORD dwFileLength, PVOID *ppMetaData, ULONG *pcbMetaData) |
| 81 | { |
| 82 | DWORD dwSize = 0; |
| 83 | DWORD dwOffset = 0; |
| 84 | |
| 85 | ANON_OBJECT_HEADER2 *pAnonImageHdr = (ANON_OBJECT_HEADER2 *) pImage; // Anonymous object header |
| 86 | |
| 87 | // Check to see if this is a LTCG object |
| 88 | if (dwFileLength >= sizeof(ANON_OBJECT_HEADER2) && |
| 89 | pAnonImageHdr->Sig1 == VAL16(IMAGE_FILE_MACHINE_UNKNOWN) && |
| 90 | pAnonImageHdr->Sig2 == VAL16(IMPORT_OBJECT_HDR_SIG2)) |
| 91 | { |
| 92 | // Version 1 anonymous objects don't have metadata info |
| 93 | if (VAL16(pAnonImageHdr->Version) < 2) |
| 94 | goto BadFormat; |
| 95 | |
| 96 | // Anonymous objects contain the metadata info in the header |
| 97 | dwOffset = VAL32(pAnonImageHdr->MetaDataOffset); |
| 98 | dwSize = VAL32(pAnonImageHdr->MetaDataSize); |
| 99 | } |
| 100 | else |
| 101 | { |
| 102 | // Check to see if we have enough data |
| 103 | if (dwFileLength < sizeof(IMAGE_FILE_HEADER)) |
| 104 | goto BadFormat; |
| 105 | |
| 106 | IMAGE_FILE_HEADER *pImageHdr = (IMAGE_FILE_HEADER *) pImage; // Header for the .obj file. |
| 107 | |
| 108 | // Walk each section looking for .cormeta. |
| 109 | DWORD nSections = VAL16(pImageHdr->NumberOfSections); |
| 110 | |
| 111 | // Check to see if we have enough data |
| 112 | S_UINT32 nSectionsSize = S_UINT32(sizeof(IMAGE_FILE_HEADER)) + S_UINT32(nSections) * S_UINT32(sizeof(IMAGE_SECTION_HEADER)); |
| 113 | if (nSectionsSize.IsOverflow() || (dwFileLength < nSectionsSize.Value())) |
| 114 | goto BadFormat; |
| 115 | |
| 116 | IMAGE_SECTION_HEADER *pSectionHdr = (IMAGE_SECTION_HEADER *)(pImageHdr + 1); // Section header. |
| 117 | |
| 118 | for (DWORD i=0; i<nSections; i++, pSectionHdr++) |
| 119 | { |
| 120 | // Simple comparison to section name. |
| 121 | if (memcmp((const char *) pSectionHdr->Name, g_szCORMETA, sizeof(pSectionHdr->Name)) == 0) |
| 122 | { |
| 123 | dwOffset = VAL32(pSectionHdr->PointerToRawData); |
| 124 | dwSize = VAL32(pSectionHdr->SizeOfRawData); |
| 125 | break; |
| 126 | } |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | if (dwOffset == 0 || dwSize == 0) |
| 131 | goto BadFormat; |
| 132 | |
| 133 | // Check that raw data in the section is actually within the file. |
| 134 | { |
| 135 | S_UINT32 dwEndOffset = S_UINT32(dwOffset) + S_UINT32(dwSize); |
| 136 | if ((dwOffset >= dwFileLength) || dwEndOffset.IsOverflow() || (dwEndOffset.Value() > dwFileLength)) |
| 137 | goto BadFormat; |
| 138 | } |
| 139 | |
| 140 | *ppMetaData = (PVOID) ((ULONG_PTR) pImage + dwOffset); |
| 141 | *pcbMetaData = dwSize; |
| 142 | return (S_OK); |
| 143 | |
| 144 | BadFormat: |
| 145 | *ppMetaData = NULL; |
| 146 | *pcbMetaData = 0; |
| 147 | return (COR_E_BADIMAGEFORMAT); |
| 148 | } |
| 149 | |