VirtualBox

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

Last change on this file since 20364 was 16933, checked in by vboxsync, 16 years ago

IPRT/PDM,SUPLIb,REM: Extended RTLdrOpen with an architecture argument for use with FAT R0.r0 images later some day. Also added fFlags argument that's currently MBZ case.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 58.9 KB
Line 
1/* $Id: ldrPE.cpp 16933 2009-02-18 23:42:57Z 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 * @param penmArch Where to store the CPU architecture.
947 */
948int rtldrPEValidateFileHeader(PIMAGE_FILE_HEADER pFileHdr, const char *pszLogName, PRTLDRARCH penmArch)
949{
950 size_t cbOptionalHeader;
951 switch (pFileHdr->Machine)
952 {
953 case IMAGE_FILE_MACHINE_I386:
954 cbOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER32);
955 *penmArch = RTLDRARCH_X86_32;
956 break;
957 case IMAGE_FILE_MACHINE_AMD64:
958 cbOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER64);
959 *penmArch = RTLDRARCH_AMD64;
960 break;
961
962 default:
963 Log(("rtldrPEOpen: %s: Unsupported Machine=%#x\n",
964 pszLogName, pFileHdr->Machine));
965 *penmArch = RTLDRARCH_INVALID;
966 return VERR_BAD_EXE_FORMAT;
967 }
968 if (pFileHdr->SizeOfOptionalHeader != cbOptionalHeader)
969 {
970 Log(("rtldrPEOpen: %s: SizeOfOptionalHeader=%#x expected %#x\n",
971 pszLogName, pFileHdr->SizeOfOptionalHeader, cbOptionalHeader));
972 return VERR_BAD_EXE_FORMAT;
973 }
974 /* This restriction needs to be implemented elsewhere. */
975 if (pFileHdr->Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
976 {
977 Log(("rtldrPEOpen: %s: IMAGE_FILE_RELOCS_STRIPPED\n", pszLogName));
978 return VERR_BAD_EXE_FORMAT;
979 }
980 if (pFileHdr->NumberOfSections > 42)
981 {
982 Log(("rtldrPEOpen: %s: NumberOfSections=%d - our limit is 42, please raise it if the binary makes sense.(!!!)\n",
983 pszLogName, pFileHdr->NumberOfSections));
984 return VERR_BAD_EXE_FORMAT;
985 }
986 if (pFileHdr->NumberOfSections < 1)
987 {
988 Log(("rtldrPEOpen: %s: NumberOfSections=%d - we can't have an image without sections (!!!)\n",
989 pszLogName, pFileHdr->NumberOfSections));
990 return VERR_BAD_EXE_FORMAT;
991 }
992 return VINF_SUCCESS;
993}
994
995
996/**
997 * Validates the optional header (64/32-bit)
998 *
999 * @returns iprt status code.
1000 * @param pOptHdr Pointer to the optional header which needs validation.
1001 * @param pszLogName The log name to prefix the errors with.
1002 * @param offNtHdrs The offset of the NT headers from teh start of the file.
1003 * @param pFileHdr Pointer to the file header (valid).
1004 * @param cbRawImage The raw image size.
1005 */
1006static int rtldrPEValidateOptionalHeader(const IMAGE_OPTIONAL_HEADER64 *pOptHdr, const char *pszLogName, RTFOFF offNtHdrs,
1007 const IMAGE_FILE_HEADER *pFileHdr, RTFOFF cbRawImage)
1008{
1009 const uint16_t CorrectMagic = pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
1010 ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC;
1011 if (pOptHdr->Magic != CorrectMagic)
1012 {
1013 Log(("rtldrPEOpen: %s: Magic=%#x - expected %#x!!!\n", pszLogName, pOptHdr->Magic, CorrectMagic));
1014 return VERR_BAD_EXE_FORMAT;
1015 }
1016 const uint32_t cbImage = pOptHdr->SizeOfImage;
1017 if (cbImage > _1G)
1018 {
1019 Log(("rtldrPEOpen: %s: SizeOfImage=%#x - Our limit is 1GB (%#x)!!!\n", pszLogName, cbImage, _1G));
1020 return VERR_BAD_EXE_FORMAT;
1021 }
1022 const uint32_t cbMinImageSize = pFileHdr->SizeOfOptionalHeader + sizeof(*pFileHdr) + 4 + (uint32_t)offNtHdrs;
1023 if (cbImage < cbMinImageSize)
1024 {
1025 Log(("rtldrPEOpen: %s: SizeOfImage=%#x to small, minimum %#x!!!\n", pszLogName, cbImage, cbMinImageSize));
1026 return VERR_BAD_EXE_FORMAT;
1027 }
1028 if (pOptHdr->AddressOfEntryPoint >= cbImage)
1029 {
1030 Log(("rtldrPEOpen: %s: AddressOfEntryPoint=%#x - beyond image size (%#x)!!!\n",
1031 pszLogName, pOptHdr->AddressOfEntryPoint, cbImage));
1032 return VERR_BAD_EXE_FORMAT;
1033 }
1034 if (pOptHdr->BaseOfCode >= cbImage)
1035 {
1036 Log(("rtldrPEOpen: %s: BaseOfCode=%#x - beyond image size (%#x)!!!\n",
1037 pszLogName, pOptHdr->BaseOfCode, cbImage));
1038 return VERR_BAD_EXE_FORMAT;
1039 }
1040#if 0/* only in 32-bit header */
1041 if (pOptHdr->BaseOfData >= cbImage)
1042 {
1043 Log(("rtldrPEOpen: %s: BaseOfData=%#x - beyond image size (%#x)!!!\n",
1044 pszLogName, pOptHdr->BaseOfData, cbImage));
1045 return VERR_BAD_EXE_FORMAT;
1046 }
1047#endif
1048 if (pOptHdr->SizeOfHeaders >= cbImage)
1049 {
1050 Log(("rtldrPEOpen: %s: SizeOfHeaders=%#x - beyond image size (%#x)!!!\n",
1051 pszLogName, pOptHdr->SizeOfHeaders, cbImage));
1052 return VERR_BAD_EXE_FORMAT;
1053 }
1054 /* don't know how to do the checksum, so ignore it. */
1055 if (pOptHdr->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN)
1056 {
1057 Log(("rtldrPEOpen: %s: Subsystem=%#x (unknown)!!!\n", pszLogName, pOptHdr->Subsystem));
1058 return VERR_BAD_EXE_FORMAT;
1059 }
1060 if (pOptHdr->SizeOfHeaders < cbMinImageSize + pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER))
1061 {
1062 Log(("rtldrPEOpen: %s: SizeOfHeaders=%#x - cbMinImageSize %#x + sections %#x = %#llx!!!\n",
1063 pszLogName, pOptHdr->SizeOfHeaders,
1064 cbImage, cbMinImageSize, pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER),
1065 cbMinImageSize + pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER)));
1066 return VERR_BAD_EXE_FORMAT;
1067 }
1068 if (pOptHdr->SizeOfStackReserve < pOptHdr->SizeOfStackCommit)
1069 {
1070 Log(("rtldrPEOpen: %s: SizeOfStackReserve %#x < SizeOfStackCommit %#x!!!\n",
1071 pszLogName, pOptHdr->SizeOfStackReserve, pOptHdr->SizeOfStackCommit));
1072 return VERR_BAD_EXE_FORMAT;
1073 }
1074 if (pOptHdr->SizeOfHeapReserve < pOptHdr->SizeOfHeapCommit)
1075 {
1076 Log(("rtldrPEOpen: %s: SizeOfStackReserve %#x < SizeOfStackCommit %#x!!!\n",
1077 pszLogName, pOptHdr->SizeOfStackReserve, pOptHdr->SizeOfStackCommit));
1078 return VERR_BAD_EXE_FORMAT;
1079 }
1080
1081 /* DataDirectory */
1082 if (pOptHdr->NumberOfRvaAndSizes != RT_ELEMENTS(pOptHdr->DataDirectory))
1083 {
1084 Log(("rtldrPEOpen: %s: NumberOfRvaAndSizes=%d!!!\n", pszLogName, pOptHdr->NumberOfRvaAndSizes));
1085 return VERR_BAD_EXE_FORMAT;
1086 }
1087 for (unsigned i = 0; i < RT_ELEMENTS(pOptHdr->DataDirectory); i++)
1088 {
1089 IMAGE_DATA_DIRECTORY const *pDir = &pOptHdr->DataDirectory[i];
1090 if (!pDir->Size)
1091 continue;
1092 size_t cb = cbImage;
1093 switch (i)
1094 {
1095 case IMAGE_DIRECTORY_ENTRY_EXPORT: // 0
1096 case IMAGE_DIRECTORY_ENTRY_IMPORT: // 1
1097 case IMAGE_DIRECTORY_ENTRY_RESOURCE: // 2
1098 case IMAGE_DIRECTORY_ENTRY_EXCEPTION: // 3
1099 case IMAGE_DIRECTORY_ENTRY_BASERELOC: // 5
1100 case IMAGE_DIRECTORY_ENTRY_DEBUG: // 6
1101 case IMAGE_DIRECTORY_ENTRY_COPYRIGHT: // 7
1102 case IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT: // 11
1103 case IMAGE_DIRECTORY_ENTRY_IAT: // 12 /* Import Address Table */
1104 break;
1105 case IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG: // 10 - need to check for lock prefixes.
1106 /* Delay inspection after section table is validated. */
1107 break;
1108
1109 case IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT: // 13
1110 Log(("rtldrPEOpen: %s: dir no. %d (DELAY_IMPORT) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1111 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1112 return VERR_LDRPE_DELAY_IMPORT;
1113
1114 /* The security directory seems to be some kind of hack, and the rva is a fileoffset or something. */
1115 case IMAGE_DIRECTORY_ENTRY_SECURITY: // 4
1116 cb = (size_t)cbRawImage; Assert((RTFOFF)cb == cbRawImage);
1117 Log(("rtldrPEOpen: %s: dir no. %d (SECURITY) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1118 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1119 return VERR_LDRPE_SECURITY;
1120
1121 case IMAGE_DIRECTORY_ENTRY_GLOBALPTR: // 8 /* (MIPS GP) */
1122 Log(("rtldrPEOpen: %s: dir no. %d (GLOBALPTR) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1123 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1124 return VERR_LDRPE_GLOBALPTR;
1125
1126 case IMAGE_DIRECTORY_ENTRY_TLS: // 9
1127 Log(("rtldrPEOpen: %s: dir no. %d (TLS) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1128 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1129 return VERR_LDRPE_TLS;
1130
1131 case IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR: // 14
1132 Log(("rtldrPEOpen: %s: dir no. %d (COM_DESCRIPTOR) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1133 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1134 return VERR_LDRPE_COM_DESCRIPTOR;
1135
1136 default:
1137 Log(("rtldrPEOpen: %s: dir no. %d VirtualAddress=%#x Size=%#x is not supported!!!\n",
1138 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1139 return VERR_BAD_EXE_FORMAT;
1140 }
1141 if (pDir->VirtualAddress >= cb)
1142 {
1143 Log(("rtldrPEOpen: %s: dir no. %d VirtualAddress=%#x is invalid (limit %#x)!!!\n",
1144 pszLogName, i, pDir->VirtualAddress, cb));
1145 return VERR_BAD_EXE_FORMAT;
1146 }
1147 if (pDir->Size > cb - pDir->VirtualAddress)
1148 {
1149 Log(("rtldrPEOpen: %s: dir no. %d Size=%#x is invalid (rva=%#x, limit=%#x)!!!\n",
1150 pszLogName, i, pDir->Size, pDir->VirtualAddress, cb));
1151 return VERR_BAD_EXE_FORMAT;
1152 }
1153 }
1154 return VINF_SUCCESS;
1155}
1156
1157
1158/**
1159 * Validates the section headers.
1160 *
1161 * @returns iprt status code.
1162 * @param paSections Pointer to the array of sections that is to be validated.
1163 * @param cSections Number of sections in that array.
1164 * @param pszLogName The log name to prefix the errors with.
1165 * @param pOptHdr Pointer to the optional header (valid).
1166 * @param cbRawImage The raw image size.
1167 */
1168int rtldrPEValidateSectionHeaders(const IMAGE_SECTION_HEADER *paSections, unsigned cSections, const char *pszLogName,
1169 const IMAGE_OPTIONAL_HEADER64 *pOptHdr, RTFOFF cbRawImage)
1170{
1171 const uint32_t cbImage = pOptHdr->SizeOfImage;
1172 const IMAGE_SECTION_HEADER *pSH = &paSections[0];
1173 uint32_t uRvaPrev = pOptHdr->SizeOfHeaders;
1174 Log3(("RTLdrPE: Section Headers:\n"));
1175 for (unsigned cSHdrsLeft = cSections; cSHdrsLeft > 0; cSHdrsLeft--, pSH++)
1176 {
1177 const unsigned iSH = pSH - &paSections[0]; NOREF(iSH);
1178 Log3(("RTLdrPE: #%d '%-8.8s' Characteristics: %08RX32\n"
1179 "RTLdrPE: VirtAddr: %08RX32 VirtSize: %08RX32\n"
1180 "RTLdrPE: FileOff: %08RX32 FileSize: %08RX32\n"
1181 "RTLdrPE: RelocOff: %08RX32 #Relocs: %08RX32\n"
1182 "RTLdrPE: LineOff: %08RX32 #Lines: %08RX32\n",
1183 iSH, pSH->Name, pSH->Characteristics,
1184 pSH->VirtualAddress, pSH->Misc.VirtualSize,
1185 pSH->PointerToRawData, pSH->SizeOfRawData,
1186 pSH->PointerToRelocations, pSH->NumberOfRelocations,
1187 pSH->PointerToLinenumbers, pSH->NumberOfLinenumbers));
1188 if (pSH->Characteristics & (IMAGE_SCN_MEM_16BIT | IMAGE_SCN_MEM_FARDATA | IMAGE_SCN_MEM_PURGEABLE | IMAGE_SCN_MEM_PRELOAD))
1189 {
1190 Log(("rtldrPEOpen: %s: Unsupported section flag(s) %#x section #%d '%.*s'!!!\n",
1191 pszLogName, pSH->Characteristics, iSH, sizeof(pSH->Name), pSH->Name));
1192 return VERR_BAD_EXE_FORMAT;
1193 }
1194
1195 if ( pSH->Misc.VirtualSize
1196 && !(pSH->Characteristics & IMAGE_SCN_TYPE_NOLOAD)) /* binutils uses this for '.stab' even if it's reserved/obsoleted by MS. */
1197 {
1198 if (pSH->VirtualAddress < uRvaPrev)
1199 {
1200 Log(("rtldrPEOpen: %s: Overlaps previous section or sections aren't in ascending order, VirtualAddress=%#x uRvaPrev=%#x - section #%d '%.*s'!!!\n",
1201 pszLogName, pSH->VirtualAddress, uRvaPrev, iSH, sizeof(pSH->Name), pSH->Name));
1202 return VERR_BAD_EXE_FORMAT;
1203 }
1204 if (pSH->VirtualAddress > cbImage)
1205 {
1206 Log(("rtldrPEOpen: %s: VirtualAddress=%#x - beyond image size (%#x) - section #%d '%.*s'!!!\n",
1207 pszLogName, pSH->VirtualAddress, cbImage, iSH, sizeof(pSH->Name), pSH->Name));
1208 return VERR_BAD_EXE_FORMAT;
1209 }
1210
1211 if (pSH->VirtualAddress & (pOptHdr->SectionAlignment - 1)) //ASSUMES power of 2 alignment.
1212 {
1213 Log(("rtldrPEOpen: %s: VirtualAddress=%#x missaligned (%#x) - section #%d '%.*s'!!!\n",
1214 pszLogName, pSH->VirtualAddress, pOptHdr->SectionAlignment, iSH, sizeof(pSH->Name), pSH->Name));
1215 return VERR_BAD_EXE_FORMAT;
1216 }
1217
1218#ifdef PE_FILE_OFFSET_EQUALS_RVA
1219 /* Our loader code assume rva matches the file offset. */
1220 if ( pSH->SizeOfRawData
1221 && pSH->PointerToRawData != pSH->VirtualAddress)
1222 {
1223 Log(("rtldrPEOpen: %s: ASSUMPTION FAILED: file offset %#x != RVA %#x - section #%d '%.*s'!!!\n",
1224 pszLogName, pSH->PointerToRawData, pSH->VirtualAddress, iSH, sizeof(pSH->Name), pSH->Name));
1225 return VERR_BAD_EXE_FORMAT;
1226 }
1227#endif
1228 }
1229
1230 ///@todo only if SizeOfRawData > 0 ?
1231 if ( pSH->PointerToRawData > cbRawImage /// @todo pSH->PointerToRawData >= cbRawImage ?
1232 || pSH->SizeOfRawData > cbRawImage
1233 || pSH->PointerToRawData + pSH->SizeOfRawData > cbRawImage)
1234 {
1235 Log(("rtldrPEOpen: %s: PointerToRawData=%#x SizeOfRawData=%#x - beyond end of file (%#x) - section #%d '%.*s'!!!\n",
1236 pszLogName, pSH->PointerToRawData, pSH->SizeOfRawData, cbRawImage,
1237 iSH, sizeof(pSH->Name), pSH->Name));
1238 return VERR_BAD_EXE_FORMAT;
1239 }
1240
1241 if (pSH->PointerToRawData & (pOptHdr->FileAlignment - 1)) //ASSUMES power of 2 alignment.
1242 {
1243 Log(("rtldrPEOpen: %s: PointerToRawData=%#x missaligned (%#x) - section #%d '%.*s'!!!\n",
1244 pszLogName, pSH->PointerToRawData, pOptHdr->FileAlignment, iSH, sizeof(pSH->Name), pSH->Name));
1245 return VERR_BAD_EXE_FORMAT;
1246 }
1247
1248 /* ignore the relocations and linenumbers. */
1249
1250 uRvaPrev = pSH->VirtualAddress + pSH->Misc.VirtualSize;
1251 }
1252
1253 /** @todo r=bird: more sanity checks! */
1254 return VINF_SUCCESS;
1255}
1256
1257
1258/**
1259 * Reads image data by RVA using the section headers.
1260 *
1261 * @returns iprt status code.
1262 * @param pModPe The PE module instance.
1263 * @param pvBuf Where to store the bits.
1264 * @param cb Number of bytes to tread.
1265 * @param RVA Where to read from.
1266 */
1267static int rtldrPEReadRVA(PRTLDRMODPE pModPe, void *pvBuf, uint32_t cb, uint32_t RVA)
1268{
1269 const IMAGE_SECTION_HEADER *pSH = pModPe->paSections;
1270 PRTLDRREADER pReader = pModPe->pReader;
1271 uint32_t cbRead;
1272 int rc;
1273
1274 /*
1275 * Is it the headers, i.e. prior to the first section.
1276 */
1277 if (RVA < pModPe->cbHeaders)
1278 {
1279 cbRead = RT_MIN(pModPe->cbHeaders - RVA, cb);
1280 rc = pReader->pfnRead(pReader, pvBuf, cbRead, RVA);
1281 if ( cbRead == cb
1282 || RT_FAILURE(rc))
1283 return rc;
1284 cb -= cbRead;
1285 RVA += cbRead;
1286 pvBuf = (uint8_t *)pvBuf + cbRead;
1287 }
1288
1289 /* In the zero space between headers and the first section? */
1290 if (RVA < pSH->VirtualAddress)
1291 {
1292 cbRead = RT_MIN(pSH->VirtualAddress - RVA, cb);
1293 memset(pvBuf, 0, cbRead);
1294 if (cbRead == cb)
1295 return VINF_SUCCESS;
1296 cb -= cbRead;
1297 RVA += cbRead;
1298 pvBuf = (uint8_t *)pvBuf + cbRead;
1299 }
1300
1301 /*
1302 * Iterate the sections.
1303 */
1304 for (unsigned cLeft = pModPe->cSections;
1305 cLeft > 0;
1306 cLeft--, pSH++)
1307 {
1308 uint32_t off = RVA - pSH->VirtualAddress;
1309 if (off < pSH->Misc.VirtualSize)
1310 {
1311 cbRead = RT_MIN(pSH->Misc.VirtualSize - off, cb);
1312 rc = pReader->pfnRead(pReader, pvBuf, cbRead, pSH->PointerToRawData + off);
1313 if ( cbRead == cb
1314 || RT_FAILURE(rc))
1315 return rc;
1316 cb -= cbRead;
1317 RVA += cbRead;
1318 pvBuf = (uint8_t *)pvBuf + cbRead;
1319 }
1320 uint32_t RVANext = cLeft ? pSH[1].VirtualAddress : pModPe->cbImage;
1321 if (RVA < RVANext)
1322 {
1323 cbRead = RT_MIN(RVANext - RVA, cb);
1324 memset(pvBuf, 0, cbRead);
1325 if (cbRead == cb)
1326 return VINF_SUCCESS;
1327 cb -= cbRead;
1328 RVA += cbRead;
1329 pvBuf = (uint8_t *)pvBuf + cbRead;
1330 }
1331 }
1332
1333 AssertFailed();
1334 return VERR_INTERNAL_ERROR;
1335}
1336
1337
1338/**
1339 * Validates the data of some selected data directories entries.
1340 *
1341 * This requires a valid section table and thus has to wait
1342 * till after we've read and validated it.
1343 *
1344 * @returns iprt status code.
1345 * @param pModPe The PE module instance.
1346 * @param pOptHdr Pointer to the optional header (valid).
1347 */
1348int rtldrPEValidateDirectories(PRTLDRMODPE pModPe, const IMAGE_OPTIONAL_HEADER64 *pOptHdr)
1349{
1350 const char *pszLogName = pModPe->pReader->pfnLogName(pModPe->pReader); NOREF(pszLogName);
1351 union /* combine stuff we're reading to help reduce stack usage. */
1352 {
1353 IMAGE_LOAD_CONFIG_DIRECTORY64 Cfg64;
1354 } u;
1355
1356 /*
1357 * The load config entry may include lock prefix tables and whatnot which we don't implement.
1358 * It does also include a lot of stuff which we can ignore, so we'll have to inspect the
1359 * actual data before we can make up our mind about it all.
1360 */
1361 IMAGE_DATA_DIRECTORY Dir = pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG];
1362 if (Dir.Size)
1363 {
1364 const size_t cbExpect = pOptHdr->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC
1365 ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32)
1366 : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64);
1367 if ( Dir.Size != cbExpect
1368 && ( cbExpect == sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32)
1369 && Dir.Size != (uint32_t)RT_OFFSETOF(IMAGE_LOAD_CONFIG_DIRECTORY32, SEHandlerTable))
1370 )
1371 {
1372 Log(("rtldrPEOpen: %s: load cfg dir: unexpected dir size of %d bytes, expected %d.\n",
1373 pszLogName, Dir.Size, cbExpect));
1374 return VERR_LDRPE_LOAD_CONFIG_SIZE;
1375 }
1376
1377 /*
1378 * Read and convert to 64-bit.
1379 */
1380 memset(&u.Cfg64, 0, sizeof(u.Cfg64));
1381 int rc = rtldrPEReadRVA(pModPe, &u.Cfg64, Dir.Size, Dir.VirtualAddress);
1382 if (RT_FAILURE(rc))
1383 return rc;
1384 rtldrPEConvert32BitLoadConfigTo64Bit(&u.Cfg64);
1385
1386 if (u.Cfg64.Size != cbExpect)
1387 {
1388 Log(("rtldrPEOpen: %s: load cfg dir: unexpected header size of %d bytes, expected %d.\n",
1389 pszLogName, u.Cfg64.Size, cbExpect));
1390 return VERR_LDRPE_LOAD_CONFIG_SIZE;
1391 }
1392 if (u.Cfg64.LockPrefixTable)
1393 {
1394 Log(("rtldrPEOpen: %s: load cfg dir: lock prefix table at %RX64. We don't support lock prefix tables!\n",
1395 pszLogName, u.Cfg64.LockPrefixTable));
1396 return VERR_LDRPE_LOCK_PREFIX_TABLE;
1397 }
1398#if 0/* this seems to be safe to ignore. */
1399 if ( u.Cfg64.SEHandlerTable
1400 || u.Cfg64.SEHandlerCount)
1401 {
1402 Log(("rtldrPEOpen: %s: load cfg dir: SEHandlerTable=%RX64 and SEHandlerCount=%RX64 are unsupported!\n",
1403 pszLogName, u.Cfg64.SEHandlerTable, u.Cfg64.SEHandlerCount));
1404 return VERR_BAD_EXE_FORMAT;
1405 }
1406#endif
1407 if (u.Cfg64.EditList)
1408 {
1409 Log(("rtldrPEOpen: %s: load cfg dir: EditList=%RX64 is unsupported!\n",
1410 pszLogName, u.Cfg64.EditList));
1411 return VERR_BAD_EXE_FORMAT;
1412 }
1413 }
1414 return VINF_SUCCESS;
1415}
1416
1417
1418/**
1419 * Open a PE image.
1420 *
1421 * @returns iprt status code.
1422 * @param pReader The loader reader instance which will provide the raw image bits.
1423 * @param fFlags Reserved, MBZ.
1424 * @param enmArch Architecture specifier.
1425 * @param offNtHdrs The offset of the NT headers (where you find "PE\0\0").
1426 * @param phLdrMod Where to store the handle.
1427 */
1428int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF offNtHdrs, PRTLDRMOD phLdrMod)
1429{
1430 /*
1431 * Read and validate the file header.
1432 */
1433 IMAGE_FILE_HEADER FileHdr;
1434 int rc = pReader->pfnRead(pReader, &FileHdr, sizeof(FileHdr), offNtHdrs + 4);
1435 if (RT_FAILURE(rc))
1436 return rc;
1437 RTLDRARCH enmArchImage;
1438 const char *pszLogName = pReader->pfnLogName(pReader);
1439 rc = rtldrPEValidateFileHeader(&FileHdr, pszLogName, &enmArchImage);
1440 if (RT_FAILURE(rc))
1441 return rc;
1442
1443 /*
1444 * Match the CPU architecture.
1445 */
1446 if ( enmArch != RTLDRARCH_WHATEVER
1447 && enmArch != enmArchImage)
1448 return VERR_LDR_ARCH_MISMATCH;
1449
1450 /*
1451 * Read and validate the "optional" header. Convert 32->64 if necessary.
1452 */
1453 IMAGE_OPTIONAL_HEADER64 OptHdr;
1454 rc = pReader->pfnRead(pReader, &OptHdr, FileHdr.SizeOfOptionalHeader, offNtHdrs + 4 + sizeof(IMAGE_FILE_HEADER));
1455 if (RT_FAILURE(rc))
1456 return rc;
1457 if (FileHdr.SizeOfOptionalHeader != sizeof(OptHdr))
1458 rtldrPEConvert32BitOptionalHeaderTo64Bit(&OptHdr);
1459 rc = rtldrPEValidateOptionalHeader(&OptHdr, pszLogName, offNtHdrs, &FileHdr, pReader->pfnSize(pReader));
1460 if (RT_FAILURE(rc))
1461 return rc;
1462
1463 /*
1464 * Read and validate section headers.
1465 */
1466 const size_t cbSections = sizeof(IMAGE_SECTION_HEADER) * FileHdr.NumberOfSections;
1467 PIMAGE_SECTION_HEADER paSections = (PIMAGE_SECTION_HEADER)RTMemAlloc(cbSections);
1468 if (!paSections)
1469 return VERR_NO_MEMORY;
1470 rc = pReader->pfnRead(pReader, paSections, cbSections, offNtHdrs + 4 + sizeof(IMAGE_FILE_HEADER) + FileHdr.SizeOfOptionalHeader);
1471 if (RT_SUCCESS(rc))
1472 {
1473 rc = rtldrPEValidateSectionHeaders(paSections, FileHdr.NumberOfSections, pszLogName,
1474 &OptHdr, pReader->pfnSize(pReader));
1475 if (RT_SUCCESS(rc))
1476 {
1477 /*
1478 * Allocate and initialize the PE module structure.
1479 */
1480 PRTLDRMODPE pModPe = (PRTLDRMODPE)RTMemAllocZ(sizeof(*pModPe));
1481 if (pModPe)
1482 {
1483 pModPe->Core.u32Magic = RTLDRMOD_MAGIC;
1484 pModPe->Core.eState = LDR_STATE_OPENED;
1485 if (FileHdr.SizeOfOptionalHeader == sizeof(OptHdr))
1486 pModPe->Core.pOps = &s_rtldrPE64Ops.Core;
1487 else
1488 pModPe->Core.pOps = &s_rtldrPE32Ops.Core;
1489 pModPe->pReader = pReader;
1490 pModPe->pvBits = NULL;
1491 pModPe->offNtHdrs = offNtHdrs;
1492 pModPe->u16Machine = FileHdr.Machine;
1493 pModPe->fFile = FileHdr.Characteristics;
1494 pModPe->cSections = FileHdr.NumberOfSections;
1495 pModPe->paSections = paSections;
1496 pModPe->uEntryPointRVA= OptHdr.AddressOfEntryPoint;
1497 pModPe->uImageBase = (RTUINTPTR)OptHdr.ImageBase;
1498 pModPe->cbImage = OptHdr.SizeOfImage;
1499 pModPe->cbHeaders = OptHdr.SizeOfHeaders;
1500 pModPe->ImportDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
1501 pModPe->RelocDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
1502 pModPe->ExportDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
1503
1504 /*
1505 * Perform validation of some selected data directories which requires
1506 * inspection of the actual data.
1507 */
1508 rc = rtldrPEValidateDirectories(pModPe, &OptHdr);
1509 if (RT_SUCCESS(rc))
1510 {
1511 *phLdrMod = &pModPe->Core;
1512 return VINF_SUCCESS;
1513 }
1514 RTMemFree(pModPe);
1515 }
1516 else
1517 rc = VERR_NO_MEMORY;
1518 }
1519 }
1520 RTMemFree(paSections);
1521 return rc;
1522}
1523
1524
1525
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