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 | // PEDecoder.h |
6 | // |
7 | |
8 | // -------------------------------------------------------------------------------- |
9 | |
10 | // -------------------------------------------------------------------------------- |
11 | // PEDecoder - Utility class for reading and verifying PE files. |
12 | // |
13 | // Note that the Check step is optional if you are willing to trust the |
14 | // integrity of the image. |
15 | // (Or at any rate can be factored into an initial verification step.) |
16 | // |
17 | // Functions which access the memory of the PE file take a "flat" flag - this |
18 | // indicates whether the PE images data has been loaded flat the way it resides in the file, |
19 | // or if the sections have been mapped into memory at the proper base addresses. |
20 | // |
21 | // Finally, some functions take an optional "size" argument, which can be used for |
22 | // range verification. This is an optional parameter, but if you omit it be sure |
23 | // you verify the size in some other way. |
24 | // -------------------------------------------------------------------------------- |
25 | |
26 | |
27 | #ifndef PEDECODER_H_ |
28 | #define PEDECODER_H_ |
29 | |
30 | // -------------------------------------------------------------------------------- |
31 | // Required headers |
32 | // -------------------------------------------------------------------------------- |
33 | |
34 | #include "windows.h" |
35 | #include "clrtypes.h" |
36 | #include "check.h" |
37 | #include "contract.h" |
38 | #include "cor.h" |
39 | #include "corhdr.h" |
40 | |
41 | #ifdef FEATURE_PREJIT |
42 | #include "corcompile.h" |
43 | #else // FEATURE_PREJIT |
44 | typedef DPTR(struct COR_ILMETHOD) PTR_COR_ILMETHOD; |
45 | struct CORCOMPILE_HEADER { int dummy_field; }; |
46 | typedef DPTR(struct CORCOMPILE_HEADER) PTR_CORCOMPILE_HEADER; |
47 | #define CORCOMPILE_IS_POINTER_TAGGED(fixup) (false) |
48 | #endif // FEATURE_PREJIT |
49 | |
50 | #include "readytorun.h" |
51 | typedef DPTR(struct READYTORUN_HEADER) ; |
52 | |
53 | typedef DPTR(IMAGE_COR20_HEADER) ; |
54 | |
55 | // -------------------------------------------------------------------------------- |
56 | // Forward declared types |
57 | // -------------------------------------------------------------------------------- |
58 | |
59 | class Module; |
60 | |
61 | // -------------------------------------------------------------------------------- |
62 | // RVA definition |
63 | // -------------------------------------------------------------------------------- |
64 | |
65 | // Needs to be DWORD to avoid conflict with <imagehlp.h> |
66 | typedef DWORD RVA; |
67 | |
68 | #ifdef _MSC_VER |
69 | // Wrapper to suppress ambigous overload problems with MSVC. |
70 | inline CHECK CheckOverflow(RVA value1, COUNT_T value2) |
71 | { |
72 | WRAPPER_NO_CONTRACT; |
73 | CHECK(CheckOverflow((UINT32) value1, (UINT32) value2)); |
74 | CHECK_OK; |
75 | } |
76 | #endif // _MSC_VER |
77 | |
78 | // -------------------------------------------------------------------------------- |
79 | // IMAGE_FILE_MACHINE_NATIVE |
80 | // -------------------------------------------------------------------------------- |
81 | |
82 | #if defined(_TARGET_X86_) |
83 | #define IMAGE_FILE_MACHINE_NATIVE IMAGE_FILE_MACHINE_I386 |
84 | #elif defined(_TARGET_AMD64_) |
85 | #define IMAGE_FILE_MACHINE_NATIVE IMAGE_FILE_MACHINE_AMD64 |
86 | #elif defined(_TARGET_ARM_) |
87 | #define IMAGE_FILE_MACHINE_NATIVE IMAGE_FILE_MACHINE_ARMNT |
88 | #elif defined(_TARGET_ARM64_) |
89 | #define IMAGE_FILE_MACHINE_NATIVE IMAGE_FILE_MACHINE_ARM64 |
90 | #else |
91 | #error "port me" |
92 | #endif |
93 | |
94 | // Machine code for native images |
95 | #if defined(__APPLE__) |
96 | #define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0x4644 |
97 | #elif defined(__FreeBSD__) |
98 | #define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0xADC4 |
99 | #elif defined(__linux__) |
100 | #define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0x7B79 |
101 | #elif defined(__NetBSD__) |
102 | #define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0x1993 |
103 | #else |
104 | #define IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE 0 |
105 | #endif |
106 | |
107 | #define IMAGE_FILE_MACHINE_NATIVE_NI (IMAGE_FILE_MACHINE_NATIVE ^ IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE) |
108 | |
109 | // -------------------------------------------------------------------------------- |
110 | // Types |
111 | // -------------------------------------------------------------------------------- |
112 | |
113 | typedef DPTR(class PEDecoder) PTR_PEDecoder; |
114 | |
115 | class PEDecoder |
116 | { |
117 | public: |
118 | |
119 | // ------------------------------------------------------------ |
120 | // Public API |
121 | // ------------------------------------------------------------ |
122 | |
123 | // Access functions are divided into 3 categories: |
124 | // Has - check if the element is present |
125 | // Check - Do consistency checks on the element (requires Has). |
126 | // This step is optional if you are willing to trust the integrity of the |
127 | // image. (It is asserted in a checked build.) |
128 | // Get - Access the element (requires Has and Check) |
129 | |
130 | PEDecoder(); |
131 | PEDecoder(void *flatBase, COUNT_T size); // flatBase is the raw disk layout data (using MapViewOfFile) |
132 | PEDecoder(PTR_VOID mappedBase, bool relocated = FALSE); // mappedBase is the mapped/expanded file (using LoadLibrary) |
133 | |
134 | void Init(void *flatBase, COUNT_T size); |
135 | HRESULT Init(void *mappedBase, bool relocated = FALSE); |
136 | void Reset(); //make sure you don't have a thread race |
137 | |
138 | PTR_VOID GetBase() const; // Currently loaded base, as opposed to GetPreferredBase() |
139 | BOOL IsMapped() const; |
140 | BOOL IsRelocated() const; |
141 | BOOL IsFlat() const; |
142 | BOOL HasContents() const; |
143 | COUNT_T GetSize() const; // size of file on disk, as opposed to GetVirtualSize() |
144 | |
145 | // High level image checks: |
146 | |
147 | CHECK CheckFormat() const; // Check whatever is present |
148 | CHECK CheckNTFormat() const; // Check a PE file image |
149 | CHECK CheckCORFormat() const; // Check a COR image (IL or native) |
150 | CHECK CheckILFormat() const; // Check a managed image |
151 | CHECK CheckILOnlyFormat() const; // Check an IL only image |
152 | CHECK CheckNativeFormat() const; // Check a native image |
153 | |
154 | // NT header access |
155 | |
156 | BOOL () const; |
157 | CHECK () const; |
158 | |
159 | IMAGE_NT_HEADERS32 *() const; |
160 | IMAGE_NT_HEADERS64 *() const; |
161 | BOOL () const; |
162 | |
163 | const void *(COUNT_T *pSize = NULL) const; |
164 | |
165 | BOOL IsDll() const; |
166 | BOOL HasBaseRelocations() const; |
167 | const void *GetPreferredBase() const; // OptionalHeaders.ImageBase |
168 | COUNT_T GetVirtualSize() const; // OptionalHeaders.SizeOfImage - size of mapped/expanded image in memory |
169 | WORD GetSubsystem() const; |
170 | WORD GetDllCharacteristics() const; |
171 | DWORD GetTimeDateStamp() const; |
172 | DWORD GetCheckSum() const; |
173 | WORD GetMachine() const; |
174 | WORD GetCharacteristics() const; |
175 | DWORD GetFileAlignment() const; |
176 | DWORD GetSectionAlignment() const; |
177 | SIZE_T GetSizeOfStackReserve() const; |
178 | SIZE_T GetSizeOfStackCommit() const; |
179 | SIZE_T GetSizeOfHeapReserve() const; |
180 | SIZE_T GetSizeOfHeapCommit() const; |
181 | UINT32 GetLoaderFlags() const; |
182 | UINT32 GetWin32VersionValue() const; |
183 | COUNT_T GetNumberOfRvaAndSizes() const; |
184 | COUNT_T GetNumberOfSections() const; |
185 | PTR_IMAGE_SECTION_HEADER FindFirstSection() const; |
186 | IMAGE_SECTION_HEADER *FindSection(LPCSTR sectionName) const; |
187 | |
188 | DWORD GetImageIdentity() const; |
189 | |
190 | BOOL HasWriteableSections() const; |
191 | |
192 | // Directory entry access |
193 | |
194 | BOOL HasDirectoryEntry(int entry) const; |
195 | CHECK CheckDirectoryEntry(int entry, int forbiddenFlags = 0, IsNullOK ok = NULL_NOT_OK) const; |
196 | IMAGE_DATA_DIRECTORY *GetDirectoryEntry(int entry) const; |
197 | TADDR GetDirectoryEntryData(int entry, COUNT_T *pSize = NULL) const; |
198 | |
199 | // IMAGE_DATA_DIRECTORY access |
200 | |
201 | CHECK CheckDirectory(IMAGE_DATA_DIRECTORY *pDir, int forbiddenFlags = 0, IsNullOK ok = NULL_NOT_OK) const; |
202 | TADDR GetDirectoryData(IMAGE_DATA_DIRECTORY *pDir) const; |
203 | TADDR GetDirectoryData(IMAGE_DATA_DIRECTORY *pDir, COUNT_T *pSize) const; |
204 | |
205 | // Basic RVA access |
206 | |
207 | CHECK CheckRva(RVA rva, IsNullOK ok = NULL_NOT_OK) const; |
208 | CHECK CheckRva(RVA rva, COUNT_T size, int forbiddenFlags=0, IsNullOK ok = NULL_NOT_OK) const; |
209 | TADDR GetRvaData(RVA rva, IsNullOK ok = NULL_NOT_OK) const; |
210 | // Called with ok=NULL_OK only for mapped fields (RVA statics) |
211 | |
212 | CHECK CheckData(const void *data, IsNullOK ok = NULL_NOT_OK) const; |
213 | CHECK CheckData(const void *data, COUNT_T size, IsNullOK ok = NULL_NOT_OK) const; |
214 | RVA GetDataRva(const TADDR data) const; |
215 | BOOL PointerInPE(PTR_CVOID data) const; |
216 | |
217 | // Flat mapping utilities - using PointerToRawData instead of (Relative)VirtualAddress |
218 | CHECK CheckOffset(COUNT_T fileOffset, IsNullOK ok = NULL_NOT_OK) const; |
219 | CHECK CheckOffset(COUNT_T fileOffset, COUNT_T size, IsNullOK ok = NULL_NOT_OK) const; |
220 | TADDR GetOffsetData(COUNT_T fileOffset, IsNullOK ok = NULL_NOT_OK) const; |
221 | // Called with ok=NULL_OK only for mapped fields (RVA statics) |
222 | |
223 | // Mapping between RVA and file offsets |
224 | COUNT_T RvaToOffset(RVA rva) const; |
225 | RVA OffsetToRva(COUNT_T fileOffset) const; |
226 | |
227 | // Base intra-image pointer access |
228 | // (These are for pointers retrieved out of the PE image) |
229 | |
230 | CHECK CheckInternalAddress(SIZE_T address, IsNullOK ok = NULL_NOT_OK) const; |
231 | CHECK CheckInternalAddress(SIZE_T address, COUNT_T size, IsNullOK ok = NULL_NOT_OK) const; |
232 | TADDR GetInternalAddressData(SIZE_T address) const; |
233 | |
234 | // CLR loader IL Image verification - these checks apply to IL_ONLY images. |
235 | |
236 | BOOL IsILOnly() const; |
237 | CHECK CheckILOnly() const; |
238 | |
239 | void LayoutILOnly(void *base, BOOL allowFullPE = FALSE) const; |
240 | |
241 | // Strong name & hashing support |
242 | |
243 | BOOL HasStrongNameSignature() const; |
244 | CHECK CheckStrongNameSignature() const; |
245 | PTR_CVOID GetStrongNameSignature(COUNT_T *pSize = NULL) const; |
246 | |
247 | // CorHeader flag support |
248 | |
249 | // IsStrongNameSigned indicates whether the signature has been filled in. |
250 | // (otherwise if it has a signature it is delay signed.) |
251 | BOOL IsStrongNameSigned() const; // TRUE if the COMIMAGE_FLAGS_STRONGNAMESIGNED flag is set |
252 | |
253 | // TLS |
254 | |
255 | BOOL HasTls() const; |
256 | CHECK CheckTls() const; |
257 | PTR_VOID GetTlsRange(COUNT_T *pSize = NULL) const; |
258 | UINT32 GetTlsIndex() const; |
259 | |
260 | #ifndef FEATURE_PAL |
261 | // Win32 resources |
262 | void *GetWin32Resource(LPCWSTR lpName, LPCWSTR lpType, COUNT_T *pSize = NULL) const; |
263 | #endif // FEATURE_PAL |
264 | |
265 | // COR header fields |
266 | |
267 | BOOL () const; |
268 | CHECK () const; |
269 | IMAGE_COR20_HEADER *() const; |
270 | |
271 | PTR_CVOID GetMetadata(COUNT_T *pSize = NULL) const; |
272 | |
273 | const void *GetResources(COUNT_T *pSize = NULL) const; |
274 | CHECK CheckResource(COUNT_T offset) const; |
275 | const void *GetResource(COUNT_T offset, COUNT_T *pSize = NULL) const; |
276 | |
277 | BOOL HasManagedEntryPoint() const; |
278 | ULONG GetEntryPointToken() const; |
279 | IMAGE_COR_VTABLEFIXUP *GetVTableFixups(COUNT_T *pCount = NULL) const; |
280 | |
281 | // Native header access |
282 | BOOL () const; |
283 | CHECK () const; |
284 | CORCOMPILE_HEADER *() const; |
285 | BOOL IsNativeMachineFormat() const; |
286 | BOOL IsI386() const; |
287 | |
288 | void GetPEKindAndMachine(DWORD * pdwPEKind, DWORD *pdwMachine); // Returns CorPEKind flags |
289 | BOOL IsPlatformNeutral(); // Returns TRUE for IL-only platform neutral images |
290 | |
291 | // |
292 | // Verifies that the IL is within the bounds of the image. |
293 | // |
294 | CHECK CheckILMethod(RVA rva); |
295 | |
296 | // |
297 | // Compute size of IL blob. Assumes that the IL is within the bounds of the image - make sure |
298 | // to call CheckILMethod before calling this method. |
299 | // |
300 | static SIZE_T ComputeILMethodSize(TADDR pIL); |
301 | |
302 | // Debug directory access, returns NULL if no such entry |
303 | PTR_IMAGE_DEBUG_DIRECTORY GetDebugDirectoryEntry(UINT index) const; |
304 | |
305 | #ifdef FEATURE_PREJIT |
306 | CHECK () const; |
307 | |
308 | // ManagedNative fields |
309 | CORCOMPILE_CODE_MANAGER_ENTRY *GetNativeCodeManagerTable() const; |
310 | CORCOMPILE_EE_INFO_TABLE *GetNativeEEInfoTable() const; |
311 | void *GetNativeHelperTable(COUNT_T *pSize = NULL) const; |
312 | CORCOMPILE_VERSION_INFO *GetNativeVersionInfo() const; |
313 | CORCOMPILE_VERSION_INFO *GetNativeVersionInfoMaybeNull(bool = false) const; |
314 | BOOL HasNativeDebugMap() const; |
315 | TADDR GetNativeDebugMap(COUNT_T *pSize = NULL) const; |
316 | Module *GetPersistedModuleImage(COUNT_T *pSize = NULL) const; |
317 | PCODE GetNativeHotCode(COUNT_T * pSize = NULL) const; |
318 | PCODE GetNativeCode(COUNT_T * pSize = NULL) const; |
319 | PCODE GetNativeColdCode(COUNT_T * pSize = NULL) const; |
320 | |
321 | CORCOMPILE_METHOD_PROFILE_LIST *GetNativeProfileDataList(COUNT_T *pSize = NULL) const; |
322 | PTR_CVOID GetNativeManifestMetadata(COUNT_T *pSize = NULL) const; |
323 | const void *GetNativePreferredBase() const; |
324 | BOOL GetNativeILHasSecurityDirectory() const; |
325 | BOOL GetNativeILIsIbcOptimized() const; |
326 | BOOL () const; |
327 | BOOL IsNativeILILOnly() const; |
328 | BOOL IsNativeILDll() const; |
329 | void GetNativeILPEKindAndMachine(DWORD* pdwKind, DWORD* pdwMachine) const; |
330 | CORCOMPILE_DEPENDENCY * GetNativeDependencies(COUNT_T *pCount = NULL) const; |
331 | |
332 | PTR_CORCOMPILE_IMPORT_SECTION GetNativeImportSections(COUNT_T *pCount = NULL) const; |
333 | PTR_CORCOMPILE_IMPORT_SECTION GetNativeImportSectionFromIndex(COUNT_T index) const; |
334 | PTR_CORCOMPILE_IMPORT_SECTION GetNativeImportSectionForRVA(RVA rva) const; |
335 | |
336 | TADDR GetStubsTable(COUNT_T *pSize = NULL) const; |
337 | TADDR GetVirtualSectionsTable(COUNT_T *pSize = NULL) const; |
338 | #endif // FEATURE_PREJIT |
339 | |
340 | BOOL () const; |
341 | READYTORUN_HEADER *() const; |
342 | |
343 | void GetEXEStackSizes(SIZE_T *PE_SizeOfStackReserve, SIZE_T *PE_SizeOfStackCommit) const; |
344 | |
345 | CHECK CheckWillCreateGuardPage() const; |
346 | |
347 | // Native DLLMain Entrypoint |
348 | BOOL HasNativeEntryPoint() const; |
349 | void *GetNativeEntryPoint() const; |
350 | |
351 | #ifdef _DEBUG |
352 | // Stress mode for relocations |
353 | static BOOL GetForceRelocs(); |
354 | static BOOL ForceRelocForDLL(LPCWSTR lpFileName); |
355 | #endif |
356 | |
357 | #ifdef DACCESS_COMPILE |
358 | void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, bool enumThis); |
359 | #endif |
360 | |
361 | protected: |
362 | |
363 | // ------------------------------------------------------------ |
364 | // Protected API for subclass use |
365 | // ------------------------------------------------------------ |
366 | |
367 | // Checking utilites |
368 | static CHECK CheckBounds(RVA rangeBase, COUNT_T rangeSize, RVA rva); |
369 | static CHECK CheckBounds(RVA rangeBase, COUNT_T rangeSize, RVA rva, COUNT_T size); |
370 | |
371 | static CHECK CheckBounds(const void *rangeBase, COUNT_T rangeSize, const void *pointer); |
372 | static CHECK CheckBounds(PTR_CVOID rangeBase, COUNT_T rangeSize, PTR_CVOID pointer, COUNT_T size); |
373 | |
374 | protected: |
375 | |
376 | // Flat mapping utilities - using PointerToRawData instead of (Relative)VirtualAddress |
377 | IMAGE_SECTION_HEADER *RvaToSection(RVA rva) const; |
378 | IMAGE_SECTION_HEADER *OffsetToSection(COUNT_T fileOffset) const; |
379 | |
380 | void SetRelocated(); |
381 | |
382 | private: |
383 | |
384 | // ------------------------------------------------------------ |
385 | // Internal functions |
386 | // ------------------------------------------------------------ |
387 | |
388 | enum METADATA_SECTION_TYPE |
389 | { |
390 | METADATA_SECTION_FULL, |
391 | #ifdef FEATURE_PREJIT |
392 | METADATA_SECTION_MANIFEST |
393 | #endif |
394 | }; |
395 | |
396 | IMAGE_DATA_DIRECTORY *GetMetaDataHelper(METADATA_SECTION_TYPE type) const; |
397 | |
398 | static PTR_IMAGE_SECTION_HEADER (IMAGE_NT_HEADERS * ); |
399 | |
400 | IMAGE_NT_HEADERS *() const; |
401 | IMAGE_COR20_HEADER *() const; |
402 | CORCOMPILE_HEADER *() const; |
403 | READYTORUN_HEADER *() const; |
404 | |
405 | // Flat mapping utilities |
406 | RVA InternalAddressToRva(SIZE_T address) const; |
407 | |
408 | // NT header subchecks |
409 | CHECK CheckSection(COUNT_T previousAddressEnd, COUNT_T addressStart, COUNT_T addressSize, |
410 | COUNT_T previousOffsetEnd, COUNT_T offsetStart, COUNT_T offsetSize) const; |
411 | |
412 | // Pure managed subchecks |
413 | CHECK CheckILOnlyImportDlls() const; |
414 | CHECK CheckILOnlyImportByNameTable(RVA rva) const; |
415 | CHECK CheckILOnlyBaseRelocations() const; |
416 | CHECK CheckILOnlyEntryPoint() const; |
417 | |
418 | // ------------------------------------------------------------ |
419 | // Instance members |
420 | // ------------------------------------------------------------ |
421 | |
422 | enum |
423 | { |
424 | FLAG_MAPPED = 0x01, // the file is mapped/hydrated (vs. the raw disk layout) |
425 | FLAG_CONTENTS = 0x02, // the file has contents |
426 | FLAG_RELOCATED = 0x04, // relocs have been applied |
427 | FLAG_NT_CHECKED = 0x10, |
428 | FLAG_COR_CHECKED = 0x20, |
429 | FLAG_IL_ONLY_CHECKED = 0x40, |
430 | FLAG_NATIVE_CHECKED = 0x80, |
431 | |
432 | = 0x100, |
433 | }; |
434 | |
435 | TADDR m_base; |
436 | COUNT_T m_size; // size of file on disk, as opposed to OptionalHeaders.SizeOfImage |
437 | ULONG m_flags; |
438 | |
439 | PTR_IMAGE_NT_HEADERS ; |
440 | PTR_IMAGE_COR20_HEADER ; |
441 | PTR_CORCOMPILE_HEADER ; |
442 | PTR_READYTORUN_HEADER ; |
443 | }; |
444 | |
445 | // |
446 | // MethodSectionIterator class is used to iterate hot (or) cold method section in an ngen image. |
447 | // It can also iterate nibble maps generated by the JIT in a regular HeapList. |
448 | // |
449 | class MethodSectionIterator |
450 | { |
451 | private: |
452 | PTR_DWORD m_codeTableStart; |
453 | PTR_DWORD m_codeTable; |
454 | PTR_DWORD m_codeTableEnd; |
455 | |
456 | BYTE *m_code; |
457 | |
458 | DWORD m_dword; |
459 | DWORD m_index; |
460 | |
461 | BYTE *m_current; |
462 | |
463 | public: |
464 | |
465 | //If code is a target pointer, then GetMethodCode and FindMethodCode return |
466 | //target pointers. codeTable may be a pointer of either type, since it is |
467 | //converted internally into a host pointer. |
468 | MethodSectionIterator(const void *code, SIZE_T codeSize, |
469 | const void *codeTable, SIZE_T codeTableSize); |
470 | BOOL Next(); |
471 | BYTE *GetMethodCode() { return m_current; } // Get the start of method code of the current method in the iterator |
472 | }; |
473 | |
474 | #include "pedecoder.inl" |
475 | |
476 | #endif // PEDECODER_H_ |
477 | |