VirtualBox

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

最後變更 在這個檔案從5999是 5999,由 vboxsync 提交於 17 年 前

The Giant CDDL Dual-License Header Change.

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

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