VirtualBox

source: vbox/trunk/src/VBox/Runtime/ldrPE.cpp@ 977

Last change on this file since 977 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 57.9 KB
Line 
1/* $Id: ldrPE.cpp 1 1970-01-01 00:00:00Z vboxsync $ */
2/** @file
3 * InnoTek Portable Runtime - Binary Image Loader, Portable Executable (PE).
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP RTLOGGROUP_LDR
27#include <iprt/ldr.h>
28#include <iprt/alloc.h>
29#include <iprt/assert.h>
30#include <iprt/log.h>
31#include <iprt/string.h>
32#include <iprt/err.h>
33#include "internal/ldrPE.h"
34#include "internal/ldr.h"
35
36
37
38/*******************************************************************************
39* Defined Constants And Macros *
40*******************************************************************************/
41/** Converts rva to a type.
42 * @param pvBits Pointer to base of image bits.
43 * @param rva Relative virtual address.
44 * @param type Type.
45 */
46#define PE_RVA2TYPE(pvBits, rva, type) ((type) ((uintptr_t)pvBits + (uintptr_t)(rva)) )
47
48
49/*******************************************************************************
50* Structures and Typedefs *
51*******************************************************************************/
52/**
53 * The PE loader structure.
54 */
55typedef struct RTLDRMODPE
56{
57 /** Core module structure. */
58 RTLDRMODINTERNAL Core;
59 /** Pointer to the reader instance. */
60 PRTLDRREADER pReader;
61 /** Pointer to internal copy of image bits.
62 * @todo the reader should take care of this. */
63 void *pvBits;
64 /** The offset of the NT headers. */
65 RTFOFF offNtHdrs;
66
67 /** The machine type (IMAGE_FILE_HEADER::Machine). */
68 uint16_t u16Machine;
69 /** The file flags (IMAGE_FILE_HEADER::Characteristics). */
70 uint16_t fFile;
71 /** Number of sections (IMAGE_FILE_HEADER::NumberOfSections). */
72 unsigned cSections;
73 /** Pointer to an array of the section headers related to the file. */
74 PIMAGE_SECTION_HEADER paSections;
75
76 /** The RVA of the entry point (IMAGE_OPTIONAL_HEADER32::AddressOfEntryPoint). */
77 RTUINTPTR uEntryPointRVA;
78 /** The base address of the image at link time (IMAGE_OPTIONAL_HEADER32::ImageBase). */
79 RTUINTPTR uImageBase;
80 /** The size of the loaded image (IMAGE_OPTIONAL_HEADER32::SizeOfImage). */
81 uint32_t cbImage;
82 /** Size of the header (IMAGE_OPTIONAL_HEADER32::SizeOfHeaders). */
83 uint32_t cbHeaders;
84 /** The import data directory entry. */
85 IMAGE_DATA_DIRECTORY ImportDir;
86 /** The base relocation data directory entry. */
87 IMAGE_DATA_DIRECTORY RelocDir;
88 /** The export data directory entry. */
89 IMAGE_DATA_DIRECTORY ExportDir;
90} RTLDRMODPE, *PRTLDRMODPE;
91
92/**
93 * PE Loader module operations.
94 *
95 * The PE loader has one operation which is a bit different between 32-bit and 64-bit PE images,
96 * and for historical and performance reasons have been split into separate functions. Thus the
97 * PE loader extends the RTLDROPS structure with this one entry.
98 */
99typedef struct RTLDROPSPE
100{
101 /** The usual ops. */
102 RTLDROPS Core;
103
104 /**
105 * Resolves all imports.
106 *
107 * @returns iprt status code.
108 * @param pModPe Pointer to the PE loader module structure.
109 * @param pvBitsR Where to read raw image bits. (optional)
110 * @param pvBitsW Where to store the imports. The size of this buffer is equal or
111 * larger to the value returned by pfnGetImageSize().
112 * @param pfnGetImport The callback function to use to resolve imports (aka unresolved externals).
113 * @param pvUser User argument to pass to the callback.
114 */
115 DECLCALLBACKMEMBER(int, pfnResolveImports)(PRTLDRMODPE pModPe, const void *pvBitsR, void *pvBitsW, PFNRTLDRIMPORT pfnGetImport, void *pvUser);
116
117 /** Dummy entry to make sure we've initialized it all. */
118 RTUINT uDummy;
119} RTLDROPSPE, *PRTLDROPSPE;
120
121
122/*******************************************************************************
123* Internal Functions *
124*******************************************************************************/
125static void rtldrPEConvert32BitOptionalHeaderTo64Bit(PIMAGE_OPTIONAL_HEADER64 pOptHdr);
126static void rtldrPEConvert32BitLoadConfigTo64Bit(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg);
127static int rtldrPEApplyFixups(PRTLDRMODPE pModPe, const void *pvBitsR, void *pvBitsW, RTUINTPTR BaseAddress, RTUINTPTR OldBaseAddress);
128
129
130/** @copydoc RTLDROPS::pfnGetImageSize */
131static DECLCALLBACK(size_t) rtldrPEGetImageSize(PRTLDRMODINTERNAL pMod)
132{
133 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
134 return pModPe->cbImage;
135}
136
137
138/**
139 * Reads the image into memory.
140 *
141 * @returns iprt status code.
142 * @param pModPe The PE module.
143 * @param pvBits Where to store the bits, this buffer is at least pItem->Core.cbImage in size.
144 */
145static int rtldrPEGetBitsNoImportsNorFixups(PRTLDRMODPE pModPe, void *pvBits)
146{
147 /*
148 * Both these checks are related to pfnDone().
149 */
150 PRTLDRREADER pReader = pModPe->pReader;
151 if (!pReader)
152 {
153 AssertMsgFailed(("You've called done!\n"));
154 return VERR_WRONG_ORDER;
155 }
156 if (!pvBits)
157 return VERR_NO_MEMORY;
158
159 /*
160 * Zero everything (could be done per section).
161 */
162 memset(pvBits, 0, pModPe->cbImage);
163
164#ifdef PE_FILE_OFFSET_EQUALS_RVA
165 /*
166 * Read the entire image / file.
167 */
168 const RTFOFF cbRawImage = pReader->pfnSize(pReader)
169 rc = pReader->pfnRead(pReader, pvBits, RT_MIN(pModPe->cbImage, cbRawImage), 0);
170 if (RT_FAILURE(rc))
171 Log(("rtldrPE: %s: Reading %#x bytes at offset %#x failed, %Rrc!!! (the entire image)\n",
172 pReader->pfnLogName(pReader), RT_MIN(pModPe->cbImage, cbRawImage), 0, rc));
173#else
174
175 /*
176 * Read the headers.
177 */
178 int rc = pReader->pfnRead(pReader, pvBits, pModPe->cbHeaders, 0);
179 if (RT_SUCCESS(rc))
180 {
181 /*
182 * Read the sections.
183 */
184 PIMAGE_SECTION_HEADER pSH = pModPe->paSections;
185 for (unsigned cLeft = pModPe->cSections; cLeft > 0; cLeft--, pSH++)
186 if (pSH->SizeOfRawData && pSH->Misc.VirtualSize)
187 {
188 rc = pReader->pfnRead(pReader, (uint8_t *)pvBits + pSH->VirtualAddress, pSH->SizeOfRawData, pSH->PointerToRawData);
189 if (RT_FAILURE(rc))
190 {
191 Log(("rtldrPE: %s: Reading %#x bytes at offset %#x failed, %Rrc - section #%d '%.*s'!!!\n",
192 pReader->pfnLogName(pReader), pSH->SizeOfRawData, pSH->PointerToRawData, rc,
193 pSH - pModPe->paSections, sizeof(pSH->Name), pSH->Name));
194 break;
195 }
196 }
197 }
198 else
199 Log(("rtldrPE: %s: Reading %#x bytes at offset %#x failed, %Rrc!!!\n",
200 pReader->pfnLogName(pReader), pModPe->cbHeaders, 0, rc));
201#endif
202 return rc;
203}
204
205
206/**
207 * Reads the bits into the internal buffer pointed to by PRTLDRMODPE::pvBits.
208 *
209 * @returns iprt status code.
210 * @param pModPe The PE module.
211 */
212static int rtldrPEReadBits(PRTLDRMODPE pModPe)
213{
214 Assert(!pModPe->pvBits);
215 void *pvBitsW = RTMemAllocZ(pModPe->cbImage);
216 if (!pvBitsW)
217 return VERR_NO_MEMORY;
218 int rc = rtldrPEGetBitsNoImportsNorFixups(pModPe, pvBitsW);
219 if (RT_SUCCESS(rc))
220 pModPe->pvBits = pvBitsW;
221 else
222 RTMemFree(pvBitsW);
223 return rc;
224}
225
226
227/** @copydoc RTLDROPS::pfnGetBits */
228static DECLCALLBACK(int) rtldrPEGetBits(PRTLDRMODINTERNAL pMod, void *pvBits, RTUINTPTR BaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser)
229{
230 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
231
232 /*
233 * Read the image.
234 */
235 int rc = rtldrPEGetBitsNoImportsNorFixups(pModPe, pvBits);
236 if (RT_SUCCESS(rc))
237 {
238 /*
239 * Resolve imports.
240 */
241 rc = ((PRTLDROPSPE)pMod->pOps)->pfnResolveImports(pModPe, pvBits, pvBits, pfnGetImport, pvUser);
242 if (RT_SUCCESS(rc))
243 {
244 /*
245 * Apply relocations.
246 */
247 rc = rtldrPEApplyFixups(pModPe, pvBits, pvBits, BaseAddress, pModPe->uImageBase);
248 if (RT_SUCCESS(rc))
249 return rc;
250 AssertMsgFailed(("Failed to apply fixups. rc=%Rrc\n", rc));
251 }
252 else
253 AssertMsgFailed(("Failed to resolve imports. rc=%Rrc\n", rc));
254 }
255 return rc;
256}
257
258
259/** @copydoc RTLDROPSPE::pfnResolveImports */
260static DECLCALLBACK(int) rtldrPEResolveImports32(PRTLDRMODPE pModPe, const void *pvBitsR, void *pvBitsW, PFNRTLDRIMPORT pfnGetImport, void *pvUser)
261{
262 /*
263 * Check if there is actually anything to work on.
264 */
265 if ( !pModPe->ImportDir.VirtualAddress
266 || !pModPe->ImportDir.Size)
267 return 0;
268
269 /*
270 * Walk the IMAGE_IMPORT_DESCRIPTOR table.
271 */
272 int rc = VINF_SUCCESS;
273 PIMAGE_IMPORT_DESCRIPTOR pImps;
274 for (pImps = PE_RVA2TYPE(pvBitsR, pModPe->ImportDir.VirtualAddress, PIMAGE_IMPORT_DESCRIPTOR);
275 !rc && pImps->Name != 0 && pImps->FirstThunk != 0;
276 pImps++)
277 {
278 const char *pszModName = PE_RVA2TYPE(pvBitsR, pImps->Name, const char *);
279 PIMAGE_THUNK_DATA32 pFirstThunk; /* update this. */
280 PIMAGE_THUNK_DATA32 pThunk; /* read from this. */
281 Log3(("RTLdrPE: Import descriptor: %s\n", pszModName));
282 Log4(("RTLdrPE: OriginalFirstThunk = %#RX32\n"
283 "RTLdrPE: TimeDateStamp = %#RX32\n"
284 "RTLdrPE: ForwarderChain = %#RX32\n"
285 "RTLdrPE: Name = %#RX32\n"
286 "RTLdrPE: FirstThunk = %#RX32\n",
287 pImps->u.OriginalFirstThunk, pImps->TimeDateStamp,
288 pImps->ForwarderChain, pImps->Name, pImps->FirstThunk));
289
290 /*
291 * Walk the thunks table(s).
292 */
293 pFirstThunk = PE_RVA2TYPE(pvBitsW, pImps->FirstThunk, PIMAGE_THUNK_DATA32);
294 pThunk = pImps->u.OriginalFirstThunk == 0
295 ? PE_RVA2TYPE(pvBitsR, pImps->FirstThunk, PIMAGE_THUNK_DATA32)
296 : PE_RVA2TYPE(pvBitsR, pImps->u.OriginalFirstThunk, PIMAGE_THUNK_DATA32);
297 while (!rc && pThunk->u1.Ordinal != 0)
298 {
299 RTUINTPTR Value = 0;
300 if (pThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG32)
301 {
302 rc = pfnGetImport(&pModPe->Core, pszModName, NULL, IMAGE_ORDINAL32(pThunk->u1.Ordinal), &Value, pvUser);
303 Log4((RT_SUCCESS(rc) ? "RTLdrPE: %RTptr #%u\n" : "RTLdrPE: %08RX32 #%u rc=%Vrc\n",
304 (uint32_t)Value, IMAGE_ORDINAL32(pThunk->u1.Ordinal), rc));
305 }
306 else if ( pThunk->u1.Ordinal > 0
307 && pThunk->u1.Ordinal < pModPe->cbImage)
308 {
309 rc = pfnGetImport(&pModPe->Core, pszModName, PE_RVA2TYPE(pvBitsR, (char*)pThunk->u1.AddressOfData + 2, const char *),
310 ~0, &Value, pvUser);
311 Log4((RT_SUCCESS(rc) ? "RTLdrPE: %RTptr %s\n" : "RTLdrPE: %08RX32 %s rc=%Vrc\n",
312 (uint32_t)Value, PE_RVA2TYPE(pvBitsR, (char*)pThunk->u1.AddressOfData + 2, const char *), rc));
313 }
314 else
315 {
316 AssertMsgFailed(("bad import data thunk!\n"));
317 rc = VERR_BAD_EXE_FORMAT;
318 }
319 pFirstThunk->u1.Function = Value;
320 if (pFirstThunk->u1.Function != Value)
321 {
322 AssertMsgFailed(("external symbol address to big!\n"));
323 rc = VERR_ADDRESS_CONFLICT; /** @todo get me a better error status code. */
324 }
325 pThunk++;
326 pFirstThunk++;
327 }
328 }
329
330 return rc;
331}
332
333
334/** @copydoc RTLDROPSPE::pfnResolveImports */
335static DECLCALLBACK(int) rtldrPEResolveImports64(PRTLDRMODPE pModPe, const void *pvBitsR, void *pvBitsW, PFNRTLDRIMPORT pfnGetImport, void *pvUser)
336{
337 /*
338 * Check if there is actually anything to work on.
339 */
340 if ( !pModPe->ImportDir.VirtualAddress
341 || !pModPe->ImportDir.Size)
342 return 0;
343
344 /*
345 * Walk the IMAGE_IMPORT_DESCRIPTOR table.
346 */
347 int rc = VINF_SUCCESS;
348 PIMAGE_IMPORT_DESCRIPTOR pImps;
349 for (pImps = PE_RVA2TYPE(pvBitsR, pModPe->ImportDir.VirtualAddress, PIMAGE_IMPORT_DESCRIPTOR);
350 !rc && pImps->Name != 0 && pImps->FirstThunk != 0;
351 pImps++)
352 {
353 const char * pszModName = PE_RVA2TYPE(pvBitsR, pImps->Name, const char *);
354 PIMAGE_THUNK_DATA64 pFirstThunk; /* update this. */
355 PIMAGE_THUNK_DATA64 pThunk; /* read from this. */
356 Log3(("RTLdrPE: Import descriptor: %s\n", pszModName));
357 Log4(("RTLdrPE: OriginalFirstThunk = %#RX32\n"
358 "RTLdrPE: TimeDateStamp = %#RX32\n"
359 "RTLdrPE: ForwarderChain = %#RX32\n"
360 "RTLdrPE: Name = %#RX32\n"
361 "RTLdrPE: FirstThunk = %#RX32\n",
362 pImps->u.OriginalFirstThunk, pImps->TimeDateStamp,
363 pImps->ForwarderChain, pImps->Name, pImps->FirstThunk));
364
365 /*
366 * Walk the thunks table(s).
367 */
368 pFirstThunk = PE_RVA2TYPE(pvBitsW, pImps->FirstThunk, PIMAGE_THUNK_DATA64);
369 pThunk = pImps->u.OriginalFirstThunk == 0
370 ? PE_RVA2TYPE(pvBitsR, pImps->FirstThunk, PIMAGE_THUNK_DATA64)
371 : PE_RVA2TYPE(pvBitsR, pImps->u.OriginalFirstThunk, PIMAGE_THUNK_DATA64);
372 while (!rc && pThunk->u1.Ordinal != 0)
373 {
374 RTUINTPTR Value = 0;
375 if (pThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG64)
376 {
377 rc = pfnGetImport(&pModPe->Core, pszModName, NULL, (unsigned)IMAGE_ORDINAL64(pThunk->u1.Ordinal), &Value, pvUser);
378 Log4((RT_SUCCESS(rc) ? "RTLdrPE: %016RX64 #%u\n" : "RTLdrPE: %016RX64 #%u rc=%Vrc\n",
379 (uint64_t)Value, (unsigned)IMAGE_ORDINAL64(pThunk->u1.Ordinal), rc));
380 }
381 else if ( pThunk->u1.Ordinal > 0
382 && pThunk->u1.Ordinal < pModPe->cbImage)
383 {
384 /** @todo add validation of the string pointer! */
385 rc = pfnGetImport(&pModPe->Core, pszModName, PE_RVA2TYPE(pvBitsR, (uintptr_t)pThunk->u1.AddressOfData + 2, const char *),
386 ~0, &Value, pvUser);
387 Log4((RT_SUCCESS(rc) ? "RTLdrPE: %016RX64 %s\n" : "RTLdrPE: %016RX64 %s rc=%Vrc\n",
388 (uint64_t)Value, PE_RVA2TYPE(pvBitsR, (uintptr_t)pThunk->u1.AddressOfData + 2, const char *), rc));
389 }
390 else
391 {
392 AssertMsgFailed(("bad import data thunk!\n"));
393 rc = VERR_BAD_EXE_FORMAT;
394 }
395 pFirstThunk->u1.Function = Value;
396 pThunk++;
397 pFirstThunk++;
398 }
399 }
400
401 return rc;
402}
403
404
405/**
406 * Applies fixups.
407 */
408static int rtldrPEApplyFixups(PRTLDRMODPE pModPe, const void *pvBitsR, void *pvBitsW, RTUINTPTR BaseAddress, RTUINTPTR OldBaseAddress)
409{
410 if ( !pModPe->RelocDir.VirtualAddress
411 || !pModPe->RelocDir.Size)
412 return 0;
413
414 /*
415 * Apply delta fixups iterating fixup chunks.
416 */
417 PIMAGE_BASE_RELOCATION pbr = PE_RVA2TYPE(pvBitsR, pModPe->RelocDir.VirtualAddress, PIMAGE_BASE_RELOCATION);
418 PIMAGE_BASE_RELOCATION pBaseRelocs = pbr;
419 unsigned cbBaseRelocs = pModPe->RelocDir.Size;
420 RTUINTPTR uDelta = BaseAddress - OldBaseAddress;
421 Log2(("RTLdrPE: Fixups: uDelta=%#RTptr BaseAddress=%#RTptr OldBaseAddress=%#RTptr\n", uDelta, BaseAddress, OldBaseAddress));
422 Log4(("RTLdrPE: BASERELOC: VirtualAddres=%RX32 Size=%RX32\n", pModPe->RelocDir.VirtualAddress, pModPe->RelocDir.Size));
423 Assert(sizeof(*pbr) == sizeof(uint32_t) * 2);
424
425 while ( (uintptr_t)pbr - (uintptr_t)pBaseRelocs + 8 < cbBaseRelocs /* 8= VirtualAddress and SizeOfBlock members */
426 && pbr->SizeOfBlock >= 8)
427 {
428 uint16_t *pwoffFixup = (uint16_t *)(pbr + 1);
429 uint32_t cRelocations = (pbr->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(uint16_t);
430 Log3(("RTLdrPE: base relocs for %#010x, size %#06x (%d relocs)\n", pbr->VirtualAddress, pbr->SizeOfBlock, cRelocations));
431
432 /* Some bound checking just to be sure it works... */
433 if ((uintptr_t)pbr - (uintptr_t)pBaseRelocs + pbr->SizeOfBlock > cbBaseRelocs)
434 cRelocations = (((uintptr_t)pBaseRelocs + cbBaseRelocs) - (uintptr_t)pbr - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(uint16_t);
435
436 /*
437 * Loop thru the fixups in this chunk.
438 */
439 while (cRelocations != 0)
440 {
441 /*
442 * Common fixup
443 */
444 static const char * const s_apszReloc[16] =
445 {
446 "ABS", "HIGH", "LOW", "HIGHLOW", "HIGHADJ", "MIPS_JMPADDR", "RES6", "RES7",
447 "RES8", "IA64_IMM64", "DIR64", "HIGH3ADJ", "RES12", "RES13", "RES14", "RES15"
448 }; NOREF(s_apszReloc);
449 union
450 {
451 uint16_t *pu16;
452 uint32_t *pu32;
453 uint64_t *pu64;
454 } u;
455 const int offFixup = *pwoffFixup & 0xfff;
456 u.pu32 = PE_RVA2TYPE(pvBitsW, offFixup + pbr->VirtualAddress, uint32_t *);
457 const int fType = *pwoffFixup >> 12;
458 Log4(("RTLdrPE: %08x %s\n", offFixup + pbr->VirtualAddress, s_apszReloc[fType]));
459 switch (fType)
460 {
461 case IMAGE_REL_BASED_HIGHLOW: /* 32-bit, add delta. */
462 *u.pu32 += uDelta;
463 break;
464 case IMAGE_REL_BASED_DIR64: /* 64-bit, add delta. */
465 *u.pu64 += (RTINTPTR)uDelta;
466 break;
467 case IMAGE_REL_BASED_ABSOLUTE: /* Alignment placeholder. */
468 break;
469 /* odd ones */
470 case IMAGE_REL_BASED_LOW: /* 16-bit, add 1st 16-bit part of the delta. */
471 *u.pu16 += (uint16_t)uDelta;
472 break;
473 case IMAGE_REL_BASED_HIGH: /* 16-bit, add 2nd 16-bit part of the delta. */
474 *u.pu16 += (uint16_t)(uDelta >> 16);
475 break;
476 /* never ever seen these next two, and I'm not 100% sure they are correctly implemented here. */
477 case IMAGE_REL_BASED_HIGHADJ:
478 {
479 if (cRelocations <= 1)
480 {
481 AssertMsgFailed(("HIGHADJ missing 2nd record!\n"));
482 return VERR_BAD_EXE_FORMAT;
483 }
484 cRelocations--;
485 pwoffFixup++;
486 int32_t i32 = (uint32_t)(*u.pu16 << 16) | *pwoffFixup;
487 i32 += uDelta;
488 i32 += 0x8000; //??
489 *u.pu16 = (uint16_t)(i32 >> 16);
490 break;
491 }
492 case IMAGE_REL_BASED_HIGH3ADJ:
493 {
494 if (cRelocations <= 2)
495 {
496 AssertMsgFailed(("HIGHADJ3 missing 2nd record!\n"));
497 return VERR_BAD_EXE_FORMAT;
498 }
499 cRelocations -= 2;
500 pwoffFixup++;
501 int64_t i64 = ((uint64_t)*u.pu16 << 32) | *(uint32_t *)pwoffFixup++;
502 i64 += (int64_t)uDelta << 16; //??
503 i64 += 0x80000000;//??
504 *u.pu16 = (uint16_t)(i64 >> 32);
505 break;
506 }
507 default:
508 AssertMsgFailed(("Unknown fixup type %d offset=%#x\n", fType, offFixup));
509 break;
510 }
511
512 /*
513 * Next offset/type
514 */
515 pwoffFixup++;
516 cRelocations--;
517 } /* while loop */
518
519 /*
520 * Next Fixup chunk. (i.e. next page)
521 */
522 pbr = (PIMAGE_BASE_RELOCATION)((uintptr_t)pbr + pbr->SizeOfBlock);
523 } /* while loop */
524
525 return 0;
526}
527
528
529/** @copydoc RTLDROPS::pfnRelocate. */
530static int rtldrPERelocate(PRTLDRMODINTERNAL pMod, void *pvBits, RTUINTPTR NewBaseAddress, RTUINTPTR OldBaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser)
531{
532 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
533
534 /*
535 * Do we have to read the image bits?
536 */
537 if (!pModPe->pvBits)
538 {
539 int rc = rtldrPEReadBits(pModPe);
540 if (RT_FAILURE(rc))
541 return rc;
542 }
543
544 /*
545 * Process imports.
546 */
547 int rc = ((PRTLDROPSPE)pMod->pOps)->pfnResolveImports(pModPe, pModPe->pvBits, pvBits, pfnGetImport, pvUser);
548 if (RT_SUCCESS(rc))
549 {
550 /*
551 * Apply relocations.
552 */
553 rc = rtldrPEApplyFixups(pModPe, pModPe->pvBits, pvBits, NewBaseAddress, OldBaseAddress);
554 AssertRC(rc);
555 }
556 return rc;
557}
558
559
560/** @copydoc RTLDROPS::pfnGetSymbolEx. */
561static DECLCALLBACK(int) rtldrPEGetSymbolEx(PRTLDRMODINTERNAL pMod, const void *pvBits, RTUINTPTR BaseAddress, const char *pszSymbol, RTUINTPTR *pValue)
562{
563 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
564
565 /*
566 * Check if there is actually anything to work on.
567 */
568 if ( !pModPe->ExportDir.VirtualAddress
569 || !pModPe->ExportDir.Size)
570 return VERR_SYMBOL_NOT_FOUND;
571
572 /*
573 * No bits supplied? Do we need to read the bits?
574 */
575 if (!pvBits)
576 {
577 if (!pModPe->pvBits)
578 {
579 int rc = rtldrPEReadBits(pModPe);
580 if (RT_FAILURE(rc))
581 return rc;
582 }
583 pvBits = pModPe->pvBits;
584 }
585
586 PIMAGE_EXPORT_DIRECTORY pExpDir = PE_RVA2TYPE(pvBits, pModPe->ExportDir.VirtualAddress, PIMAGE_EXPORT_DIRECTORY);
587 int iExpOrdinal = 0; /* index into address table. */
588 if ((uintptr_t)pszSymbol <= 0xffff)
589 {
590 /*
591 * Find ordinal export: Simple table lookup.
592 */
593 unsigned uOrdinal = (uintptr_t)pszSymbol & 0xffff;
594 if ( uOrdinal >= pExpDir->Base + RT_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions)
595 || uOrdinal < pExpDir->Base)
596 return VERR_SYMBOL_NOT_FOUND;
597 iExpOrdinal = uOrdinal - pExpDir->Base;
598 }
599 else
600 {
601 /*
602 * Find Named Export: Do binary search on the name table.
603 */
604 uint32_t *paRVANames = PE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, uint32_t *);
605 uint16_t *paOrdinals = PE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, uint16_t *);
606 int iStart = 1;
607 int iEnd = pExpDir->NumberOfNames;
608
609 for (;;)
610 {
611 /* end of search? */
612 if (iStart > iEnd)
613 {
614 #ifdef RT_STRICT
615 /* do a linear search just to verify the correctness of the above algorithm */
616 for (unsigned i = 0; i < pExpDir->NumberOfNames; i++)
617 {
618 AssertMsg(i == 0 || strcmp(PE_RVA2TYPE(pvBits, paRVANames[i], const char *), PE_RVA2TYPE(pvBits, paRVANames[i - 1], const char *)) > 0,
619 ("bug in binary export search!!!\n"));
620 AssertMsg(strcmp(PE_RVA2TYPE(pvBits, paRVANames[i], const char *), pszSymbol) != 0,
621 ("bug in binary export search!!!\n"));
622 }
623 #endif
624 return VERR_SYMBOL_NOT_FOUND;
625 }
626
627 int i = (iEnd - iStart) / 2 + iStart;
628 const char *pszExpName = PE_RVA2TYPE(pvBits, paRVANames[i - 1], const char *);
629 int diff = strcmp(pszExpName, pszSymbol);
630 if (diff > 0) /* pszExpName > pszSymbol: search chunck before i */
631 iEnd = i - 1;
632 else if (diff) /* pszExpName < pszSymbol: search chunk after i */
633 iStart = i + 1;
634 else /* pszExpName == pszSymbol */
635 {
636 iExpOrdinal = paOrdinals[i - 1];
637 break;
638 }
639 } /* binary search thru name table */
640 }
641
642 /*
643 * Found export (iExpOrdinal).
644 */
645 uint32_t * paAddress = PE_RVA2TYPE(pvBits, pExpDir->AddressOfFunctions, uint32_t *);
646 unsigned uRVAExport = paAddress[iExpOrdinal];
647
648 if ( uRVAExport > pModPe->ExportDir.VirtualAddress
649 && uRVAExport < pModPe->ExportDir.VirtualAddress + pModPe->ExportDir.Size)
650 {
651 /* Resolve forwarder. */
652 AssertMsgFailed(("Forwarders are not supported!\n"));
653 return VERR_SYMBOL_NOT_FOUND;
654 }
655
656 /* Get plain export address */
657 *pValue = PE_RVA2TYPE(BaseAddress, uRVAExport, RTUINTPTR);
658
659 return VINF_SUCCESS;
660}
661
662
663/** @copydoc RTLDROPS::pfnEnumSymbols */
664static DECLCALLBACK(int) rtldrPEEnumSymbols(PRTLDRMODINTERNAL pMod, unsigned fFlags, const void *pvBits, RTUINTPTR BaseAddress,
665 PFNRTLDRENUMSYMS pfnCallback, void *pvUser)
666{
667 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
668
669 /*
670 * Check if there is actually anything to work on.
671 */
672 if ( !pModPe->ExportDir.VirtualAddress
673 || !pModPe->ExportDir.Size)
674 return VERR_SYMBOL_NOT_FOUND;
675
676 /*
677 * No bits supplied? Do we need to read the bits?
678 */
679 if (!pvBits)
680 {
681 if (!pModPe->pvBits)
682 {
683 int rc = rtldrPEReadBits(pModPe);
684 if (RT_FAILURE(rc))
685 return rc;
686 }
687 pvBits = pModPe->pvBits;
688 }
689
690 /*
691 * We enumerates by ordinal, which means using a slow linear search for
692 * getting any name
693 */
694 PIMAGE_EXPORT_DIRECTORY pExpDir = PE_RVA2TYPE(pvBits, pModPe->ExportDir.VirtualAddress, PIMAGE_EXPORT_DIRECTORY);
695 uint32_t *paAddress = PE_RVA2TYPE(pvBits, pExpDir->AddressOfFunctions, uint32_t *);
696 uint32_t *paRVANames = PE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, uint32_t *);
697 uint16_t *paOrdinals = PE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, uint16_t *);
698 uintptr_t uNamePrev = 0;
699 unsigned cOrdinals = RT_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions);
700 for (unsigned uOrdinal = 0; uOrdinal < cOrdinals; uOrdinal++)
701 {
702 if (paAddress[uOrdinal] /* needed? */)
703 {
704 /*
705 * Look for name.
706 */
707 const char *pszName = NULL;
708 /* Search from previous + 1 to the end. */
709 unsigned uName = uNamePrev + 1;
710 while (uName < pExpDir->NumberOfNames)
711 {
712 if (paOrdinals[uName] == uOrdinal)
713 {
714 pszName = PE_RVA2TYPE(pvBits, paRVANames[uName], const char *);
715 uNamePrev = uName;
716 break;
717 }
718 uName++;
719 }
720 if (!pszName)
721 {
722 /* Search from start to the previous. */
723 uName = 0;
724 for (uName = 0 ; uName <= uNamePrev; uName++)
725 {
726 if (paOrdinals[uName] == uOrdinal)
727 {
728 pszName = PE_RVA2TYPE(pvBits, paRVANames[uName], const char *);
729 uNamePrev = uName;
730 break;
731 }
732 }
733 }
734
735 /*
736 * Get address.
737 */
738 uintptr_t uRVAExport = paAddress[uOrdinal];
739 RTUINTPTR Value;
740 if ( uRVAExport - (uintptr_t)pModPe->ExportDir.VirtualAddress
741 < pModPe->ExportDir.Size)
742 {
743 /* Resolve forwarder. */
744 AssertMsgFailed(("Forwarders are not supported!\n"));
745 continue;
746 }
747 else
748 /* Get plain export address */
749 Value = PE_RVA2TYPE(BaseAddress, uRVAExport, RTUINTPTR);
750
751 /*
752 * Call back.
753 */
754 int rc = pfnCallback(pMod, pszName, uOrdinal + pExpDir->Base, Value, pvUser);
755 if (rc)
756 return rc;
757 }
758 }
759
760 return VINF_SUCCESS;
761}
762
763
764/** @copydoc RTLDROPS::pfnDone */
765static DECLCALLBACK(int) rtldrPEDone(PRTLDRMODINTERNAL pMod)
766{
767 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
768 if (pModPe->pvBits)
769 {
770 RTMemFree(pModPe->pvBits);
771 pModPe->pvBits = NULL;
772 }
773 if (pModPe->pReader)
774 {
775 int rc = pModPe->pReader->pfnDestroy(pModPe->pReader);
776 AssertRC(rc);
777 pModPe->pReader = NULL;
778 }
779 return VINF_SUCCESS;
780}
781
782/** @copydoc RTLDROPS::pfnClose */
783static DECLCALLBACK(int) rtldrPEClose(PRTLDRMODINTERNAL pMod)
784{
785 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
786 if (pModPe->paSections)
787 {
788 RTMemFree(pModPe->paSections);
789 pModPe->paSections = NULL;
790 }
791 if (pModPe->pvBits)
792 {
793 RTMemFree(pModPe->pvBits);
794 pModPe->pvBits = NULL;
795 }
796 if (pModPe->pReader)
797 {
798 int rc = pModPe->pReader->pfnDestroy(pModPe->pReader);
799 AssertRC(rc);
800 pModPe->pReader = NULL;
801 }
802 return VINF_SUCCESS;
803}
804
805
806/**
807 * Operations for a 32-bit PE module.
808 */
809static const RTLDROPSPE s_rtldrPE32Ops =
810{
811 {
812 "pe32",
813 rtldrPEClose,
814 NULL,
815 rtldrPEDone,
816 rtldrPEEnumSymbols,
817 /* ext */
818 rtldrPEGetImageSize,
819 rtldrPEGetBits,
820 rtldrPERelocate,
821 rtldrPEGetSymbolEx,
822 42
823 },
824 rtldrPEResolveImports32,
825 42
826};
827
828
829/**
830 * Operations for a 64-bit PE module.
831 */
832static const RTLDROPSPE s_rtldrPE64Ops =
833{
834 {
835 "pe64",
836 rtldrPEClose,
837 NULL,
838 rtldrPEDone,
839 rtldrPEEnumSymbols,
840 /* ext */
841 rtldrPEGetImageSize,
842 rtldrPEGetBits,
843 rtldrPERelocate,
844 rtldrPEGetSymbolEx,
845 42
846 },
847 rtldrPEResolveImports64,
848 42
849};
850
851
852/**
853 * Converts the optional header from 32 bit to 64 bit.
854 * This is a rather simple task, if you start from the right end.
855 *
856 * @param pOptHdr On input this is a PIMAGE_OPTIONAL_HEADER32.
857 * On output this will be a PIMAGE_OPTIONAL_HEADER64.
858 */
859static void rtldrPEConvert32BitOptionalHeaderTo64Bit(PIMAGE_OPTIONAL_HEADER64 pOptHdr)
860{
861 /*
862 * volatile everywhere! Trying to prevent the compiler being a smarta$$ and reorder stuff.
863 */
864 IMAGE_OPTIONAL_HEADER32 volatile *pOptHdr32 = (IMAGE_OPTIONAL_HEADER32 volatile *)pOptHdr;
865 IMAGE_OPTIONAL_HEADER64 volatile *pOptHdr64 = pOptHdr;
866
867 /* from LoaderFlags and out the difference is 4 * 32-bits. */
868 Assert(RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, LoaderFlags) + 16 == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, LoaderFlags));
869 Assert( RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]) + 16
870 == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]));
871 uint32_t volatile *pu32Dst = (uint32_t *)&pOptHdr64->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1;
872 const uint32_t volatile *pu32Src = (uint32_t *)&pOptHdr32->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1;
873 const uint32_t volatile *pu32SrcLast = (uint32_t *)&pOptHdr32->LoaderFlags;
874 while (pu32Src >= pu32SrcLast)
875 *pu32Dst-- = *pu32Src--;
876
877 /* the previous 4 fields are 32/64 and needs special attention. */
878 pOptHdr64->SizeOfHeapCommit = pOptHdr32->SizeOfHeapCommit;
879 pOptHdr64->SizeOfHeapReserve = pOptHdr32->SizeOfHeapReserve;
880 pOptHdr64->SizeOfStackCommit = pOptHdr32->SizeOfStackCommit;
881 uint32_t u32SizeOfStackReserve = pOptHdr32->SizeOfStackReserve;
882 pOptHdr64->SizeOfStackReserve = u32SizeOfStackReserve;
883
884 /* The rest matches except for BaseOfData which has been merged into ImageBase in the 64-bit version..
885 * Thus, ImageBase needs some special treatement. It will probably work fine assigning one to the
886 * other since this is all declared volatile, but taking now chances, we'll use a temp variable.
887 */
888 Assert(RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, SizeOfStackReserve) == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, SizeOfStackReserve));
889 Assert(RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, BaseOfData) == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, ImageBase));
890 Assert(RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, SectionAlignment) == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, SectionAlignment));
891 uint32_t u32ImageBase = pOptHdr32->ImageBase;
892 pOptHdr64->ImageBase = u32ImageBase;
893}
894
895
896/**
897 * Converts the load config directory from 32 bit to 64 bit.
898 * This is a rather simple task, if you start from the right end.
899 *
900 * @param pLoadCfg On input this is a PIMAGE_LOAD_CONFIG_DIRECTORY32.
901 * On output this will be a PIMAGE_LOAD_CONFIG_DIRECTORY64.
902 */
903static void rtldrPEConvert32BitLoadConfigTo64Bit(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg)
904{
905 /*
906 * volatile everywhere! Trying to prevent the compiler being a smarta$$ and reorder stuff.
907 */
908 IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *pLoadCfg32 = (IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *)pLoadCfg;
909 IMAGE_LOAD_CONFIG_DIRECTORY64 volatile *pLoadCfg64 = pLoadCfg;
910
911 pLoadCfg64->SEHandlerCount = pLoadCfg32->SEHandlerCount;
912 pLoadCfg64->SEHandlerTable = pLoadCfg32->SEHandlerTable;
913 pLoadCfg64->SecurityCookie = pLoadCfg32->SecurityCookie;
914 pLoadCfg64->EditList = pLoadCfg32->EditList;
915 pLoadCfg64->Reserved1 = pLoadCfg32->Reserved1;
916 pLoadCfg64->CSDVersion = pLoadCfg32->CSDVersion;
917 pLoadCfg64->ProcessHeapFlags = pLoadCfg32->ProcessHeapFlags; /* switched place with ProcessAffinityMask, but we're more than 16 byte off by now so it doesn't matter. */
918 pLoadCfg64->ProcessAffinityMask = pLoadCfg32->ProcessAffinityMask;
919 pLoadCfg64->VirtualMemoryThreshold = pLoadCfg32->VirtualMemoryThreshold;
920 pLoadCfg64->MaximumAllocationSize = pLoadCfg32->MaximumAllocationSize;
921 pLoadCfg64->LockPrefixTable = pLoadCfg32->LockPrefixTable;
922 pLoadCfg64->DeCommitTotalFreeThreshold = pLoadCfg32->DeCommitTotalFreeThreshold;
923 uint32_t u32DeCommitFreeBlockThreshold = pLoadCfg32->DeCommitFreeBlockThreshold;
924 pLoadCfg64->DeCommitFreeBlockThreshold = u32DeCommitFreeBlockThreshold;
925 /* the rest is equal. */
926 Assert( RT_OFFSETOF(IMAGE_LOAD_CONFIG_DIRECTORY32, DeCommitFreeBlockThreshold)
927 == RT_OFFSETOF(IMAGE_LOAD_CONFIG_DIRECTORY64, DeCommitFreeBlockThreshold));
928}
929
930
931/**
932 * Validates the file header.
933 *
934 * @returns iprt status code.
935 * @param pFileHdr Pointer to the file header that needs validating.
936 * @param pszLogName The log name to prefix the errors with.
937 */
938int rtldrPEValidateFileHeader(PIMAGE_FILE_HEADER pFileHdr, const char *pszLogName)
939{
940 size_t cbOptionalHeader;
941 switch (pFileHdr->Machine)
942 {
943 case IMAGE_FILE_MACHINE_I386:
944 cbOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER32);
945 break;
946 case IMAGE_FILE_MACHINE_AMD64:
947 cbOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER64);
948 break;
949
950 default:
951 Log(("rtldrPEOpen: %s: Unsupported Machine=%#x\n",
952 pszLogName, pFileHdr->Machine));
953 return VERR_BAD_EXE_FORMAT;
954 }
955 if (pFileHdr->SizeOfOptionalHeader != cbOptionalHeader)
956 {
957 Log(("rtldrPEOpen: %s: SizeOfOptionalHeader=%#x expected %#x\n",
958 pszLogName, pFileHdr->SizeOfOptionalHeader, cbOptionalHeader));
959 return VERR_BAD_EXE_FORMAT;
960 }
961 /* This restriction needs to be implemented elsewhere. */
962 if (pFileHdr->Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
963 {
964 Log(("rtldrPEOpen: %s: IMAGE_FILE_RELOCS_STRIPPED\n", pszLogName));
965 return VERR_BAD_EXE_FORMAT;
966 }
967 if (pFileHdr->NumberOfSections > 42)
968 {
969 Log(("rtldrPEOpen: %s: NumberOfSections=%d - our limit is 42, please raise it if the binary makes sense.(!!!)\n",
970 pszLogName, pFileHdr->NumberOfSections));
971 return VERR_BAD_EXE_FORMAT;
972 }
973 if (pFileHdr->NumberOfSections < 1)
974 {
975 Log(("rtldrPEOpen: %s: NumberOfSections=%d - we can't have an image without sections (!!!)\n",
976 pszLogName, pFileHdr->NumberOfSections));
977 return VERR_BAD_EXE_FORMAT;
978 }
979 return VINF_SUCCESS;
980}
981
982
983/**
984 * Validates the optional header (64/32-bit)
985 *
986 * @returns iprt status code.
987 * @param pOptHdr Pointer to the optional header which needs validation.
988 * @param pszLogName The log name to prefix the errors with.
989 * @param offNtHdrs The offset of the NT headers from teh start of the file.
990 * @param pFileHdr Pointer to the file header (valid).
991 * @param cbRawImage The raw image size.
992 */
993static int rtldrPEValidateOptionalHeader(const IMAGE_OPTIONAL_HEADER64 *pOptHdr, const char *pszLogName, RTFOFF offNtHdrs,
994 const IMAGE_FILE_HEADER *pFileHdr, RTFOFF cbRawImage)
995{
996 const uint16_t CorrectMagic = pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
997 ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC;
998 if (pOptHdr->Magic != CorrectMagic)
999 {
1000 Log(("rtldrPEOpen: %s: Magic=%#x - expected %#x!!!\n", pszLogName, pOptHdr->Magic, CorrectMagic));
1001 return VERR_BAD_EXE_FORMAT;
1002 }
1003 const uint32_t cbImage = pOptHdr->SizeOfImage;
1004 if (cbImage > _1G)
1005 {
1006 Log(("rtldrPEOpen: %s: SizeOfImage=%#x - Our limit is 1GB (%#x)!!!\n", pszLogName, cbImage, _1G));
1007 return VERR_BAD_EXE_FORMAT;
1008 }
1009 const uint32_t cbMinImageSize = pFileHdr->SizeOfOptionalHeader + sizeof(*pFileHdr) + 4 + (uint32_t)offNtHdrs;
1010 if (cbImage < cbMinImageSize)
1011 {
1012 Log(("rtldrPEOpen: %s: SizeOfImage=%#x to small, minimum %#x!!!\n", pszLogName, cbImage, cbMinImageSize));
1013 return VERR_BAD_EXE_FORMAT;
1014 }
1015 if (pOptHdr->AddressOfEntryPoint >= cbImage)
1016 {
1017 Log(("rtldrPEOpen: %s: AddressOfEntryPoint=%#x - beyond image size (%#x)!!!\n",
1018 pszLogName, pOptHdr->AddressOfEntryPoint, cbImage));
1019 return VERR_BAD_EXE_FORMAT;
1020 }
1021 if (pOptHdr->BaseOfCode >= cbImage)
1022 {
1023 Log(("rtldrPEOpen: %s: BaseOfCode=%#x - beyond image size (%#x)!!!\n",
1024 pszLogName, pOptHdr->BaseOfCode, cbImage));
1025 return VERR_BAD_EXE_FORMAT;
1026 }
1027#if 0/* only in 32-bit header */
1028 if (pOptHdr->BaseOfData >= cbImage)
1029 {
1030 Log(("rtldrPEOpen: %s: BaseOfData=%#x - beyond image size (%#x)!!!\n",
1031 pszLogName, pOptHdr->BaseOfData, cbImage));
1032 return VERR_BAD_EXE_FORMAT;
1033 }
1034#endif
1035 if (pOptHdr->SizeOfHeaders >= cbImage)
1036 {
1037 Log(("rtldrPEOpen: %s: SizeOfHeaders=%#x - beyond image size (%#x)!!!\n",
1038 pszLogName, pOptHdr->SizeOfHeaders, cbImage));
1039 return VERR_BAD_EXE_FORMAT;
1040 }
1041 /* don't know how to do the checksum, so ignore it. */
1042 if (pOptHdr->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN)
1043 {
1044 Log(("rtldrPEOpen: %s: Subsystem=%#x (unknown)!!!\n", pszLogName, pOptHdr->Subsystem));
1045 return VERR_BAD_EXE_FORMAT;
1046 }
1047 if (pOptHdr->SizeOfHeaders < cbMinImageSize + pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER))
1048 {
1049 Log(("rtldrPEOpen: %s: SizeOfHeaders=%#x - cbMinImageSize %#x + sections %#x = %#llx!!!\n",
1050 pszLogName, pOptHdr->SizeOfHeaders,
1051 cbImage, cbMinImageSize, pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER),
1052 cbMinImageSize + pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER)));
1053 return VERR_BAD_EXE_FORMAT;
1054 }
1055 if (pOptHdr->SizeOfStackReserve < pOptHdr->SizeOfStackCommit)
1056 {
1057 Log(("rtldrPEOpen: %s: SizeOfStackReserve %#x < SizeOfStackCommit %#x!!!\n",
1058 pszLogName, pOptHdr->SizeOfStackReserve, pOptHdr->SizeOfStackCommit));
1059 return VERR_BAD_EXE_FORMAT;
1060 }
1061 if (pOptHdr->SizeOfHeapReserve < pOptHdr->SizeOfHeapCommit)
1062 {
1063 Log(("rtldrPEOpen: %s: SizeOfStackReserve %#x < SizeOfStackCommit %#x!!!\n",
1064 pszLogName, pOptHdr->SizeOfStackReserve, pOptHdr->SizeOfStackCommit));
1065 return VERR_BAD_EXE_FORMAT;
1066 }
1067
1068 /* DataDirectory */
1069 if (pOptHdr->NumberOfRvaAndSizes != ELEMENTS(pOptHdr->DataDirectory))
1070 {
1071 Log(("rtldrPEOpen: %s: NumberOfRvaAndSizes=%d!!!\n", pszLogName, pOptHdr->NumberOfRvaAndSizes));
1072 return VERR_BAD_EXE_FORMAT;
1073 }
1074 for (unsigned i = 0; i < ELEMENTS(pOptHdr->DataDirectory); i++)
1075 {
1076 IMAGE_DATA_DIRECTORY const *pDir = &pOptHdr->DataDirectory[i];
1077 if (!pDir->Size)
1078 continue;
1079 size_t cb = cbImage;
1080 switch (i)
1081 {
1082 case IMAGE_DIRECTORY_ENTRY_EXPORT: // 0
1083 case IMAGE_DIRECTORY_ENTRY_IMPORT: // 1
1084 case IMAGE_DIRECTORY_ENTRY_RESOURCE: // 2
1085 case IMAGE_DIRECTORY_ENTRY_EXCEPTION: // 3
1086 case IMAGE_DIRECTORY_ENTRY_BASERELOC: // 5
1087 case IMAGE_DIRECTORY_ENTRY_DEBUG: // 6
1088 case IMAGE_DIRECTORY_ENTRY_COPYRIGHT: // 7
1089 case IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT: // 11
1090 case IMAGE_DIRECTORY_ENTRY_IAT: // 12 /* Import Address Table */
1091 break;
1092 case IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG: // 10 - need to check for lock prefixes.
1093 /* Delay inspection after section table is validated. */
1094 break;
1095
1096 case IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT: // 13
1097 Log(("rtldrPEOpen: %s: dir no. %d (DELAY_IMPORT) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1098 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1099 return VERR_LDRPE_DELAY_IMPORT;
1100
1101 /* The security directory seems to be some kind of hack, and the rva is a fileoffset or something. */
1102 case IMAGE_DIRECTORY_ENTRY_SECURITY: // 4
1103 cb = (size_t)cbRawImage; Assert((RTFOFF)cb == cbRawImage);
1104 Log(("rtldrPEOpen: %s: dir no. %d (SECURITY) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1105 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1106 return VERR_LDRPE_SECURITY;
1107
1108 case IMAGE_DIRECTORY_ENTRY_GLOBALPTR: // 8 /* (MIPS GP) */
1109 Log(("rtldrPEOpen: %s: dir no. %d (GLOBALPTR) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1110 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1111 return VERR_LDRPE_GLOBALPTR;
1112
1113 case IMAGE_DIRECTORY_ENTRY_TLS: // 9
1114 Log(("rtldrPEOpen: %s: dir no. %d (TLS) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1115 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1116 return VERR_LDRPE_TLS;
1117
1118 case IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR: // 14
1119 Log(("rtldrPEOpen: %s: dir no. %d (COM_DESCRIPTOR) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1120 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1121 return VERR_LDRPE_COM_DESCRIPTOR;
1122
1123 default:
1124 Log(("rtldrPEOpen: %s: dir no. %d VirtualAddress=%#x Size=%#x is not supported!!!\n",
1125 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1126 return VERR_BAD_EXE_FORMAT;
1127 }
1128 if (pDir->VirtualAddress >= cb)
1129 {
1130 Log(("rtldrPEOpen: %s: dir no. %d VirtualAddress=%#x is invalid (limit %#x)!!!\n",
1131 pszLogName, i, pDir->VirtualAddress, cb));
1132 return VERR_BAD_EXE_FORMAT;
1133 }
1134 if (pDir->Size > cb - pDir->VirtualAddress)
1135 {
1136 Log(("rtldrPEOpen: %s: dir no. %d Size=%#x is invalid (rva=%#x, limit=%#x)!!!\n",
1137 pszLogName, i, pDir->Size, pDir->VirtualAddress, cb));
1138 return VERR_BAD_EXE_FORMAT;
1139 }
1140 }
1141 return VINF_SUCCESS;
1142}
1143
1144
1145/**
1146 * Validates the section headers.
1147 *
1148 * @returns iprt status code.
1149 * @param paSections Pointer to the array of sections that is to be validated.
1150 * @param cSections Number of sections in that array.
1151 * @param pszLogName The log name to prefix the errors with.
1152 * @param pOptHdr Pointer to the optional header (valid).
1153 * @param cbRawImage The raw image size.
1154 */
1155int rtldrPEValidateSectionHeaders(const IMAGE_SECTION_HEADER *paSections, unsigned cSections, const char *pszLogName,
1156 const IMAGE_OPTIONAL_HEADER64 *pOptHdr, RTFOFF cbRawImage)
1157{
1158 const uint32_t cbImage = pOptHdr->SizeOfImage;
1159 const IMAGE_SECTION_HEADER *pSH = &paSections[0];
1160 uint32_t uRvaPrev = pOptHdr->SizeOfHeaders;
1161 Log3(("RTLdrPE: Section Headers:\n"));
1162 for (unsigned cSHdrsLeft = cSections; cSHdrsLeft > 0; cSHdrsLeft--, pSH++)
1163 {
1164 const unsigned iSH = pSH - &paSections[0]; NOREF(iSH);
1165 Log3(("RTLdrPE: #%d '%-8.8s' Characteristics: %08RX32\n"
1166 "RTLdrPE: VirtAddr: %08RX32 VirtSize: %08RX32\n"
1167 "RTLdrPE: FileOff: %08RX32 FileSize: %08RX32\n"
1168 "RTLdrPE: RelocOff: %08RX32 #Relocs: %08RX32\n"
1169 "RTLdrPE: LineOff: %08RX32 #Lines: %08RX32\n",
1170 iSH, pSH->Name, pSH->Characteristics,
1171 pSH->VirtualAddress, pSH->Misc.VirtualSize,
1172 pSH->PointerToRawData, pSH->SizeOfRawData,
1173 pSH->PointerToRelocations, pSH->NumberOfRelocations,
1174 pSH->PointerToLinenumbers, pSH->NumberOfLinenumbers));
1175 if (pSH->Characteristics & (IMAGE_SCN_MEM_16BIT | IMAGE_SCN_MEM_FARDATA | IMAGE_SCN_MEM_PURGEABLE | IMAGE_SCN_MEM_PRELOAD))
1176 {
1177 Log(("rtldrPEOpen: %s: Unsupported section flag(s) %#x section #%d '%.*s'!!!\n",
1178 pszLogName, pSH->Characteristics, iSH, sizeof(pSH->Name), pSH->Name));
1179 return VERR_BAD_EXE_FORMAT;
1180 }
1181
1182 if ( pSH->Misc.VirtualSize
1183 && !(pSH->Characteristics & IMAGE_SCN_TYPE_NOLOAD)) /* binutils uses this for '.stab' even if it's reserved/obsoleted by MS. */
1184 {
1185 if (pSH->VirtualAddress < uRvaPrev)
1186 {
1187 Log(("rtldrPEOpen: %s: Overlaps previous section or sections aren't in ascending order, VirtualAddress=%#x uRvaPrev=%#x - section #%d '%.*s'!!!\n",
1188 pszLogName, pSH->VirtualAddress, uRvaPrev, iSH, sizeof(pSH->Name), pSH->Name));
1189 return VERR_BAD_EXE_FORMAT;
1190 }
1191 if (pSH->VirtualAddress > cbImage)
1192 {
1193 Log(("rtldrPEOpen: %s: VirtualAddress=%#x - beyond image size (%#x) - section #%d '%.*s'!!!\n",
1194 pszLogName, pSH->VirtualAddress, cbImage, iSH, sizeof(pSH->Name), pSH->Name));
1195 return VERR_BAD_EXE_FORMAT;
1196 }
1197
1198 if (pSH->VirtualAddress & (pOptHdr->SectionAlignment - 1)) //ASSUMES power of 2 alignment.
1199 {
1200 Log(("rtldrPEOpen: %s: VirtualAddress=%#x missaligned (%#x) - section #%d '%.*s'!!!\n",
1201 pszLogName, pSH->VirtualAddress, pOptHdr->SectionAlignment, iSH, sizeof(pSH->Name), pSH->Name));
1202 return VERR_BAD_EXE_FORMAT;
1203 }
1204
1205#ifdef PE_FILE_OFFSET_EQUALS_RVA
1206 /* Our loader code assume rva matches the file offset. */
1207 if ( pSH->SizeOfRawData
1208 && pSH->PointerToRawData != pSH->VirtualAddress)
1209 {
1210 Log(("rtldrPEOpen: %s: ASSUMPTION FAILED: file offset %#x != RVA %#x - section #%d '%.*s'!!!\n",
1211 pszLogName, pSH->PointerToRawData, pSH->VirtualAddress, iSH, sizeof(pSH->Name), pSH->Name));
1212 return VERR_BAD_EXE_FORMAT;
1213 }
1214#endif
1215 }
1216
1217 ///@todo only if SizeOfRawData > 0 ?
1218 if ( pSH->PointerToRawData > cbRawImage /// @todo pSH->PointerToRawData >= cbRawImage ?
1219 || pSH->SizeOfRawData > cbRawImage
1220 || pSH->PointerToRawData + pSH->SizeOfRawData > cbRawImage)
1221 {
1222 Log(("rtldrPEOpen: %s: PointerToRawData=%#x SizeOfRawData=%#x - beyond end of file (%#x) - section #%d '%.*s'!!!\n",
1223 pszLogName, pSH->PointerToRawData, pSH->SizeOfRawData, cbRawImage,
1224 iSH, sizeof(pSH->Name), pSH->Name));
1225 return VERR_BAD_EXE_FORMAT;
1226 }
1227
1228 if (pSH->PointerToRawData & (pOptHdr->FileAlignment - 1)) //ASSUMES power of 2 alignment.
1229 {
1230 Log(("rtldrPEOpen: %s: PointerToRawData=%#x missaligned (%#x) - section #%d '%.*s'!!!\n",
1231 pszLogName, pSH->PointerToRawData, pOptHdr->FileAlignment, iSH, sizeof(pSH->Name), pSH->Name));
1232 return VERR_BAD_EXE_FORMAT;
1233 }
1234
1235 /* ignore the relocations and linenumbers. */
1236
1237 uRvaPrev = pSH->VirtualAddress + pSH->Misc.VirtualSize;
1238 }
1239
1240 /** @todo r=bird: more sanity checks! */
1241 return VINF_SUCCESS;
1242}
1243
1244
1245/**
1246 * Reads image data by RVA using the section headers.
1247 *
1248 * @returns iprt status code.
1249 * @param pModPe The PE module instance.
1250 * @param pvBuf Where to store the bits.
1251 * @param cb Number of bytes to tread.
1252 * @param RVA Where to read from.
1253 */
1254static int rtldrPEReadRVA(PRTLDRMODPE pModPe, void *pvBuf, uint32_t cb, uint32_t RVA)
1255{
1256 const IMAGE_SECTION_HEADER *pSH = pModPe->paSections;
1257 PRTLDRREADER pReader = pModPe->pReader;
1258 uint32_t cbRead;
1259 int rc;
1260
1261 /*
1262 * Is it the headers, i.e. prior to the first section.
1263 */
1264 if (RVA < pModPe->cbHeaders)
1265 {
1266 cbRead = RT_MIN(pModPe->cbHeaders - RVA, cb);
1267 rc = pReader->pfnRead(pReader, pvBuf, cbRead, RVA);
1268 if ( cbRead == cb
1269 || RT_FAILURE(rc))
1270 return rc;
1271 cb -= cbRead;
1272 RVA += cbRead;
1273 pvBuf = (uint8_t *)pvBuf + cbRead;
1274 }
1275
1276 /* In the zero space between headers and the first section? */
1277 if (RVA < pSH->VirtualAddress)
1278 {
1279 cbRead = RT_MIN(pSH->VirtualAddress - RVA, cb);
1280 memset(pvBuf, 0, cbRead);
1281 if (cbRead == cb)
1282 return VINF_SUCCESS;
1283 cb -= cbRead;
1284 RVA += cbRead;
1285 pvBuf = (uint8_t *)pvBuf + cbRead;
1286 }
1287
1288 /*
1289 * Iterate the sections.
1290 */
1291 for (unsigned cLeft = pModPe->cSections;
1292 cLeft > 0;
1293 cLeft--, pSH++)
1294 {
1295 uint32_t off = RVA - pSH->VirtualAddress;
1296 if (off < pSH->Misc.VirtualSize)
1297 {
1298 cbRead = RT_MIN(pSH->Misc.VirtualSize - off, cb);
1299 rc = pReader->pfnRead(pReader, pvBuf, cbRead, pSH->PointerToRawData + off);
1300 if ( cbRead == cb
1301 || RT_FAILURE(rc))
1302 return rc;
1303 cb -= cbRead;
1304 RVA += cbRead;
1305 pvBuf = (uint8_t *)pvBuf + cbRead;
1306 }
1307 uint32_t RVANext = cLeft ? pSH[1].VirtualAddress : pModPe->cbImage;
1308 if (RVA < RVANext)
1309 {
1310 cbRead = RT_MIN(RVANext - RVA, cb);
1311 memset(pvBuf, 0, cbRead);
1312 if (cbRead == cb)
1313 return VINF_SUCCESS;
1314 cb -= cbRead;
1315 RVA += cbRead;
1316 pvBuf = (uint8_t *)pvBuf + cbRead;
1317 }
1318 }
1319
1320 AssertFailed();
1321 return VERR_INTERNAL_ERROR;
1322}
1323
1324
1325/**
1326 * Validates the data of some selected data directories entries.
1327 *
1328 * This requires a valid section table and thus has to wait
1329 * till after we've read and validated it.
1330 *
1331 * @returns iprt status code.
1332 * @param pModPe The PE module instance.
1333 * @param pOptHdr Pointer to the optional header (valid).
1334 */
1335int rtldrPEValidateDirectories(PRTLDRMODPE pModPe, const IMAGE_OPTIONAL_HEADER64 *pOptHdr)
1336{
1337 const char *pszLogName = pModPe->pReader->pfnLogName(pModPe->pReader); NOREF(pszLogName);
1338 union /* combine stuff we're reading to help reduce stack usage. */
1339 {
1340 IMAGE_LOAD_CONFIG_DIRECTORY64 Cfg64;
1341 } u;
1342
1343 /*
1344 * The load config entry may include lock prefix tables and whatnot which we don't implement.
1345 * It does also include a lot of stuff which we can ignore, so we'll have to inspect the
1346 * actual data before we can make up our mind about it all.
1347 */
1348 IMAGE_DATA_DIRECTORY Dir = pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG];
1349 if (Dir.Size)
1350 {
1351 const size_t cbExpect = pOptHdr->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC
1352 ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32)
1353 : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64);
1354 if ( Dir.Size != cbExpect
1355 && ( cbExpect == sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32)
1356 && Dir.Size != (uint32_t)RT_OFFSETOF(IMAGE_LOAD_CONFIG_DIRECTORY32, SEHandlerTable))
1357 )
1358 {
1359 Log(("rtldrPEOpen: %s: load cfg dir: unexpected dir size of %d bytes, expected %d.\n",
1360 pszLogName, Dir.Size, cbExpect));
1361 return VERR_LDRPE_LOAD_CONFIG_SIZE;
1362 }
1363
1364 /*
1365 * Read and convert to 64-bit.
1366 */
1367 memset(&u.Cfg64, 0, sizeof(u.Cfg64));
1368 int rc = rtldrPEReadRVA(pModPe, &u.Cfg64, Dir.Size, Dir.VirtualAddress);
1369 if (RT_FAILURE(rc))
1370 return rc;
1371 rtldrPEConvert32BitLoadConfigTo64Bit(&u.Cfg64);
1372
1373 if (u.Cfg64.Size != cbExpect)
1374 {
1375 Log(("rtldrPEOpen: %s: load cfg dir: unexpected header size of %d bytes, expected %d.\n",
1376 pszLogName, u.Cfg64.Size, cbExpect));
1377 return VERR_LDRPE_LOAD_CONFIG_SIZE;
1378 }
1379 if (u.Cfg64.LockPrefixTable)
1380 {
1381 Log(("rtldrPEOpen: %s: load cfg dir: lock prefix table at %RX64. We don't support lock prefix tables!\n",
1382 pszLogName, u.Cfg64.LockPrefixTable));
1383 return VERR_LDRPE_LOCK_PREFIX_TABLE;
1384 }
1385#if 0/* this seems to be safe to ignore. */
1386 if ( u.Cfg64.SEHandlerTable
1387 || u.Cfg64.SEHandlerCount)
1388 {
1389 Log(("rtldrPEOpen: %s: load cfg dir: SEHandlerTable=%RX64 and SEHandlerCount=%RX64 are unsupported!\n",
1390 pszLogName, u.Cfg64.SEHandlerTable, u.Cfg64.SEHandlerCount));
1391 return VERR_BAD_EXE_FORMAT;
1392 }
1393#endif
1394 if (u.Cfg64.EditList)
1395 {
1396 Log(("rtldrPEOpen: %s: load cfg dir: EditList=%RX64 is unsupported!\n",
1397 pszLogName, u.Cfg64.EditList));
1398 return VERR_BAD_EXE_FORMAT;
1399 }
1400 }
1401 return VINF_SUCCESS;
1402}
1403
1404
1405/**
1406 * Open a PE image.
1407 *
1408 * @returns iprt status code.
1409 * @param pReader The loader reader instance which will provide the raw image bits.
1410 * @param offNtHdrs The offset of the NT headers (where you find "PE\0\0").
1411 * @param phLdrMod Where to store the handle.
1412 */
1413int rtldrPEOpen(PRTLDRREADER pReader, RTFOFF offNtHdrs, PRTLDRMOD phLdrMod)
1414{
1415 /*
1416 * Read and validate the file header.
1417 */
1418 IMAGE_FILE_HEADER FileHdr;
1419 int rc = pReader->pfnRead(pReader, &FileHdr, sizeof(FileHdr), offNtHdrs + 4);
1420 if (RT_FAILURE(rc))
1421 return rc;
1422 const char *pszLogName = pReader->pfnLogName(pReader);
1423 rc = rtldrPEValidateFileHeader(&FileHdr, pszLogName);
1424 if (RT_FAILURE(rc))
1425 return rc;
1426
1427 /*
1428 * Read and validate the "optional" header. Convert 32->64 if necessary.
1429 */
1430 IMAGE_OPTIONAL_HEADER64 OptHdr;
1431 rc = pReader->pfnRead(pReader, &OptHdr, FileHdr.SizeOfOptionalHeader, offNtHdrs + 4 + sizeof(IMAGE_FILE_HEADER));
1432 if (RT_FAILURE(rc))
1433 return rc;
1434 if (FileHdr.SizeOfOptionalHeader != sizeof(OptHdr))
1435 rtldrPEConvert32BitOptionalHeaderTo64Bit(&OptHdr);
1436 rc = rtldrPEValidateOptionalHeader(&OptHdr, pszLogName, offNtHdrs, &FileHdr, pReader->pfnSize(pReader));
1437 if (RT_FAILURE(rc))
1438 return rc;
1439
1440 /*
1441 * Read and validate section headers.
1442 */
1443 const size_t cbSections = sizeof(IMAGE_SECTION_HEADER) * FileHdr.NumberOfSections;
1444 PIMAGE_SECTION_HEADER paSections = (PIMAGE_SECTION_HEADER)RTMemAlloc(cbSections);
1445 if (!paSections)
1446 return VERR_NO_MEMORY;
1447 rc = pReader->pfnRead(pReader, paSections, cbSections, offNtHdrs + 4 + sizeof(IMAGE_FILE_HEADER) + FileHdr.SizeOfOptionalHeader);
1448 if (RT_SUCCESS(rc))
1449 {
1450 rc = rtldrPEValidateSectionHeaders(paSections, FileHdr.NumberOfSections, pszLogName,
1451 &OptHdr, pReader->pfnSize(pReader));
1452 if (RT_SUCCESS(rc))
1453 {
1454 /*
1455 * Allocate and initialize the PE module structure.
1456 */
1457 PRTLDRMODPE pModPe = (PRTLDRMODPE)RTMemAllocZ(sizeof(*pModPe));
1458 if (pModPe)
1459 {
1460 pModPe->Core.u32Magic = RTLDRMOD_MAGIC;
1461 pModPe->Core.eState = LDR_STATE_OPENED;
1462 if (FileHdr.SizeOfOptionalHeader == sizeof(OptHdr))
1463 pModPe->Core.pOps = &s_rtldrPE64Ops.Core;
1464 else
1465 pModPe->Core.pOps = &s_rtldrPE32Ops.Core;
1466 pModPe->pReader = pReader;
1467 pModPe->pvBits = NULL;
1468 pModPe->offNtHdrs = offNtHdrs;
1469 pModPe->u16Machine = FileHdr.Machine;
1470 pModPe->fFile = FileHdr.Characteristics;
1471 pModPe->cSections = FileHdr.NumberOfSections;
1472 pModPe->paSections = paSections;
1473 pModPe->uEntryPointRVA= OptHdr.AddressOfEntryPoint;
1474 pModPe->uImageBase = (RTUINTPTR)OptHdr.ImageBase;
1475 pModPe->cbImage = OptHdr.SizeOfImage;
1476 pModPe->cbHeaders = OptHdr.SizeOfHeaders;
1477 pModPe->ImportDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
1478 pModPe->RelocDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
1479 pModPe->ExportDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
1480
1481 /*
1482 * Perform validation of some selected data directories which requires
1483 * inspection of the actual data.
1484 */
1485 rc = rtldrPEValidateDirectories(pModPe, &OptHdr);
1486 if (RT_SUCCESS(rc))
1487 {
1488 *phLdrMod = &pModPe->Core;
1489 return VINF_SUCCESS;
1490 }
1491 RTMemFree(pModPe);
1492 }
1493 else
1494 rc = VERR_NO_MEMORY;
1495 }
1496 }
1497 RTMemFree(paSections);
1498 return rc;
1499}
1500
1501
1502
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette