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 | |