VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/ldr/ldrPE.cpp@ 16823

Last change on this file since 16823 was 13837, checked in by vboxsync, 16 years ago

s/%Vr\([acfs]\)/%Rr\1/g - since I'm upsetting everyone anyway, better make the most of it...

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