VirtualBox

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

Last change on this file since 4268 was 4071, checked in by vboxsync, 17 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

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