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
13static const char g_szCORMETA[] = ".cormeta";
14
15
16HRESULT 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//
64typedef struct ANON_OBJECT_HEADER2 {
65 WORD Sig1; // Must be IMAGE_FILE_MACHINE_UNKNOWN
66 WORD Sig2; // Must be 0xffff
67 WORD Version; // >= 2 (implies the CLSID field, Flags and metadata info are present)
68 WORD Machine;
69 DWORD TimeDateStamp;
70 CLSID ClassID; // Used to invoke CoCreateInstance
71 DWORD SizeOfData; // Size of data that follows the header
72 DWORD Flags;
73 DWORD MetaDataSize; // Size of CLR metadata
74 DWORD MetaDataOffset; // Offset of CLR metadata
75} ANON_OBJECT_HEADER2;
76
77#define ANON_OBJECT_HAS_CORMETA 0x00000001
78#define ANON_OBJECT_IS_PUREMSIL 0x00000002
79
80HRESULT 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
144BadFormat:
145 *ppMetaData = NULL;
146 *pcbMetaData = 0;
147 return (COR_E_BADIMAGEFORMAT);
148}
149