VirtualBox

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

Last change on this file since 46134 was 46133, checked in by vboxsync, 12 years ago

build fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 89.4 KB
Line 
1/* $Id: ldrPE.cpp 46133 2013-05-16 17:58:42Z vboxsync $ */
2/** @file
3 * IPRT - Binary Image Loader, Portable Executable (PE).
4 */
5
6/*
7 * Copyright (C) 2006-2012 Oracle Corporation
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
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#define LOG_GROUP RTLOGGROUP_LDR
32#include <iprt/ldr.h>
33#include "internal/iprt.h"
34
35#include <iprt/alloc.h>
36#include <iprt/assert.h>
37#include <iprt/log.h>
38#include <iprt/path.h>
39#include <iprt/string.h>
40#include <iprt/err.h>
41#include <iprt/formats/codeview.h>
42#include "internal/ldrPE.h"
43#include "internal/ldr.h"
44
45
46/*******************************************************************************
47* Defined Constants And Macros *
48*******************************************************************************/
49/** Converts rva to a type.
50 * @param pvBits Pointer to base of image bits.
51 * @param rva Relative virtual address.
52 * @param type Type.
53 */
54#define PE_RVA2TYPE(pvBits, rva, type) ((type) ((uintptr_t)pvBits + (uintptr_t)(rva)) )
55
56
57/*******************************************************************************
58* Structures and Typedefs *
59*******************************************************************************/
60/**
61 * The PE loader structure.
62 */
63typedef struct RTLDRMODPE
64{
65 /** Core module structure. */
66 RTLDRMODINTERNAL Core;
67 /** Pointer to internal copy of image bits.
68 * @todo the reader should take care of this. */
69 void *pvBits;
70 /** The offset of the NT headers. */
71 RTFOFF offNtHdrs;
72 /** The offset of the first byte after the section table. */
73 RTFOFF offEndOfHdrs;
74
75 /** The machine type (IMAGE_FILE_HEADER::Machine). */
76 uint16_t u16Machine;
77 /** The file flags (IMAGE_FILE_HEADER::Characteristics). */
78 uint16_t fFile;
79 /** Number of sections (IMAGE_FILE_HEADER::NumberOfSections). */
80 unsigned cSections;
81 /** Pointer to an array of the section headers related to the file. */
82 PIMAGE_SECTION_HEADER paSections;
83
84 /** The RVA of the entry point (IMAGE_OPTIONAL_HEADER32::AddressOfEntryPoint). */
85 RTUINTPTR uEntryPointRVA;
86 /** The base address of the image at link time (IMAGE_OPTIONAL_HEADER32::ImageBase). */
87 RTUINTPTR uImageBase;
88 /** The size of the loaded image (IMAGE_OPTIONAL_HEADER32::SizeOfImage). */
89 uint32_t cbImage;
90 /** Size of the header (IMAGE_OPTIONAL_HEADER32::SizeOfHeaders). */
91 uint32_t cbHeaders;
92 /** The image timestamp. */
93 uint32_t uTimestamp;
94 /** The import data directory entry. */
95 IMAGE_DATA_DIRECTORY ImportDir;
96 /** The base relocation data directory entry. */
97 IMAGE_DATA_DIRECTORY RelocDir;
98 /** The export data directory entry. */
99 IMAGE_DATA_DIRECTORY ExportDir;
100 /** The debug directory entry. */
101 IMAGE_DATA_DIRECTORY DebugDir;
102} RTLDRMODPE, *PRTLDRMODPE;
103
104/**
105 * PE Loader module operations.
106 *
107 * The PE loader has one operation which is a bit different between 32-bit and 64-bit PE images,
108 * and for historical and performance reasons have been split into separate functions. Thus the
109 * PE loader extends the RTLDROPS structure with this one entry.
110 */
111typedef struct RTLDROPSPE
112{
113 /** The usual ops. */
114 RTLDROPS Core;
115
116 /**
117 * Resolves all imports.
118 *
119 * @returns iprt status code.
120 * @param pModPe Pointer to the PE loader module structure.
121 * @param pvBitsR Where to read raw image bits. (optional)
122 * @param pvBitsW Where to store the imports. The size of this buffer is equal or
123 * larger to the value returned by pfnGetImageSize().
124 * @param pfnGetImport The callback function to use to resolve imports (aka unresolved externals).
125 * @param pvUser User argument to pass to the callback.
126 */
127 DECLCALLBACKMEMBER(int, pfnResolveImports)(PRTLDRMODPE pModPe, const void *pvBitsR, void *pvBitsW, PFNRTLDRIMPORT pfnGetImport, void *pvUser);
128
129 /** Dummy entry to make sure we've initialized it all. */
130 RTUINT uDummy;
131} RTLDROPSPE, *PRTLDROPSPE;
132
133
134/*******************************************************************************
135* Internal Functions *
136*******************************************************************************/
137static void rtldrPEConvert32BitOptionalHeaderTo64Bit(PIMAGE_OPTIONAL_HEADER64 pOptHdr);
138static void rtldrPEConvert32BitLoadConfigTo64Bit(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg);
139static int rtldrPEApplyFixups(PRTLDRMODPE pModPe, const void *pvBitsR, void *pvBitsW, RTUINTPTR BaseAddress, RTUINTPTR OldBaseAddress);
140
141
142
143/**
144 * Reads a section of a PE image given by RVA + size, using mapped bits if
145 * available or allocating heap memory and reading from the file.
146 *
147 * @returns IPRT status code.
148 * @param pThis Pointer to the PE loader module structure.
149 * @param pvBits Read only bits if available. NULL if not.
150 * @param uRva The RVA to read at.
151 * @param cbMem The number of bytes to read.
152 * @param ppvMem Where to return the memory on success (heap or
153 * inside pvBits).
154 */
155static int rtldrPEReadPartByRva(PRTLDRMODPE pThis, const void *pvBits, uint32_t uRva, uint32_t cbMem, void const **ppvMem)
156{
157 *ppvMem = NULL;
158 if (!cbMem)
159 return VINF_SUCCESS;
160
161 /*
162 * Use bits if we've got some.
163 */
164 if (pvBits)
165 {
166 *ppvMem = (uint8_t const *)pvBits + uRva;
167 return VINF_SUCCESS;
168 }
169 if (pThis->pvBits)
170 {
171 *ppvMem = (uint8_t const *)pThis->pvBits + uRva;
172 return VINF_SUCCESS;
173 }
174
175 /*
176 * Allocate a buffer and read the bits from the file (or whatever).
177 */
178 if (!pThis->Core.pReader)
179 return VERR_ACCESS_DENIED;
180
181 uint8_t *pbMem = (uint8_t *)RTMemAllocZ(cbMem);
182 if (!pbMem)
183 return VERR_NO_MEMORY;
184 *ppvMem = pbMem;
185
186 /* Do the reading on a per section base. */
187 RTFOFF const cbFile = pThis->Core.pReader->pfnSize(pThis->Core.pReader);
188 for (;;)
189 {
190 /* Translate the RVA into a file offset. */
191 uint32_t offFile = uRva;
192 uint32_t cbToRead = cbMem;
193 uint32_t cbToAdv = cbMem;
194
195 if (uRva < pThis->paSections[0].VirtualAddress)
196 {
197 /* Special header section. */
198 cbToRead = pThis->paSections[0].VirtualAddress - uRva;
199 if (cbToRead > cbMem)
200 cbToRead = cbMem;
201 cbToAdv = cbToRead;
202
203 /* The following capping is an approximation. */
204 uint32_t offFirstRawData = RT_ALIGN(pThis->cbHeaders, _4K);
205 if ( pThis->paSections[0].PointerToRawData > 0
206 && pThis->paSections[0].SizeOfRawData > 0)
207 offFirstRawData = pThis->paSections[0].PointerToRawData;
208 if (offFile > offFirstRawData)
209 cbToRead = 0;
210 else if (offFile + cbToRead > offFirstRawData)
211 cbToRead = offFile + cbToRead - offFirstRawData;
212 }
213 else
214 {
215 /* Find the matching section and its mapping size. */
216 uint32_t j = 0;
217 uint32_t cbMapping = 0;
218 while (j < pThis->cSections)
219 {
220 cbMapping = (j + 1 < pThis->cSections ? pThis->paSections[j + 1].VirtualAddress : pThis->cbImage)
221 - pThis->paSections[j].VirtualAddress;
222 if (uRva - pThis->paSections[j].VirtualAddress < cbMapping)
223 break;
224 j++;
225 }
226 if (j >= cbMapping)
227 break; /* This shouldn't happen, just return zeros if it does. */
228
229 /* Adjust the sizes and calc the file offset. */
230 if (cbToAdv > cbMapping)
231 cbToAdv = cbToRead = cbMapping;
232 if ( pThis->paSections[j].PointerToRawData > 0
233 && pThis->paSections[j].SizeOfRawData > 0)
234 {
235 offFile = uRva - pThis->paSections[j].VirtualAddress;
236 if (offFile + cbToRead > pThis->paSections[j].SizeOfRawData)
237 cbToRead = pThis->paSections[j].SizeOfRawData - offFile;
238 offFile += pThis->paSections[j].PointerToRawData;
239 }
240 else
241 {
242 offFile = -1;
243 cbToRead = 0;
244 }
245 }
246
247 /* Perform the read after adjusting a little (paranoia). */
248 if (offFile > cbFile)
249 cbToRead = 0;
250 if (cbToRead)
251 {
252 if ((RTFOFF)offFile + cbToRead > cbFile)
253 cbToRead = cbFile - (RTFOFF)offFile;
254 int rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pbMem, cbToRead, offFile);
255 if (RT_FAILURE(rc))
256 {
257 RTMemFree((void *)*ppvMem);
258 *ppvMem = NULL;
259 return rc;
260 }
261 }
262
263 /* Advance */
264 if (cbMem == cbToRead)
265 break;
266 cbMem -= cbToRead;
267 pbMem += cbToRead;
268 uRva += cbToRead;
269 }
270
271 return VINF_SUCCESS;
272}
273
274
275/**
276 * Reads a part of a PE file from the file and into a heap block.
277 *
278 * @returns IRPT status code.
279 * @param pThis Pointer to the PE loader module structure..
280 * @param offFile The file offset.
281 * @param cbMem The number of bytes to read.
282 * @param ppvMem Where to return the heap block with the bytes on
283 * success.
284 */
285static int rtldrPEReadPartFromFile(PRTLDRMODPE pThis, uint32_t offFile, uint32_t cbMem, void const **ppvMem)
286{
287 *ppvMem = NULL;
288 if (!cbMem)
289 return VINF_SUCCESS;
290
291 /*
292 * Allocate a buffer and read the bits from the file (or whatever).
293 */
294 if (!pThis->Core.pReader)
295 return VERR_ACCESS_DENIED;
296
297 uint8_t *pbMem = (uint8_t *)RTMemAlloc(cbMem);
298 if (!pbMem)
299 return VERR_NO_MEMORY;
300
301 int rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pbMem, cbMem, offFile);
302 if (RT_FAILURE(rc))
303 {
304 RTMemFree((void *)*ppvMem);
305 return rc;
306 }
307
308 *ppvMem = pbMem;
309 return VINF_SUCCESS;
310}
311
312
313/**
314 * Reads a part of a PE image into memory one way or another.
315 *
316 * Either the RVA or the offFile must be valid. We'll prefer the RVA if
317 * possible.
318 *
319 * @returns IPRT status code.
320 * @param pThis Pointer to the PE loader module structure.
321 * @param pvBits Read only bits if available. NULL if not.
322 * @param uRva The RVA to read at.
323 * @param offFile The file offset.
324 * @param cbMem The number of bytes to read.
325 * @param ppvMem Where to return the memory on success (heap or
326 * inside pvBits).
327 */
328static int rtldrPEReadPart(PRTLDRMODPE pThis, const void *pvBits, RTFOFF offFile, RTLDRADDR uRva,
329 uint32_t cbMem, void const **ppvMem)
330{
331 if (uRva == NIL_RTLDRADDR || uRva > pThis->cbImage)
332 {
333 if (offFile < 0)
334 return VERR_INVALID_PARAMETER;
335 return rtldrPEReadPartFromFile(pThis, offFile, cbMem, ppvMem);
336 }
337 return rtldrPEReadPartByRva(pThis, pvBits, uRva, cbMem, ppvMem);
338}
339
340
341/**
342 * Frees up memory returned by rtldrPEReadPart*.
343 *
344 * @param pThis Pointer to the PE loader module structure..
345 * @param pvBits Read only bits if available. NULL if not..
346 * @param pvMem The memory we were given by the reader method.
347 */
348static void rtldrPEFreePart(PRTLDRMODPE pThis, const void *pvBits, void const *pvMem)
349{
350 if (!pvMem)
351 return;
352
353 if (pvBits && (uintptr_t)pvBits - (uintptr_t)pvMem < pThis->cbImage)
354 return;
355 if (pThis->pvBits && (uintptr_t)pThis->pvBits - (uintptr_t)pvMem < pThis->cbImage)
356 return;
357
358 RTMemFree((void *)pvMem);
359}
360
361
362/** @copydoc RTLDROPS::pfnGetImageSize */
363static DECLCALLBACK(size_t) rtldrPEGetImageSize(PRTLDRMODINTERNAL pMod)
364{
365 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
366 return pModPe->cbImage;
367}
368
369
370/**
371 * Reads the image into memory.
372 *
373 * @returns iprt status code.
374 * @param pModPe The PE module.
375 * @param pvBits Where to store the bits, this buffer is at least pItem->Core.cbImage in size.
376 */
377static int rtldrPEGetBitsNoImportsNorFixups(PRTLDRMODPE pModPe, void *pvBits)
378{
379 /*
380 * Both these checks are related to pfnDone().
381 */
382 PRTLDRREADER pReader = pModPe->Core.pReader;
383 if (!pReader)
384 {
385 AssertMsgFailed(("You've called done!\n"));
386 return VERR_WRONG_ORDER;
387 }
388 if (!pvBits)
389 return VERR_NO_MEMORY;
390
391 /*
392 * Zero everything (could be done per section).
393 */
394 memset(pvBits, 0, pModPe->cbImage);
395
396#ifdef PE_FILE_OFFSET_EQUALS_RVA
397 /*
398 * Read the entire image / file.
399 */
400 const RTFOFF cbRawImage = pReader->pfnSize(pReader)
401 rc = pReader->pfnRead(pReader, pvBits, RT_MIN(pModPe->cbImage, cbRawImage), 0);
402 if (RT_FAILURE(rc))
403 Log(("rtldrPE: %s: Reading %#x bytes at offset %#x failed, %Rrc!!! (the entire image)\n",
404 pReader->pfnLogName(pReader), RT_MIN(pModPe->cbImage, cbRawImage), 0, rc));
405#else
406
407 /*
408 * Read the headers.
409 */
410 int rc = pReader->pfnRead(pReader, pvBits, pModPe->cbHeaders, 0);
411 if (RT_SUCCESS(rc))
412 {
413 /*
414 * Read the sections.
415 */
416 PIMAGE_SECTION_HEADER pSH = pModPe->paSections;
417 for (unsigned cLeft = pModPe->cSections; cLeft > 0; cLeft--, pSH++)
418 if (pSH->SizeOfRawData && pSH->Misc.VirtualSize)
419 {
420 rc = pReader->pfnRead(pReader, (uint8_t *)pvBits + pSH->VirtualAddress, pSH->SizeOfRawData, pSH->PointerToRawData);
421 if (RT_FAILURE(rc))
422 {
423 Log(("rtldrPE: %s: Reading %#x bytes at offset %#x failed, %Rrc - section #%d '%.*s'!!!\n",
424 pReader->pfnLogName(pReader), pSH->SizeOfRawData, pSH->PointerToRawData, rc,
425 pSH - pModPe->paSections, sizeof(pSH->Name), pSH->Name));
426 break;
427 }
428 }
429 }
430 else
431 Log(("rtldrPE: %s: Reading %#x bytes at offset %#x failed, %Rrc!!!\n",
432 pReader->pfnLogName(pReader), pModPe->cbHeaders, 0, rc));
433#endif
434 return rc;
435}
436
437
438/**
439 * Reads the bits into the internal buffer pointed to by PRTLDRMODPE::pvBits.
440 *
441 * @returns iprt status code.
442 * @param pModPe The PE module.
443 */
444static int rtldrPEReadBits(PRTLDRMODPE pModPe)
445{
446 Assert(!pModPe->pvBits);
447 void *pvBitsW = RTMemAllocZ(pModPe->cbImage);
448 if (!pvBitsW)
449 return VERR_NO_MEMORY;
450 int rc = rtldrPEGetBitsNoImportsNorFixups(pModPe, pvBitsW);
451 if (RT_SUCCESS(rc))
452 pModPe->pvBits = pvBitsW;
453 else
454 RTMemFree(pvBitsW);
455 return rc;
456}
457
458
459/** @copydoc RTLDROPS::pfnGetBits */
460static DECLCALLBACK(int) rtldrPEGetBits(PRTLDRMODINTERNAL pMod, void *pvBits, RTUINTPTR BaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser)
461{
462 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
463
464 /*
465 * Read the image.
466 */
467 int rc = rtldrPEGetBitsNoImportsNorFixups(pModPe, pvBits);
468 if (RT_SUCCESS(rc))
469 {
470 /*
471 * Resolve imports.
472 */
473 rc = ((PRTLDROPSPE)pMod->pOps)->pfnResolveImports(pModPe, pvBits, pvBits, pfnGetImport, pvUser);
474 if (RT_SUCCESS(rc))
475 {
476 /*
477 * Apply relocations.
478 */
479 rc = rtldrPEApplyFixups(pModPe, pvBits, pvBits, BaseAddress, pModPe->uImageBase);
480 if (RT_SUCCESS(rc))
481 return rc;
482 AssertMsgFailed(("Failed to apply fixups. rc=%Rrc\n", rc));
483 }
484 else
485 AssertMsgFailed(("Failed to resolve imports. rc=%Rrc\n", rc));
486 }
487 return rc;
488}
489
490
491/** @copydoc RTLDROPSPE::pfnResolveImports */
492static DECLCALLBACK(int) rtldrPEResolveImports32(PRTLDRMODPE pModPe, const void *pvBitsR, void *pvBitsW, PFNRTLDRIMPORT pfnGetImport, void *pvUser)
493{
494 /*
495 * Check if there is actually anything to work on.
496 */
497 if ( !pModPe->ImportDir.VirtualAddress
498 || !pModPe->ImportDir.Size)
499 return 0;
500
501 /*
502 * Walk the IMAGE_IMPORT_DESCRIPTOR table.
503 */
504 int rc = VINF_SUCCESS;
505 PIMAGE_IMPORT_DESCRIPTOR pImps;
506 for (pImps = PE_RVA2TYPE(pvBitsR, pModPe->ImportDir.VirtualAddress, PIMAGE_IMPORT_DESCRIPTOR);
507 !rc && pImps->Name != 0 && pImps->FirstThunk != 0;
508 pImps++)
509 {
510 const char *pszModName = PE_RVA2TYPE(pvBitsR, pImps->Name, const char *);
511 PIMAGE_THUNK_DATA32 pFirstThunk; /* update this. */
512 PIMAGE_THUNK_DATA32 pThunk; /* read from this. */
513 Log3(("RTLdrPE: Import descriptor: %s\n", pszModName));
514 Log4(("RTLdrPE: OriginalFirstThunk = %#RX32\n"
515 "RTLdrPE: TimeDateStamp = %#RX32\n"
516 "RTLdrPE: ForwarderChain = %#RX32\n"
517 "RTLdrPE: Name = %#RX32\n"
518 "RTLdrPE: FirstThunk = %#RX32\n",
519 pImps->u.OriginalFirstThunk, pImps->TimeDateStamp,
520 pImps->ForwarderChain, pImps->Name, pImps->FirstThunk));
521
522 /*
523 * Walk the thunks table(s).
524 */
525 pFirstThunk = PE_RVA2TYPE(pvBitsW, pImps->FirstThunk, PIMAGE_THUNK_DATA32);
526 pThunk = pImps->u.OriginalFirstThunk == 0
527 ? PE_RVA2TYPE(pvBitsR, pImps->FirstThunk, PIMAGE_THUNK_DATA32)
528 : PE_RVA2TYPE(pvBitsR, pImps->u.OriginalFirstThunk, PIMAGE_THUNK_DATA32);
529 while (!rc && pThunk->u1.Ordinal != 0)
530 {
531 RTUINTPTR Value = 0;
532 if (pThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG32)
533 {
534 rc = pfnGetImport(&pModPe->Core, pszModName, NULL, IMAGE_ORDINAL32(pThunk->u1.Ordinal), &Value, pvUser);
535 Log4((RT_SUCCESS(rc) ? "RTLdrPE: %RTptr #%u\n" : "RTLdrPE: %08RX32 #%u rc=%Rrc\n",
536 (uint32_t)Value, IMAGE_ORDINAL32(pThunk->u1.Ordinal), rc));
537 }
538 else if ( pThunk->u1.Ordinal > 0
539 && pThunk->u1.Ordinal < pModPe->cbImage)
540 {
541 rc = pfnGetImport(&pModPe->Core, pszModName, PE_RVA2TYPE(pvBitsR, (char*)(uintptr_t)pThunk->u1.AddressOfData + 2, const char *),
542 ~0, &Value, pvUser);
543 Log4((RT_SUCCESS(rc) ? "RTLdrPE: %RTptr %s\n" : "RTLdrPE: %08RX32 %s rc=%Rrc\n",
544 (uint32_t)Value, PE_RVA2TYPE(pvBitsR, (char*)(uintptr_t)pThunk->u1.AddressOfData + 2, const char *), rc));
545 }
546 else
547 {
548 AssertMsgFailed(("bad import data thunk!\n"));
549 rc = VERR_BAD_EXE_FORMAT;
550 }
551 pFirstThunk->u1.Function = Value;
552 if (pFirstThunk->u1.Function != Value)
553 {
554 AssertMsgFailed(("external symbol address to big!\n"));
555 rc = VERR_ADDRESS_CONFLICT; /** @todo get me a better error status code. */
556 }
557 pThunk++;
558 pFirstThunk++;
559 }
560 }
561
562 return rc;
563}
564
565
566/** @copydoc RTLDROPSPE::pfnResolveImports */
567static DECLCALLBACK(int) rtldrPEResolveImports64(PRTLDRMODPE pModPe, const void *pvBitsR, void *pvBitsW, PFNRTLDRIMPORT pfnGetImport, void *pvUser)
568{
569 /*
570 * Check if there is actually anything to work on.
571 */
572 if ( !pModPe->ImportDir.VirtualAddress
573 || !pModPe->ImportDir.Size)
574 return 0;
575
576 /*
577 * Walk the IMAGE_IMPORT_DESCRIPTOR table.
578 */
579 int rc = VINF_SUCCESS;
580 PIMAGE_IMPORT_DESCRIPTOR pImps;
581 for (pImps = PE_RVA2TYPE(pvBitsR, pModPe->ImportDir.VirtualAddress, PIMAGE_IMPORT_DESCRIPTOR);
582 !rc && pImps->Name != 0 && pImps->FirstThunk != 0;
583 pImps++)
584 {
585 const char * pszModName = PE_RVA2TYPE(pvBitsR, pImps->Name, const char *);
586 PIMAGE_THUNK_DATA64 pFirstThunk; /* update this. */
587 PIMAGE_THUNK_DATA64 pThunk; /* read from this. */
588 Log3(("RTLdrPE: Import descriptor: %s\n", pszModName));
589 Log4(("RTLdrPE: OriginalFirstThunk = %#RX32\n"
590 "RTLdrPE: TimeDateStamp = %#RX32\n"
591 "RTLdrPE: ForwarderChain = %#RX32\n"
592 "RTLdrPE: Name = %#RX32\n"
593 "RTLdrPE: FirstThunk = %#RX32\n",
594 pImps->u.OriginalFirstThunk, pImps->TimeDateStamp,
595 pImps->ForwarderChain, pImps->Name, pImps->FirstThunk));
596
597 /*
598 * Walk the thunks table(s).
599 */
600 pFirstThunk = PE_RVA2TYPE(pvBitsW, pImps->FirstThunk, PIMAGE_THUNK_DATA64);
601 pThunk = pImps->u.OriginalFirstThunk == 0
602 ? PE_RVA2TYPE(pvBitsR, pImps->FirstThunk, PIMAGE_THUNK_DATA64)
603 : PE_RVA2TYPE(pvBitsR, pImps->u.OriginalFirstThunk, PIMAGE_THUNK_DATA64);
604 while (!rc && pThunk->u1.Ordinal != 0)
605 {
606 RTUINTPTR Value = 0;
607 if (pThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG64)
608 {
609 rc = pfnGetImport(&pModPe->Core, pszModName, NULL, (unsigned)IMAGE_ORDINAL64(pThunk->u1.Ordinal), &Value, pvUser);
610 Log4((RT_SUCCESS(rc) ? "RTLdrPE: %016RX64 #%u\n" : "RTLdrPE: %016RX64 #%u rc=%Rrc\n",
611 (uint64_t)Value, (unsigned)IMAGE_ORDINAL64(pThunk->u1.Ordinal), rc));
612 }
613 else if ( pThunk->u1.Ordinal > 0
614 && pThunk->u1.Ordinal < pModPe->cbImage)
615 {
616 /** @todo add validation of the string pointer! */
617 rc = pfnGetImport(&pModPe->Core, pszModName, PE_RVA2TYPE(pvBitsR, (uintptr_t)pThunk->u1.AddressOfData + 2, const char *),
618 ~0, &Value, pvUser);
619 Log4((RT_SUCCESS(rc) ? "RTLdrPE: %016RX64 %s\n" : "RTLdrPE: %016RX64 %s rc=%Rrc\n",
620 (uint64_t)Value, PE_RVA2TYPE(pvBitsR, (uintptr_t)pThunk->u1.AddressOfData + 2, const char *), rc));
621 }
622 else
623 {
624 AssertMsgFailed(("bad import data thunk!\n"));
625 rc = VERR_BAD_EXE_FORMAT;
626 }
627 pFirstThunk->u1.Function = Value;
628 pThunk++;
629 pFirstThunk++;
630 }
631 }
632
633 return rc;
634}
635
636
637/**
638 * Applies fixups.
639 */
640static int rtldrPEApplyFixups(PRTLDRMODPE pModPe, const void *pvBitsR, void *pvBitsW, RTUINTPTR BaseAddress, RTUINTPTR OldBaseAddress)
641{
642 if ( !pModPe->RelocDir.VirtualAddress
643 || !pModPe->RelocDir.Size)
644 return 0;
645
646 /*
647 * Apply delta fixups iterating fixup chunks.
648 */
649 PIMAGE_BASE_RELOCATION pbr = PE_RVA2TYPE(pvBitsR, pModPe->RelocDir.VirtualAddress, PIMAGE_BASE_RELOCATION);
650 PIMAGE_BASE_RELOCATION pBaseRelocs = pbr;
651 unsigned cbBaseRelocs = pModPe->RelocDir.Size;
652 RTUINTPTR uDelta = BaseAddress - OldBaseAddress;
653 Log2(("RTLdrPE: Fixups: uDelta=%#RTptr BaseAddress=%#RTptr OldBaseAddress=%#RTptr\n", uDelta, BaseAddress, OldBaseAddress));
654 Log4(("RTLdrPE: BASERELOC: VirtualAddres=%RX32 Size=%RX32\n", pModPe->RelocDir.VirtualAddress, pModPe->RelocDir.Size));
655 Assert(sizeof(*pbr) == sizeof(uint32_t) * 2);
656
657 while ( (uintptr_t)pbr - (uintptr_t)pBaseRelocs + 8 < cbBaseRelocs /* 8= VirtualAddress and SizeOfBlock members */
658 && pbr->SizeOfBlock >= 8)
659 {
660 uint16_t *pwoffFixup = (uint16_t *)(pbr + 1);
661 uint32_t cRelocations = (pbr->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(uint16_t);
662 Log3(("RTLdrPE: base relocs for %#010x, size %#06x (%d relocs)\n", pbr->VirtualAddress, pbr->SizeOfBlock, cRelocations));
663
664 /* Some bound checking just to be sure it works... */
665 if ((uintptr_t)pbr - (uintptr_t)pBaseRelocs + pbr->SizeOfBlock > cbBaseRelocs)
666 cRelocations = (((uintptr_t)pBaseRelocs + cbBaseRelocs) - (uintptr_t)pbr - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(uint16_t);
667
668 /*
669 * Loop thru the fixups in this chunk.
670 */
671 while (cRelocations != 0)
672 {
673 /*
674 * Common fixup
675 */
676 static const char * const s_apszReloc[16] =
677 {
678 "ABS", "HIGH", "LOW", "HIGHLOW", "HIGHADJ", "MIPS_JMPADDR", "RES6", "RES7",
679 "RES8", "IA64_IMM64", "DIR64", "HIGH3ADJ", "RES12", "RES13", "RES14", "RES15"
680 }; NOREF(s_apszReloc);
681 union
682 {
683 uint16_t *pu16;
684 uint32_t *pu32;
685 uint64_t *pu64;
686 } u;
687 const int offFixup = *pwoffFixup & 0xfff;
688 u.pu32 = PE_RVA2TYPE(pvBitsW, offFixup + pbr->VirtualAddress, uint32_t *);
689 const int fType = *pwoffFixup >> 12;
690 Log4(("RTLdrPE: %08x %s\n", offFixup + pbr->VirtualAddress, s_apszReloc[fType]));
691 switch (fType)
692 {
693 case IMAGE_REL_BASED_HIGHLOW: /* 32-bit, add delta. */
694 *u.pu32 += uDelta;
695 break;
696 case IMAGE_REL_BASED_DIR64: /* 64-bit, add delta. */
697 *u.pu64 += (RTINTPTR)uDelta;
698 break;
699 case IMAGE_REL_BASED_ABSOLUTE: /* Alignment placeholder. */
700 break;
701 /* odd ones */
702 case IMAGE_REL_BASED_LOW: /* 16-bit, add 1st 16-bit part of the delta. */
703 *u.pu16 += (uint16_t)uDelta;
704 break;
705 case IMAGE_REL_BASED_HIGH: /* 16-bit, add 2nd 16-bit part of the delta. */
706 *u.pu16 += (uint16_t)(uDelta >> 16);
707 break;
708 /* never ever seen these next two, and I'm not 100% sure they are correctly implemented here. */
709 case IMAGE_REL_BASED_HIGHADJ:
710 {
711 if (cRelocations <= 1)
712 {
713 AssertMsgFailed(("HIGHADJ missing 2nd record!\n"));
714 return VERR_BAD_EXE_FORMAT;
715 }
716 cRelocations--;
717 pwoffFixup++;
718 int32_t i32 = (uint32_t)(*u.pu16 << 16) | *pwoffFixup;
719 i32 += uDelta;
720 i32 += 0x8000; //??
721 *u.pu16 = (uint16_t)(i32 >> 16);
722 break;
723 }
724 case IMAGE_REL_BASED_HIGH3ADJ:
725 {
726 if (cRelocations <= 2)
727 {
728 AssertMsgFailed(("HIGHADJ3 missing 2nd record!\n"));
729 return VERR_BAD_EXE_FORMAT;
730 }
731 cRelocations -= 2;
732 pwoffFixup++;
733 int64_t i64 = ((uint64_t)*u.pu16 << 32) | *(uint32_t *)pwoffFixup++;
734 i64 += (int64_t)uDelta << 16; //??
735 i64 += 0x80000000;//??
736 *u.pu16 = (uint16_t)(i64 >> 32);
737 break;
738 }
739 default:
740 AssertMsgFailed(("Unknown fixup type %d offset=%#x\n", fType, offFixup));
741 break;
742 }
743
744 /*
745 * Next offset/type
746 */
747 pwoffFixup++;
748 cRelocations--;
749 } /* while loop */
750
751 /*
752 * Next Fixup chunk. (i.e. next page)
753 */
754 pbr = (PIMAGE_BASE_RELOCATION)((uintptr_t)pbr + pbr->SizeOfBlock);
755 } /* while loop */
756
757 return 0;
758}
759
760
761/** @copydoc RTLDROPS::pfnRelocate. */
762static int rtldrPERelocate(PRTLDRMODINTERNAL pMod, void *pvBits, RTUINTPTR NewBaseAddress, RTUINTPTR OldBaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser)
763{
764 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
765
766 /*
767 * Do we have to read the image bits?
768 */
769 if (!pModPe->pvBits)
770 {
771 int rc = rtldrPEReadBits(pModPe);
772 if (RT_FAILURE(rc))
773 return rc;
774 }
775
776 /*
777 * Process imports.
778 */
779 int rc = ((PRTLDROPSPE)pMod->pOps)->pfnResolveImports(pModPe, pModPe->pvBits, pvBits, pfnGetImport, pvUser);
780 if (RT_SUCCESS(rc))
781 {
782 /*
783 * Apply relocations.
784 */
785 rc = rtldrPEApplyFixups(pModPe, pModPe->pvBits, pvBits, NewBaseAddress, OldBaseAddress);
786 AssertRC(rc);
787 }
788 return rc;
789}
790
791
792/** @copydoc RTLDROPS::pfnGetSymbolEx. */
793static DECLCALLBACK(int) rtldrPEGetSymbolEx(PRTLDRMODINTERNAL pMod, const void *pvBits, RTUINTPTR BaseAddress, const char *pszSymbol, RTUINTPTR *pValue)
794{
795 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
796
797 /*
798 * Check if there is actually anything to work on.
799 */
800 if ( !pModPe->ExportDir.VirtualAddress
801 || !pModPe->ExportDir.Size)
802 return VERR_SYMBOL_NOT_FOUND;
803
804 /*
805 * No bits supplied? Do we need to read the bits?
806 */
807 if (!pvBits)
808 {
809 if (!pModPe->pvBits)
810 {
811 int rc = rtldrPEReadBits(pModPe);
812 if (RT_FAILURE(rc))
813 return rc;
814 }
815 pvBits = pModPe->pvBits;
816 }
817
818 PIMAGE_EXPORT_DIRECTORY pExpDir = PE_RVA2TYPE(pvBits, pModPe->ExportDir.VirtualAddress, PIMAGE_EXPORT_DIRECTORY);
819 int iExpOrdinal = 0; /* index into address table. */
820 if ((uintptr_t)pszSymbol <= 0xffff)
821 {
822 /*
823 * Find ordinal export: Simple table lookup.
824 */
825 unsigned uOrdinal = (uintptr_t)pszSymbol & 0xffff;
826 if ( uOrdinal >= pExpDir->Base + RT_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions)
827 || uOrdinal < pExpDir->Base)
828 return VERR_SYMBOL_NOT_FOUND;
829 iExpOrdinal = uOrdinal - pExpDir->Base;
830 }
831 else
832 {
833 /*
834 * Find Named Export: Do binary search on the name table.
835 */
836 uint32_t *paRVANames = PE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, uint32_t *);
837 uint16_t *paOrdinals = PE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, uint16_t *);
838 int iStart = 1;
839 int iEnd = pExpDir->NumberOfNames;
840
841 for (;;)
842 {
843 /* end of search? */
844 if (iStart > iEnd)
845 {
846 #ifdef RT_STRICT
847 /* do a linear search just to verify the correctness of the above algorithm */
848 for (unsigned i = 0; i < pExpDir->NumberOfNames; i++)
849 {
850 AssertMsg(i == 0 || strcmp(PE_RVA2TYPE(pvBits, paRVANames[i], const char *), PE_RVA2TYPE(pvBits, paRVANames[i - 1], const char *)) > 0,
851 ("bug in binary export search!!!\n"));
852 AssertMsg(strcmp(PE_RVA2TYPE(pvBits, paRVANames[i], const char *), pszSymbol) != 0,
853 ("bug in binary export search!!!\n"));
854 }
855 #endif
856 return VERR_SYMBOL_NOT_FOUND;
857 }
858
859 int i = (iEnd - iStart) / 2 + iStart;
860 const char *pszExpName = PE_RVA2TYPE(pvBits, paRVANames[i - 1], const char *);
861 int diff = strcmp(pszExpName, pszSymbol);
862 if (diff > 0) /* pszExpName > pszSymbol: search chunck before i */
863 iEnd = i - 1;
864 else if (diff) /* pszExpName < pszSymbol: search chunk after i */
865 iStart = i + 1;
866 else /* pszExpName == pszSymbol */
867 {
868 iExpOrdinal = paOrdinals[i - 1];
869 break;
870 }
871 } /* binary search thru name table */
872 }
873
874 /*
875 * Found export (iExpOrdinal).
876 */
877 uint32_t * paAddress = PE_RVA2TYPE(pvBits, pExpDir->AddressOfFunctions, uint32_t *);
878 unsigned uRVAExport = paAddress[iExpOrdinal];
879
880 if ( uRVAExport > pModPe->ExportDir.VirtualAddress
881 && uRVAExport < pModPe->ExportDir.VirtualAddress + pModPe->ExportDir.Size)
882 {
883 /* Resolve forwarder. */
884 AssertMsgFailed(("Forwarders are not supported!\n"));
885 return VERR_SYMBOL_NOT_FOUND;
886 }
887
888 /* Get plain export address */
889 *pValue = PE_RVA2TYPE(BaseAddress, uRVAExport, RTUINTPTR);
890
891 return VINF_SUCCESS;
892}
893
894
895/**
896 * Slow version of rtldrPEEnumSymbols that'll work without all of the image
897 * being accessible.
898 *
899 * This is mainly for use in debuggers and similar.
900 */
901static int rtldrPEEnumSymbolsSlow(PRTLDRMODPE pThis, unsigned fFlags, RTUINTPTR BaseAddress,
902 PFNRTLDRENUMSYMS pfnCallback, void *pvUser)
903{
904 /*
905 * We enumerates by ordinal, which means using a slow linear search for
906 * getting any name
907 */
908 PCIMAGE_EXPORT_DIRECTORY pExpDir = NULL;
909 int rc = rtldrPEReadPartByRva(pThis, NULL, pThis->ExportDir.VirtualAddress, pThis->ExportDir.Size,
910 (void const **)&pExpDir);
911 if (RT_FAILURE(rc))
912 return rc;
913 uint32_t const cOrdinals = RT_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions);
914
915 uint32_t const *paAddress = NULL;
916 rc = rtldrPEReadPartByRva(pThis, NULL, pExpDir->AddressOfFunctions, cOrdinals * sizeof(uint32_t),
917 (void const **)&paAddress);
918 uint32_t const *paRVANames = NULL;
919 if (RT_SUCCESS(rc) && pExpDir->NumberOfNames)
920 rc = rtldrPEReadPartByRva(pThis, NULL, pExpDir->AddressOfNames, pExpDir->NumberOfNames * sizeof(uint32_t),
921 (void const **)&paRVANames);
922 uint16_t const *paOrdinals = NULL;
923 if (RT_SUCCESS(rc) && pExpDir->NumberOfNames)
924 rc = rtldrPEReadPartByRva(pThis, NULL, pExpDir->AddressOfNameOrdinals, pExpDir->NumberOfNames * sizeof(uint16_t),
925 (void const **)&paOrdinals);
926 if (RT_SUCCESS(rc))
927 {
928 uintptr_t uNamePrev = 0;
929 for (uint32_t uOrdinal = 0; uOrdinal < cOrdinals; uOrdinal++)
930 {
931 if (paAddress[uOrdinal] /* needed? */)
932 {
933 /*
934 * Look for name.
935 */
936 uint32_t uRvaName = UINT32_MAX;
937 /* Search from previous + 1 to the end. */
938 unsigned uName = uNamePrev + 1;
939 while (uName < pExpDir->NumberOfNames)
940 {
941 if (paOrdinals[uName] == uOrdinal)
942 {
943 uRvaName = paRVANames[uName];
944 uNamePrev = uName;
945 break;
946 }
947 uName++;
948 }
949 if (uRvaName == UINT32_MAX)
950 {
951 /* Search from start to the previous. */
952 uName = 0;
953 for (uName = 0 ; uName <= uNamePrev; uName++)
954 {
955 if (paOrdinals[uName] == uOrdinal)
956 {
957 uRvaName = paRVANames[uName];
958 uNamePrev = uName;
959 break;
960 }
961 }
962 }
963
964 /*
965 * Get address.
966 */
967 uintptr_t uRVAExport = paAddress[uOrdinal];
968 RTUINTPTR Value;
969 if ( uRVAExport - (uintptr_t)pThis->ExportDir.VirtualAddress
970 < pThis->ExportDir.Size)
971 {
972 if (!(fFlags & RTLDR_ENUM_SYMBOL_FLAGS_NO_FWD))
973 {
974 /* Resolve forwarder. */
975 AssertMsgFailed(("Forwarders are not supported!\n"));
976 }
977 continue;
978 }
979
980 /* Get plain export address */
981 Value = PE_RVA2TYPE(BaseAddress, uRVAExport, RTUINTPTR);
982
983 /* Read in the name if found one. */
984 char szAltName[32];
985 const char *pszName = NULL;
986 if (uRvaName != UINT32_MAX)
987 {
988 uint32_t cbName = 0x1000 - (uRvaName & 0xfff);
989 if (cbName < 10 || cbName > 512)
990 cbName = 128;
991 rc = rtldrPEReadPartByRva(pThis, NULL, uRvaName, cbName, (void const **)&pszName);
992 while (RT_SUCCESS(rc) && RTStrNLen(pszName, cbName) == cbName)
993 {
994 rtldrPEFreePart(pThis, NULL, pszName);
995 pszName = NULL;
996 if (cbName >= _4K)
997 break;
998 cbName += 128;
999 rc = rtldrPEReadPartByRva(pThis, NULL, uRvaName, cbName, (void const **)&pszName);
1000 }
1001 }
1002 if (!pszName)
1003 {
1004 RTStrPrintf(szAltName, sizeof(szAltName), "Ordinal%#x", uOrdinal);
1005 pszName = szAltName;
1006 }
1007
1008 /*
1009 * Call back.
1010 */
1011 rc = pfnCallback(&pThis->Core, pszName, uOrdinal + pExpDir->Base, Value, pvUser);
1012 if (pszName != szAltName && pszName)
1013 rtldrPEFreePart(pThis, NULL, pszName);
1014 if (rc)
1015 break;
1016 }
1017 }
1018 }
1019
1020 rtldrPEFreePart(pThis, NULL, paOrdinals);
1021 rtldrPEFreePart(pThis, NULL, paRVANames);
1022 rtldrPEFreePart(pThis, NULL, paAddress);
1023 rtldrPEFreePart(pThis, NULL, pExpDir);
1024 return rc;
1025
1026}
1027
1028
1029/** @copydoc RTLDROPS::pfnEnumSymbols */
1030static DECLCALLBACK(int) rtldrPEEnumSymbols(PRTLDRMODINTERNAL pMod, unsigned fFlags, const void *pvBits, RTUINTPTR BaseAddress,
1031 PFNRTLDRENUMSYMS pfnCallback, void *pvUser)
1032{
1033 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1034 NOREF(fFlags); /* ignored ... */
1035
1036 /*
1037 * Check if there is actually anything to work on.
1038 */
1039 if ( !pModPe->ExportDir.VirtualAddress
1040 || !pModPe->ExportDir.Size)
1041 return VERR_SYMBOL_NOT_FOUND;
1042
1043 /*
1044 * No bits supplied? Do we need to read the bits?
1045 */
1046 if (!pvBits)
1047 {
1048 if (!pModPe->pvBits)
1049 {
1050 int rc = rtldrPEReadBits(pModPe);
1051 if (RT_FAILURE(rc))
1052 return rtldrPEEnumSymbolsSlow(pModPe, fFlags, BaseAddress, pfnCallback, pvUser);
1053 }
1054 pvBits = pModPe->pvBits;
1055 }
1056
1057 /*
1058 * We enumerates by ordinal, which means using a slow linear search for
1059 * getting any name
1060 */
1061 PIMAGE_EXPORT_DIRECTORY pExpDir = PE_RVA2TYPE(pvBits, pModPe->ExportDir.VirtualAddress, PIMAGE_EXPORT_DIRECTORY);
1062 uint32_t *paAddress = PE_RVA2TYPE(pvBits, pExpDir->AddressOfFunctions, uint32_t *);
1063 uint32_t *paRVANames = PE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, uint32_t *);
1064 uint16_t *paOrdinals = PE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, uint16_t *);
1065 uintptr_t uNamePrev = 0;
1066 unsigned cOrdinals = RT_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions);
1067 for (unsigned uOrdinal = 0; uOrdinal < cOrdinals; uOrdinal++)
1068 {
1069 if (paAddress[uOrdinal] /* needed? */)
1070 {
1071 /*
1072 * Look for name.
1073 */
1074 const char *pszName = NULL;
1075 /* Search from previous + 1 to the end. */
1076 unsigned uName = uNamePrev + 1;
1077 while (uName < pExpDir->NumberOfNames)
1078 {
1079 if (paOrdinals[uName] == uOrdinal)
1080 {
1081 pszName = PE_RVA2TYPE(pvBits, paRVANames[uName], const char *);
1082 uNamePrev = uName;
1083 break;
1084 }
1085 uName++;
1086 }
1087 if (!pszName)
1088 {
1089 /* Search from start to the previous. */
1090 uName = 0;
1091 for (uName = 0 ; uName <= uNamePrev; uName++)
1092 {
1093 if (paOrdinals[uName] == uOrdinal)
1094 {
1095 pszName = PE_RVA2TYPE(pvBits, paRVANames[uName], const char *);
1096 uNamePrev = uName;
1097 break;
1098 }
1099 }
1100 }
1101
1102 /*
1103 * Get address.
1104 */
1105 uintptr_t uRVAExport = paAddress[uOrdinal];
1106 RTUINTPTR Value;
1107 if ( uRVAExport - (uintptr_t)pModPe->ExportDir.VirtualAddress
1108 < pModPe->ExportDir.Size)
1109 {
1110 if (!(fFlags & RTLDR_ENUM_SYMBOL_FLAGS_NO_FWD))
1111 {
1112 /* Resolve forwarder. */
1113 AssertMsgFailed(("Forwarders are not supported!\n"));
1114 }
1115 continue;
1116 }
1117
1118 /* Get plain export address */
1119 Value = PE_RVA2TYPE(BaseAddress, uRVAExport, RTUINTPTR);
1120
1121 /*
1122 * Call back.
1123 */
1124 int rc = pfnCallback(pMod, pszName, uOrdinal + pExpDir->Base, Value, pvUser);
1125 if (rc)
1126 return rc;
1127 }
1128 }
1129
1130 return VINF_SUCCESS;
1131}
1132
1133
1134/** @copydoc RTLDROPS::pfnEnumDbgInfo. */
1135static DECLCALLBACK(int) rtldrPE_EnumDbgInfo(PRTLDRMODINTERNAL pMod, const void *pvBits,
1136 PFNRTLDRENUMDBG pfnCallback, void *pvUser)
1137{
1138 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1139 int rc;
1140
1141 /*
1142 * Debug info directory empty?
1143 */
1144 if ( !pModPe->DebugDir.VirtualAddress
1145 || !pModPe->DebugDir.Size)
1146 return VINF_SUCCESS;
1147
1148 /*
1149 * Get the debug directory.
1150 */
1151 if (!pvBits)
1152 pvBits = pModPe->pvBits;
1153
1154 PCIMAGE_DEBUG_DIRECTORY paDbgDir;
1155 int rcRet = rtldrPEReadPartByRva(pModPe, pvBits, pModPe->DebugDir.VirtualAddress, pModPe->DebugDir.Size,
1156 (void const **)&paDbgDir);
1157 if (RT_FAILURE(rcRet))
1158 return rcRet;
1159
1160 /*
1161 * Enumerate the debug directory.
1162 */
1163 uint32_t const cEntries = pModPe->DebugDir.Size / sizeof(paDbgDir[0]);
1164 for (uint32_t i = 0; i < cEntries; i++)
1165 {
1166 if (paDbgDir[i].PointerToRawData < pModPe->offEndOfHdrs)
1167 continue;
1168 if (paDbgDir[i].SizeOfData < 4)
1169 continue;
1170
1171 void const *pvPart = NULL;
1172 char szPath[RTPATH_MAX];
1173 RTLDRDBGINFO DbgInfo;
1174 RT_ZERO(DbgInfo.u);
1175 DbgInfo.iDbgInfo = i;
1176 DbgInfo.offFile = paDbgDir[i].PointerToRawData;
1177 DbgInfo.LinkAddress = paDbgDir[i].AddressOfRawData < pModPe->cbImage
1178 && paDbgDir[i].AddressOfRawData >= pModPe->offEndOfHdrs
1179 ? paDbgDir[i].AddressOfRawData : NIL_RTLDRADDR;
1180 DbgInfo.cb = paDbgDir[i].SizeOfData;
1181 DbgInfo.pszExtFile = NULL;
1182
1183 rc = VINF_SUCCESS;
1184 switch (paDbgDir[i].Type)
1185 {
1186 case IMAGE_DEBUG_TYPE_CODEVIEW:
1187 DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW;
1188 DbgInfo.u.Cv.uMajorVer = paDbgDir[i].MajorVersion;
1189 DbgInfo.u.Cv.uMinorVer = paDbgDir[i].MinorVersion;
1190 DbgInfo.u.Cv.uTimestamp = paDbgDir[i].TimeDateStamp;
1191 if ( paDbgDir[i].SizeOfData < sizeof(szPath)
1192 && paDbgDir[i].SizeOfData > 16
1193 && ( DbgInfo.LinkAddress != NIL_RTLDRADDR
1194 || DbgInfo.offFile > 0)
1195 )
1196 {
1197 rc = rtldrPEReadPart(pModPe, pvBits, DbgInfo.offFile, DbgInfo.LinkAddress, paDbgDir[i].SizeOfData, &pvPart);
1198 if (RT_SUCCESS(rc))
1199 {
1200 PCCVPDB20INFO pCv20 = (PCCVPDB20INFO)pvPart;
1201 if ( pCv20->u32Magic == CVPDB20INFO_MAGIC
1202 && pCv20->offDbgInfo == 0
1203 && paDbgDir[i].SizeOfData > RT_UOFFSETOF(CVPDB20INFO, szPdbFilename) )
1204 {
1205 DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW_PDB20;
1206 DbgInfo.u.Pdb20.cbImage = pModPe->cbImage;
1207 DbgInfo.u.Pdb20.uTimestamp = pCv20->uTimestamp;
1208 DbgInfo.u.Pdb20.uAge = pCv20->uAge;
1209 DbgInfo.pszExtFile = (const char *)&pCv20->szPdbFilename[0];
1210 }
1211 else if ( pCv20->u32Magic == CVPDB70INFO_MAGIC
1212 && paDbgDir[i].SizeOfData > RT_UOFFSETOF(CVPDB70INFO, szPdbFilename) )
1213 {
1214 PCCVPDB70INFO pCv70 = (PCCVPDB70INFO)pCv20;
1215 DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW_PDB70;
1216 DbgInfo.u.Pdb70.cbImage = pModPe->cbImage;
1217 DbgInfo.u.Pdb70.Uuid = pCv70->PdbUuid;
1218 DbgInfo.u.Pdb70.uAge = pCv70->uAge;
1219 DbgInfo.pszExtFile = (const char *)&pCv70->szPdbFilename[0];
1220 }
1221 }
1222 else
1223 rcRet = rc;
1224 }
1225 break;
1226
1227 case IMAGE_DEBUG_TYPE_MISC:
1228 DbgInfo.enmType = RTLDRDBGINFOTYPE_UNKNOWN;
1229 if ( paDbgDir[i].SizeOfData < sizeof(szPath)
1230 && paDbgDir[i].SizeOfData > RT_UOFFSETOF(IMAGE_DEBUG_MISC, Data))
1231 {
1232 DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW_DBG;
1233 DbgInfo.u.Dbg.cbImage = pModPe->cbImage;
1234 if (DbgInfo.LinkAddress != NIL_RTLDRADDR)
1235 DbgInfo.u.Dbg.uTimestamp = paDbgDir[i].TimeDateStamp;
1236 else
1237 DbgInfo.u.Dbg.uTimestamp = pModPe->uTimestamp; /* NT4 SP1 ntfs.sys hack. Generic? */
1238
1239 rc = rtldrPEReadPart(pModPe, pvBits, DbgInfo.offFile, DbgInfo.LinkAddress, paDbgDir[i].SizeOfData, &pvPart);
1240 if (RT_SUCCESS(rc))
1241 {
1242 PCIMAGE_DEBUG_MISC pMisc = (PCIMAGE_DEBUG_MISC)pvPart;
1243 if ( pMisc->DataType == IMAGE_DEBUG_MISC_EXENAME
1244 && pMisc->Length == paDbgDir[i].SizeOfData)
1245 {
1246 if (!pMisc->Unicode)
1247 DbgInfo.pszExtFile = (const char *)&pMisc->Data[0];
1248 else
1249 {
1250 char *pszPath = szPath;
1251 rc = RTUtf16ToUtf8Ex((PCRTUTF16)&pMisc->Data[0],
1252 (pMisc->Length - RT_OFFSETOF(IMAGE_DEBUG_MISC, Data)) / sizeof(RTUTF16),
1253 &pszPath, sizeof(szPath), NULL);
1254 if (RT_SUCCESS(rc))
1255 DbgInfo.pszExtFile = szPath;
1256 else
1257 rcRet = rc; /* continue without a filename. */
1258 }
1259 }
1260 }
1261 else
1262 rcRet = rc; /* continue without a filename. */
1263 }
1264 break;
1265
1266 default:
1267 DbgInfo.enmType = RTLDRDBGINFOTYPE_UNKNOWN;
1268 break;
1269 }
1270
1271 /* Fix (hack) the file name encoding. We don't have Windows-1252 handy,
1272 so we'll be using Latin-1 as a reasonable approximation.
1273 (I don't think we know exactly which encoding this is anyway, as
1274 it's probably the current ANSI/Windows code page for the process
1275 generating the image anyways.) */
1276 if (DbgInfo.pszExtFile && DbgInfo.pszExtFile != szPath)
1277 {
1278 char *pszPath = szPath;
1279 rc = RTLatin1ToUtf8Ex(DbgInfo.pszExtFile,
1280 paDbgDir[i].SizeOfData - ((uintptr_t)DbgInfo.pszExtFile - (uintptr_t)pvBits),
1281 &pszPath, sizeof(szPath), NULL);
1282 if (RT_FAILURE(rc))
1283 {
1284 rcRet = rc;
1285 DbgInfo.pszExtFile = NULL;
1286 }
1287 }
1288 if (DbgInfo.pszExtFile)
1289 RTPathChangeToUnixSlashes(szPath, true /*fForce*/);
1290
1291 rc = pfnCallback(pMod, &DbgInfo, pvUser);
1292 rtldrPEFreePart(pModPe, pvBits, pvPart);
1293 if (rc != VINF_SUCCESS)
1294 {
1295 rcRet = rc;
1296 break;
1297 }
1298 }
1299
1300 rtldrPEFreePart(pModPe, pvBits, paDbgDir);
1301 return rcRet;
1302}
1303
1304
1305/** @copydoc RTLDROPS::pfnEnumSegments. */
1306static DECLCALLBACK(int) rtldrPE_EnumSegments(PRTLDRMODINTERNAL pMod, PFNRTLDRENUMSEGS pfnCallback, void *pvUser)
1307{
1308 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1309 RTLDRSEG SegInfo;
1310
1311 /*
1312 * The first section is a fake one covering the headers.
1313 */
1314 SegInfo.pchName = "NtHdrs";
1315 SegInfo.cchName = 6;
1316 SegInfo.SelFlat = 0;
1317 SegInfo.Sel16bit = 0;
1318 SegInfo.fFlags = 0;
1319 SegInfo.fProt = RTMEM_PROT_READ;
1320 SegInfo.Alignment = 1;
1321 SegInfo.LinkAddress = pModPe->uImageBase;
1322 SegInfo.RVA = 0;
1323 SegInfo.offFile = 0;
1324 SegInfo.cb = pModPe->cbHeaders;
1325 SegInfo.cbFile = pModPe->cbHeaders;
1326 SegInfo.cbMapped = pModPe->cbHeaders;
1327 if ((pModPe->paSections[0].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
1328 SegInfo.cbMapped = pModPe->paSections[0].VirtualAddress;
1329 int rc = pfnCallback(pMod, &SegInfo, pvUser);
1330
1331 /*
1332 * Then all the normal sections.
1333 */
1334 PCIMAGE_SECTION_HEADER pSh = pModPe->paSections;
1335 for (uint32_t i = 0; i < pModPe->cSections && rc == VINF_SUCCESS; i++, pSh++)
1336 {
1337 SegInfo.pchName = (const char *)&pSh->Name[0];
1338 SegInfo.cchName = (uint32_t)RTStrNLen(SegInfo.pchName, sizeof(pSh->Name));
1339 SegInfo.SelFlat = 0;
1340 SegInfo.Sel16bit = 0;
1341 SegInfo.fFlags = 0;
1342 SegInfo.fProt = RTMEM_PROT_NONE;
1343 if (pSh->Characteristics & IMAGE_SCN_MEM_READ)
1344 SegInfo.fProt |= RTMEM_PROT_READ;
1345 if (pSh->Characteristics & IMAGE_SCN_MEM_WRITE)
1346 SegInfo.fProt |= RTMEM_PROT_WRITE;
1347 if (pSh->Characteristics & IMAGE_SCN_MEM_EXECUTE)
1348 SegInfo.fProt |= RTMEM_PROT_EXEC;
1349 SegInfo.Alignment = (pSh->Characteristics & IMAGE_SCN_ALIGN_MASK) >> IMAGE_SCN_ALIGN_SHIFT;
1350 if (SegInfo.Alignment > 0)
1351 SegInfo.Alignment = RT_BIT_64(SegInfo.Alignment - 1);
1352 if (pSh->Characteristics & IMAGE_SCN_TYPE_NOLOAD)
1353 {
1354 SegInfo.LinkAddress = NIL_RTLDRADDR;
1355 SegInfo.RVA = NIL_RTLDRADDR;
1356 SegInfo.cbMapped = pSh->Misc.VirtualSize;
1357 }
1358 else
1359 {
1360 SegInfo.LinkAddress = pSh->VirtualAddress + pModPe->uImageBase ;
1361 SegInfo.RVA = pSh->VirtualAddress;
1362 SegInfo.cbMapped = RT_ALIGN(SegInfo.cb, SegInfo.Alignment);
1363 if (i + 1 < pModPe->cSections && !(pSh[1].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
1364 SegInfo.cbMapped = pSh[1].VirtualAddress - pSh->VirtualAddress;
1365 }
1366 SegInfo.cb = pSh->Misc.VirtualSize;
1367 if (pSh->PointerToRawData == 0 || pSh->SizeOfRawData == 0)
1368 {
1369 SegInfo.offFile = -1;
1370 SegInfo.cbFile = 0;
1371 }
1372 else
1373 {
1374 SegInfo.offFile = pSh->PointerToRawData;
1375 SegInfo.cbFile = pSh->SizeOfRawData;
1376 }
1377
1378 rc = pfnCallback(pMod, &SegInfo, pvUser);
1379 }
1380
1381 return rc;
1382}
1383
1384
1385/** @copydoc RTLDROPS::pfnLinkAddressToSegOffset. */
1386static DECLCALLBACK(int) rtldrPE_LinkAddressToSegOffset(PRTLDRMODINTERNAL pMod, RTLDRADDR LinkAddress,
1387 uint32_t *piSeg, PRTLDRADDR poffSeg)
1388{
1389 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1390
1391 LinkAddress -= pModPe->uImageBase;
1392
1393 /* Special header segment. */
1394 if (LinkAddress < pModPe->paSections[0].VirtualAddress)
1395 {
1396 *piSeg = 0;
1397 *poffSeg = LinkAddress;
1398 return VINF_SUCCESS;
1399 }
1400
1401 /*
1402 * Search the normal sections. (Could do this in binary fashion, they're
1403 * sorted, but too much bother right now.)
1404 */
1405 if (LinkAddress > pModPe->cbImage)
1406 return VERR_LDR_INVALID_LINK_ADDRESS;
1407 uint32_t i = pModPe->cSections;
1408 PCIMAGE_SECTION_HEADER paShs = pModPe->paSections;
1409 while (i-- > 0)
1410 if (!(paShs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
1411 {
1412 uint32_t uAddr = paShs[i].VirtualAddress;
1413 if (LinkAddress >= uAddr)
1414 {
1415 *poffSeg = LinkAddress - uAddr;
1416 *piSeg = i + 1;
1417 return VINF_SUCCESS;
1418 }
1419 }
1420
1421 return VERR_LDR_INVALID_LINK_ADDRESS;
1422}
1423
1424
1425/** @copydoc RTLDROPS::pfnLinkAddressToRva. */
1426static DECLCALLBACK(int) rtldrPE_LinkAddressToRva(PRTLDRMODINTERNAL pMod, RTLDRADDR LinkAddress, PRTLDRADDR pRva)
1427{
1428 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1429
1430 LinkAddress -= pModPe->uImageBase;
1431 if (LinkAddress > pModPe->cbImage)
1432 return VERR_LDR_INVALID_LINK_ADDRESS;
1433 *pRva = LinkAddress;
1434
1435 return VINF_SUCCESS;
1436}
1437
1438
1439/** @copydoc RTLDROPS::pfnSegOffsetToRva. */
1440static DECLCALLBACK(int) rtldrPE_SegOffsetToRva(PRTLDRMODINTERNAL pMod, uint32_t iSeg, RTLDRADDR offSeg,
1441 PRTLDRADDR pRva)
1442{
1443 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1444
1445 if (iSeg > pModPe->cSections)
1446 return VERR_LDR_INVALID_SEG_OFFSET;
1447
1448 /** @todo should validate offSeg here... too lazy right now. */
1449 if (iSeg == 0)
1450 *pRva = offSeg;
1451 else if (pModPe->paSections[iSeg].Characteristics & IMAGE_SCN_TYPE_NOLOAD)
1452 return VERR_LDR_INVALID_SEG_OFFSET;
1453 else
1454 *pRva = offSeg + pModPe->paSections[iSeg].VirtualAddress;
1455 return VINF_SUCCESS;
1456}
1457
1458
1459/** @copydoc RTLDROPS::pfnRvaToSegOffset. */
1460static DECLCALLBACK(int) rtldrPE_RvaToSegOffset(PRTLDRMODINTERNAL pMod, RTLDRADDR Rva,
1461 uint32_t *piSeg, PRTLDRADDR poffSeg)
1462{
1463 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1464 int rc = rtldrPE_LinkAddressToSegOffset(pMod, Rva + pModPe->uImageBase, piSeg, poffSeg);
1465 if (RT_FAILURE(rc))
1466 rc = VERR_LDR_INVALID_RVA;
1467 return rc;
1468}
1469
1470
1471/** @copydoc RTLDROPS::pfnDone */
1472static DECLCALLBACK(int) rtldrPEDone(PRTLDRMODINTERNAL pMod)
1473{
1474 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1475 if (pModPe->pvBits)
1476 {
1477 RTMemFree(pModPe->pvBits);
1478 pModPe->pvBits = NULL;
1479 }
1480 return VINF_SUCCESS;
1481}
1482
1483/** @copydoc RTLDROPS::pfnClose */
1484static DECLCALLBACK(int) rtldrPEClose(PRTLDRMODINTERNAL pMod)
1485{
1486 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1487 if (pModPe->paSections)
1488 {
1489 RTMemFree(pModPe->paSections);
1490 pModPe->paSections = NULL;
1491 }
1492 if (pModPe->pvBits)
1493 {
1494 RTMemFree(pModPe->pvBits);
1495 pModPe->pvBits = NULL;
1496 }
1497 if (pModPe->Core.pReader)
1498 {
1499 int rc = pModPe->Core.pReader->pfnDestroy(pModPe->Core.pReader);
1500 AssertRC(rc);
1501 pModPe->Core.pReader = NULL;
1502 }
1503 return VINF_SUCCESS;
1504}
1505
1506
1507/**
1508 * Operations for a 32-bit PE module.
1509 */
1510static const RTLDROPSPE s_rtldrPE32Ops =
1511{
1512 {
1513 "pe32",
1514 rtldrPEClose,
1515 NULL,
1516 rtldrPEDone,
1517 rtldrPEEnumSymbols,
1518 /* ext */
1519 rtldrPEGetImageSize,
1520 rtldrPEGetBits,
1521 rtldrPERelocate,
1522 rtldrPEGetSymbolEx,
1523 rtldrPE_EnumDbgInfo,
1524 rtldrPE_EnumSegments,
1525 rtldrPE_LinkAddressToSegOffset,
1526 rtldrPE_LinkAddressToRva,
1527 rtldrPE_SegOffsetToRva,
1528 rtldrPE_RvaToSegOffset,
1529 42
1530 },
1531 rtldrPEResolveImports32,
1532 42
1533};
1534
1535
1536/**
1537 * Operations for a 64-bit PE module.
1538 */
1539static const RTLDROPSPE s_rtldrPE64Ops =
1540{
1541 {
1542 "pe64",
1543 rtldrPEClose,
1544 NULL,
1545 rtldrPEDone,
1546 rtldrPEEnumSymbols,
1547 /* ext */
1548 rtldrPEGetImageSize,
1549 rtldrPEGetBits,
1550 rtldrPERelocate,
1551 rtldrPEGetSymbolEx,
1552 rtldrPE_EnumDbgInfo,
1553 rtldrPE_EnumSegments,
1554 rtldrPE_LinkAddressToSegOffset,
1555 rtldrPE_LinkAddressToRva,
1556 rtldrPE_SegOffsetToRva,
1557 rtldrPE_RvaToSegOffset,
1558 42
1559 },
1560 rtldrPEResolveImports64,
1561 42
1562};
1563
1564
1565/**
1566 * Converts the optional header from 32 bit to 64 bit.
1567 * This is a rather simple task, if you start from the right end.
1568 *
1569 * @param pOptHdr On input this is a PIMAGE_OPTIONAL_HEADER32.
1570 * On output this will be a PIMAGE_OPTIONAL_HEADER64.
1571 */
1572static void rtldrPEConvert32BitOptionalHeaderTo64Bit(PIMAGE_OPTIONAL_HEADER64 pOptHdr)
1573{
1574 /*
1575 * volatile everywhere! Trying to prevent the compiler being a smarta$$ and reorder stuff.
1576 */
1577 IMAGE_OPTIONAL_HEADER32 volatile *pOptHdr32 = (IMAGE_OPTIONAL_HEADER32 volatile *)pOptHdr;
1578 IMAGE_OPTIONAL_HEADER64 volatile *pOptHdr64 = pOptHdr;
1579
1580 /* from LoaderFlags and out the difference is 4 * 32-bits. */
1581 Assert(RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, LoaderFlags) + 16 == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, LoaderFlags));
1582 Assert( RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]) + 16
1583 == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]));
1584 uint32_t volatile *pu32Dst = (uint32_t *)&pOptHdr64->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1;
1585 const uint32_t volatile *pu32Src = (uint32_t *)&pOptHdr32->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1;
1586 const uint32_t volatile *pu32SrcLast = (uint32_t *)&pOptHdr32->LoaderFlags;
1587 while (pu32Src >= pu32SrcLast)
1588 *pu32Dst-- = *pu32Src--;
1589
1590 /* the previous 4 fields are 32/64 and needs special attention. */
1591 pOptHdr64->SizeOfHeapCommit = pOptHdr32->SizeOfHeapCommit;
1592 pOptHdr64->SizeOfHeapReserve = pOptHdr32->SizeOfHeapReserve;
1593 pOptHdr64->SizeOfStackCommit = pOptHdr32->SizeOfStackCommit;
1594 uint32_t u32SizeOfStackReserve = pOptHdr32->SizeOfStackReserve;
1595 pOptHdr64->SizeOfStackReserve = u32SizeOfStackReserve;
1596
1597 /* The rest matches except for BaseOfData which has been merged into ImageBase in the 64-bit version..
1598 * Thus, ImageBase needs some special treatment. It will probably work fine assigning one to the
1599 * other since this is all declared volatile, but taking now chances, we'll use a temp variable.
1600 */
1601 Assert(RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, SizeOfStackReserve) == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, SizeOfStackReserve));
1602 Assert(RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, BaseOfData) == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, ImageBase));
1603 Assert(RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, SectionAlignment) == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, SectionAlignment));
1604 uint32_t u32ImageBase = pOptHdr32->ImageBase;
1605 pOptHdr64->ImageBase = u32ImageBase;
1606}
1607
1608
1609/**
1610 * Converts the load config directory from 32 bit to 64 bit.
1611 * This is a rather simple task, if you start from the right end.
1612 *
1613 * @param pLoadCfg On input this is a PIMAGE_LOAD_CONFIG_DIRECTORY32.
1614 * On output this will be a PIMAGE_LOAD_CONFIG_DIRECTORY64.
1615 */
1616static void rtldrPEConvert32BitLoadConfigTo64Bit(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg)
1617{
1618 /*
1619 * volatile everywhere! Trying to prevent the compiler being a smarta$$ and reorder stuff.
1620 */
1621 IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *pLoadCfg32 = (IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *)pLoadCfg;
1622 IMAGE_LOAD_CONFIG_DIRECTORY64 volatile *pLoadCfg64 = pLoadCfg;
1623
1624 pLoadCfg64->SEHandlerCount = pLoadCfg32->SEHandlerCount;
1625 pLoadCfg64->SEHandlerTable = pLoadCfg32->SEHandlerTable;
1626 pLoadCfg64->SecurityCookie = pLoadCfg32->SecurityCookie;
1627 pLoadCfg64->EditList = pLoadCfg32->EditList;
1628 pLoadCfg64->Reserved1 = pLoadCfg32->Reserved1;
1629 pLoadCfg64->CSDVersion = pLoadCfg32->CSDVersion;
1630 pLoadCfg64->ProcessHeapFlags = pLoadCfg32->ProcessHeapFlags; /* switched place with ProcessAffinityMask, but we're more than 16 byte off by now so it doesn't matter. */
1631 pLoadCfg64->ProcessAffinityMask = pLoadCfg32->ProcessAffinityMask;
1632 pLoadCfg64->VirtualMemoryThreshold = pLoadCfg32->VirtualMemoryThreshold;
1633 pLoadCfg64->MaximumAllocationSize = pLoadCfg32->MaximumAllocationSize;
1634 pLoadCfg64->LockPrefixTable = pLoadCfg32->LockPrefixTable;
1635 pLoadCfg64->DeCommitTotalFreeThreshold = pLoadCfg32->DeCommitTotalFreeThreshold;
1636 uint32_t u32DeCommitFreeBlockThreshold = pLoadCfg32->DeCommitFreeBlockThreshold;
1637 pLoadCfg64->DeCommitFreeBlockThreshold = u32DeCommitFreeBlockThreshold;
1638 /* the rest is equal. */
1639 Assert( RT_OFFSETOF(IMAGE_LOAD_CONFIG_DIRECTORY32, DeCommitFreeBlockThreshold)
1640 == RT_OFFSETOF(IMAGE_LOAD_CONFIG_DIRECTORY64, DeCommitFreeBlockThreshold));
1641}
1642
1643
1644/**
1645 * Validates the file header.
1646 *
1647 * @returns iprt status code.
1648 * @param pFileHdr Pointer to the file header that needs validating.
1649 * @param fFlags Valid RTLDR_O_XXX combination.
1650 * @param pszLogName The log name to prefix the errors with.
1651 * @param penmArch Where to store the CPU architecture.
1652 */
1653static int rtldrPEValidateFileHeader(PIMAGE_FILE_HEADER pFileHdr, uint32_t fFlags, const char *pszLogName, PRTLDRARCH penmArch)
1654{
1655 size_t cbOptionalHeader;
1656 switch (pFileHdr->Machine)
1657 {
1658 case IMAGE_FILE_MACHINE_I386:
1659 cbOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER32);
1660 *penmArch = RTLDRARCH_X86_32;
1661 break;
1662 case IMAGE_FILE_MACHINE_AMD64:
1663 cbOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER64);
1664 *penmArch = RTLDRARCH_AMD64;
1665 break;
1666
1667 default:
1668 Log(("rtldrPEOpen: %s: Unsupported Machine=%#x\n",
1669 pszLogName, pFileHdr->Machine));
1670 *penmArch = RTLDRARCH_INVALID;
1671 return VERR_BAD_EXE_FORMAT;
1672 }
1673 if (pFileHdr->SizeOfOptionalHeader != cbOptionalHeader)
1674 {
1675 Log(("rtldrPEOpen: %s: SizeOfOptionalHeader=%#x expected %#x\n",
1676 pszLogName, pFileHdr->SizeOfOptionalHeader, cbOptionalHeader));
1677 return VERR_BAD_EXE_FORMAT;
1678 }
1679 /* This restriction needs to be implemented elsewhere. */
1680 if ( (pFileHdr->Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
1681 && !(fFlags & RTLDR_O_FOR_DEBUG))
1682 {
1683 Log(("rtldrPEOpen: %s: IMAGE_FILE_RELOCS_STRIPPED\n", pszLogName));
1684 return VERR_BAD_EXE_FORMAT;
1685 }
1686 if (pFileHdr->NumberOfSections > 42)
1687 {
1688 Log(("rtldrPEOpen: %s: NumberOfSections=%d - our limit is 42, please raise it if the binary makes sense.(!!!)\n",
1689 pszLogName, pFileHdr->NumberOfSections));
1690 return VERR_BAD_EXE_FORMAT;
1691 }
1692 if (pFileHdr->NumberOfSections < 1)
1693 {
1694 Log(("rtldrPEOpen: %s: NumberOfSections=%d - we can't have an image without sections (!!!)\n",
1695 pszLogName, pFileHdr->NumberOfSections));
1696 return VERR_BAD_EXE_FORMAT;
1697 }
1698 return VINF_SUCCESS;
1699}
1700
1701
1702/**
1703 * Validates the optional header (64/32-bit)
1704 *
1705 * @returns iprt status code.
1706 * @param pOptHdr Pointer to the optional header which needs validation.
1707 * @param pszLogName The log name to prefix the errors with.
1708 * @param offNtHdrs The offset of the NT headers from the start of the file.
1709 * @param pFileHdr Pointer to the file header (valid).
1710 * @param cbRawImage The raw image size.
1711 * @param fFlags Loader flags, RTLDR_O_XXX.
1712 */
1713static int rtldrPEValidateOptionalHeader(const IMAGE_OPTIONAL_HEADER64 *pOptHdr, const char *pszLogName, RTFOFF offNtHdrs,
1714 const IMAGE_FILE_HEADER *pFileHdr, RTFOFF cbRawImage, uint32_t fFlags)
1715{
1716 const uint16_t CorrectMagic = pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
1717 ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC;
1718 if (pOptHdr->Magic != CorrectMagic)
1719 {
1720 Log(("rtldrPEOpen: %s: Magic=%#x - expected %#x!!!\n", pszLogName, pOptHdr->Magic, CorrectMagic));
1721 return VERR_BAD_EXE_FORMAT;
1722 }
1723 const uint32_t cbImage = pOptHdr->SizeOfImage;
1724 if (cbImage > _1G)
1725 {
1726 Log(("rtldrPEOpen: %s: SizeOfImage=%#x - Our limit is 1GB (%#x)!!!\n", pszLogName, cbImage, _1G));
1727 return VERR_BAD_EXE_FORMAT;
1728 }
1729 const uint32_t cbMinImageSize = pFileHdr->SizeOfOptionalHeader + sizeof(*pFileHdr) + 4 + (uint32_t)offNtHdrs;
1730 if (cbImage < cbMinImageSize)
1731 {
1732 Log(("rtldrPEOpen: %s: SizeOfImage=%#x to small, minimum %#x!!!\n", pszLogName, cbImage, cbMinImageSize));
1733 return VERR_BAD_EXE_FORMAT;
1734 }
1735 if (pOptHdr->AddressOfEntryPoint >= cbImage)
1736 {
1737 Log(("rtldrPEOpen: %s: AddressOfEntryPoint=%#x - beyond image size (%#x)!!!\n",
1738 pszLogName, pOptHdr->AddressOfEntryPoint, cbImage));
1739 return VERR_BAD_EXE_FORMAT;
1740 }
1741 if (pOptHdr->BaseOfCode >= cbImage)
1742 {
1743 Log(("rtldrPEOpen: %s: BaseOfCode=%#x - beyond image size (%#x)!!!\n",
1744 pszLogName, pOptHdr->BaseOfCode, cbImage));
1745 return VERR_BAD_EXE_FORMAT;
1746 }
1747#if 0/* only in 32-bit header */
1748 if (pOptHdr->BaseOfData >= cbImage)
1749 {
1750 Log(("rtldrPEOpen: %s: BaseOfData=%#x - beyond image size (%#x)!!!\n",
1751 pszLogName, pOptHdr->BaseOfData, cbImage));
1752 return VERR_BAD_EXE_FORMAT;
1753 }
1754#endif
1755 if (pOptHdr->SizeOfHeaders >= cbImage)
1756 {
1757 Log(("rtldrPEOpen: %s: SizeOfHeaders=%#x - beyond image size (%#x)!!!\n",
1758 pszLogName, pOptHdr->SizeOfHeaders, cbImage));
1759 return VERR_BAD_EXE_FORMAT;
1760 }
1761 /* don't know how to do the checksum, so ignore it. */
1762 if (pOptHdr->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN)
1763 {
1764 Log(("rtldrPEOpen: %s: Subsystem=%#x (unknown)!!!\n", pszLogName, pOptHdr->Subsystem));
1765 return VERR_BAD_EXE_FORMAT;
1766 }
1767 if (pOptHdr->SizeOfHeaders < cbMinImageSize + pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER))
1768 {
1769 Log(("rtldrPEOpen: %s: SizeOfHeaders=%#x - cbMinImageSize %#x + sections %#x = %#llx!!!\n",
1770 pszLogName, pOptHdr->SizeOfHeaders,
1771 cbImage, cbMinImageSize, pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER),
1772 cbMinImageSize + pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER)));
1773 return VERR_BAD_EXE_FORMAT;
1774 }
1775 if (pOptHdr->SizeOfStackReserve < pOptHdr->SizeOfStackCommit)
1776 {
1777 Log(("rtldrPEOpen: %s: SizeOfStackReserve %#x < SizeOfStackCommit %#x!!!\n",
1778 pszLogName, pOptHdr->SizeOfStackReserve, pOptHdr->SizeOfStackCommit));
1779 return VERR_BAD_EXE_FORMAT;
1780 }
1781 if (pOptHdr->SizeOfHeapReserve < pOptHdr->SizeOfHeapCommit)
1782 {
1783 Log(("rtldrPEOpen: %s: SizeOfStackReserve %#x < SizeOfStackCommit %#x!!!\n",
1784 pszLogName, pOptHdr->SizeOfStackReserve, pOptHdr->SizeOfStackCommit));
1785 return VERR_BAD_EXE_FORMAT;
1786 }
1787
1788 /* DataDirectory */
1789 if (pOptHdr->NumberOfRvaAndSizes != RT_ELEMENTS(pOptHdr->DataDirectory))
1790 {
1791 Log(("rtldrPEOpen: %s: NumberOfRvaAndSizes=%d!!!\n", pszLogName, pOptHdr->NumberOfRvaAndSizes));
1792 return VERR_BAD_EXE_FORMAT;
1793 }
1794 for (unsigned i = 0; i < RT_ELEMENTS(pOptHdr->DataDirectory); i++)
1795 {
1796 IMAGE_DATA_DIRECTORY const *pDir = &pOptHdr->DataDirectory[i];
1797 if (!pDir->Size)
1798 continue;
1799 size_t cb = cbImage;
1800 switch (i)
1801 {
1802 case IMAGE_DIRECTORY_ENTRY_EXPORT: // 0
1803 case IMAGE_DIRECTORY_ENTRY_IMPORT: // 1
1804 case IMAGE_DIRECTORY_ENTRY_RESOURCE: // 2
1805 case IMAGE_DIRECTORY_ENTRY_EXCEPTION: // 3
1806 case IMAGE_DIRECTORY_ENTRY_BASERELOC: // 5
1807 case IMAGE_DIRECTORY_ENTRY_DEBUG: // 6
1808 case IMAGE_DIRECTORY_ENTRY_COPYRIGHT: // 7
1809 case IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT: // 11
1810 case IMAGE_DIRECTORY_ENTRY_IAT: // 12 /* Import Address Table */
1811 break;
1812 case IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG: // 10 - need to check for lock prefixes.
1813 /* Delay inspection after section table is validated. */
1814 break;
1815
1816 case IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT: // 13
1817 Log(("rtldrPEOpen: %s: dir no. %d (DELAY_IMPORT) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1818 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1819 return VERR_LDRPE_DELAY_IMPORT;
1820
1821 case IMAGE_DIRECTORY_ENTRY_SECURITY: // 4
1822 /* The VirtualAddress is a PointerToRawData. */
1823 cb = (size_t)cbRawImage; Assert((RTFOFF)cb == cbRawImage);
1824 Log(("rtldrPEOpen: %s: dir no. %d (SECURITY) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1825 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1826 if (pDir->Size < sizeof(WIN_CERTIFICATE))
1827 {
1828 Log(("rtldrPEOpen: %s: Security directory is too small: %#x bytes\n", pszLogName, i, pDir->Size));
1829 return VERR_LDRPE_CERT_MALFORMED;
1830 }
1831 if (pDir->Size >= _1M)
1832 {
1833 Log(("rtldrPEOpen: %s: Security directory is too large: %#x bytes\n", pszLogName, i, pDir->Size));
1834 return VERR_LDRPE_CERT_MALFORMED;
1835 }
1836 if (pDir->VirtualAddress & 7)
1837 {
1838 Log(("rtldrPEOpen: %s: Security directory is misaligned: %#x\n", pszLogName, i, pDir->VirtualAddress));
1839 return VERR_LDRPE_CERT_MALFORMED;
1840 }
1841 /* When using the in-memory reader with a debugger, we may get
1842 into trouble here since we might not have access to the whole
1843 physical file. So skip the tests below. Makes VBoxGuest.sys
1844 load and check out just fine, for instance. */
1845 if (fFlags & RTLDR_O_FOR_DEBUG)
1846 continue;
1847 break;
1848
1849 case IMAGE_DIRECTORY_ENTRY_GLOBALPTR: // 8 /* (MIPS GP) */
1850 Log(("rtldrPEOpen: %s: dir no. %d (GLOBALPTR) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1851 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1852 return VERR_LDRPE_GLOBALPTR;
1853
1854 case IMAGE_DIRECTORY_ENTRY_TLS: // 9
1855 Log(("rtldrPEOpen: %s: dir no. %d (TLS) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1856 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1857 return VERR_LDRPE_TLS;
1858
1859 case IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR:// 14
1860 Log(("rtldrPEOpen: %s: dir no. %d (COM_DESCRIPTOR) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1861 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1862 return VERR_LDRPE_COM_DESCRIPTOR;
1863
1864 default:
1865 Log(("rtldrPEOpen: %s: dir no. %d VirtualAddress=%#x Size=%#x is not supported!!!\n",
1866 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1867 return VERR_BAD_EXE_FORMAT;
1868 }
1869 if (pDir->VirtualAddress >= cb)
1870 {
1871 Log(("rtldrPEOpen: %s: dir no. %d VirtualAddress=%#x is invalid (limit %#x)!!!\n",
1872 pszLogName, i, pDir->VirtualAddress, cb));
1873 return VERR_BAD_EXE_FORMAT;
1874 }
1875 if (pDir->Size > cb - pDir->VirtualAddress)
1876 {
1877 Log(("rtldrPEOpen: %s: dir no. %d Size=%#x is invalid (rva=%#x, limit=%#x)!!!\n",
1878 pszLogName, i, pDir->Size, pDir->VirtualAddress, cb));
1879 return VERR_BAD_EXE_FORMAT;
1880 }
1881 }
1882 return VINF_SUCCESS;
1883}
1884
1885
1886/**
1887 * Validates the section headers.
1888 *
1889 * @returns iprt status code.
1890 * @param paSections Pointer to the array of sections that is to be validated.
1891 * @param cSections Number of sections in that array.
1892 * @param pszLogName The log name to prefix the errors with.
1893 * @param pOptHdr Pointer to the optional header (valid).
1894 * @param cbRawImage The raw image size.
1895 * @param fFlags Loader flags, RTLDR_O_XXX.
1896 */
1897static int rtldrPEValidateSectionHeaders(const IMAGE_SECTION_HEADER *paSections, unsigned cSections, const char *pszLogName,
1898 const IMAGE_OPTIONAL_HEADER64 *pOptHdr, RTFOFF cbRawImage, uint32_t fFlags)
1899{
1900 const uint32_t cbImage = pOptHdr->SizeOfImage;
1901 const IMAGE_SECTION_HEADER *pSH = &paSections[0];
1902 uint32_t uRvaPrev = pOptHdr->SizeOfHeaders;
1903 Log3(("RTLdrPE: Section Headers:\n"));
1904 for (unsigned cSHdrsLeft = cSections; cSHdrsLeft > 0; cSHdrsLeft--, pSH++)
1905 {
1906 const unsigned iSH = pSH - &paSections[0]; NOREF(iSH);
1907 Log3(("RTLdrPE: #%d '%-8.8s' Characteristics: %08RX32\n"
1908 "RTLdrPE: VirtAddr: %08RX32 VirtSize: %08RX32\n"
1909 "RTLdrPE: FileOff: %08RX32 FileSize: %08RX32\n"
1910 "RTLdrPE: RelocOff: %08RX32 #Relocs: %08RX32\n"
1911 "RTLdrPE: LineOff: %08RX32 #Lines: %08RX32\n",
1912 iSH, pSH->Name, pSH->Characteristics,
1913 pSH->VirtualAddress, pSH->Misc.VirtualSize,
1914 pSH->PointerToRawData, pSH->SizeOfRawData,
1915 pSH->PointerToRelocations, pSH->NumberOfRelocations,
1916 pSH->PointerToLinenumbers, pSH->NumberOfLinenumbers));
1917
1918 AssertCompile(IMAGE_SCN_MEM_16BIT == IMAGE_SCN_MEM_PURGEABLE);
1919 if ( ( pSH->Characteristics & (IMAGE_SCN_MEM_PURGEABLE | IMAGE_SCN_MEM_PRELOAD | IMAGE_SCN_MEM_FARDATA) )
1920 && !(fFlags & RTLDR_O_FOR_DEBUG)) /* purgable/16-bit seen on w2ksp0 hal.dll, ignore the bunch. */
1921 {
1922 Log(("rtldrPEOpen: %s: Unsupported section flag(s) %#x section #%d '%.*s'!!!\n",
1923 pszLogName, pSH->Characteristics, iSH, sizeof(pSH->Name), pSH->Name));
1924 return VERR_BAD_EXE_FORMAT;
1925 }
1926
1927 if ( pSH->Misc.VirtualSize
1928 && !(pSH->Characteristics & IMAGE_SCN_TYPE_NOLOAD)) /* binutils uses this for '.stab' even if it's reserved/obsoleted by MS. */
1929 {
1930 if (pSH->VirtualAddress < uRvaPrev)
1931 {
1932 Log(("rtldrPEOpen: %s: Overlaps previous section or sections aren't in ascending order, VirtualAddress=%#x uRvaPrev=%#x - section #%d '%.*s'!!!\n",
1933 pszLogName, pSH->VirtualAddress, uRvaPrev, iSH, sizeof(pSH->Name), pSH->Name));
1934 return VERR_BAD_EXE_FORMAT;
1935 }
1936 if (pSH->VirtualAddress > cbImage)
1937 {
1938 Log(("rtldrPEOpen: %s: VirtualAddress=%#x - beyond image size (%#x) - section #%d '%.*s'!!!\n",
1939 pszLogName, pSH->VirtualAddress, cbImage, iSH, sizeof(pSH->Name), pSH->Name));
1940 return VERR_BAD_EXE_FORMAT;
1941 }
1942
1943 if (pSH->VirtualAddress & (pOptHdr->SectionAlignment - 1)) //ASSUMES power of 2 alignment.
1944 {
1945 Log(("rtldrPEOpen: %s: VirtualAddress=%#x misaligned (%#x) - section #%d '%.*s'!!!\n",
1946 pszLogName, pSH->VirtualAddress, pOptHdr->SectionAlignment, iSH, sizeof(pSH->Name), pSH->Name));
1947 return VERR_BAD_EXE_FORMAT;
1948 }
1949
1950#ifdef PE_FILE_OFFSET_EQUALS_RVA
1951 /* Our loader code assume rva matches the file offset. */
1952 if ( pSH->SizeOfRawData
1953 && pSH->PointerToRawData != pSH->VirtualAddress)
1954 {
1955 Log(("rtldrPEOpen: %s: ASSUMPTION FAILED: file offset %#x != RVA %#x - section #%d '%.*s'!!!\n",
1956 pszLogName, pSH->PointerToRawData, pSH->VirtualAddress, iSH, sizeof(pSH->Name), pSH->Name));
1957 return VERR_BAD_EXE_FORMAT;
1958 }
1959#endif
1960 }
1961
1962 ///@todo only if SizeOfRawData > 0 ?
1963 if ( pSH->PointerToRawData > cbRawImage /// @todo pSH->PointerToRawData >= cbRawImage ?
1964 || pSH->SizeOfRawData > cbRawImage
1965 || pSH->PointerToRawData + pSH->SizeOfRawData > cbRawImage)
1966 {
1967 Log(("rtldrPEOpen: %s: PointerToRawData=%#x SizeOfRawData=%#x - beyond end of file (%#x) - section #%d '%.*s'!!!\n",
1968 pszLogName, pSH->PointerToRawData, pSH->SizeOfRawData, cbRawImage,
1969 iSH, sizeof(pSH->Name), pSH->Name));
1970 return VERR_BAD_EXE_FORMAT;
1971 }
1972
1973 if (pSH->PointerToRawData & (pOptHdr->FileAlignment - 1)) //ASSUMES power of 2 alignment.
1974 {
1975 Log(("rtldrPEOpen: %s: PointerToRawData=%#x misaligned (%#x) - section #%d '%.*s'!!!\n",
1976 pszLogName, pSH->PointerToRawData, pOptHdr->FileAlignment, iSH, sizeof(pSH->Name), pSH->Name));
1977 return VERR_BAD_EXE_FORMAT;
1978 }
1979
1980 /* ignore the relocations and linenumbers. */
1981
1982 uRvaPrev = pSH->VirtualAddress + pSH->Misc.VirtualSize;
1983 }
1984
1985 /** @todo r=bird: more sanity checks! */
1986 return VINF_SUCCESS;
1987}
1988
1989
1990/**
1991 * Reads image data by RVA using the section headers.
1992 *
1993 * @returns iprt status code.
1994 * @param pModPe The PE module instance.
1995 * @param pvBuf Where to store the bits.
1996 * @param cb Number of bytes to tread.
1997 * @param RVA Where to read from.
1998 */
1999static int rtldrPEReadRVA(PRTLDRMODPE pModPe, void *pvBuf, uint32_t cb, uint32_t RVA)
2000{
2001 const IMAGE_SECTION_HEADER *pSH = pModPe->paSections;
2002 PRTLDRREADER pReader = pModPe->Core.pReader;
2003 uint32_t cbRead;
2004 int rc;
2005
2006 /*
2007 * Is it the headers, i.e. prior to the first section.
2008 */
2009 if (RVA < pModPe->cbHeaders)
2010 {
2011 cbRead = RT_MIN(pModPe->cbHeaders - RVA, cb);
2012 rc = pReader->pfnRead(pReader, pvBuf, cbRead, RVA);
2013 if ( cbRead == cb
2014 || RT_FAILURE(rc))
2015 return rc;
2016 cb -= cbRead;
2017 RVA += cbRead;
2018 pvBuf = (uint8_t *)pvBuf + cbRead;
2019 }
2020
2021 /* In the zero space between headers and the first section? */
2022 if (RVA < pSH->VirtualAddress)
2023 {
2024 cbRead = RT_MIN(pSH->VirtualAddress - RVA, cb);
2025 memset(pvBuf, 0, cbRead);
2026 if (cbRead == cb)
2027 return VINF_SUCCESS;
2028 cb -= cbRead;
2029 RVA += cbRead;
2030 pvBuf = (uint8_t *)pvBuf + cbRead;
2031 }
2032
2033 /*
2034 * Iterate the sections.
2035 */
2036 for (unsigned cLeft = pModPe->cSections;
2037 cLeft > 0;
2038 cLeft--, pSH++)
2039 {
2040 uint32_t off = RVA - pSH->VirtualAddress;
2041 if (off < pSH->Misc.VirtualSize)
2042 {
2043 cbRead = RT_MIN(pSH->Misc.VirtualSize - off, cb);
2044 rc = pReader->pfnRead(pReader, pvBuf, cbRead, pSH->PointerToRawData + off);
2045 if ( cbRead == cb
2046 || RT_FAILURE(rc))
2047 return rc;
2048 cb -= cbRead;
2049 RVA += cbRead;
2050 pvBuf = (uint8_t *)pvBuf + cbRead;
2051 }
2052 uint32_t RVANext = cLeft ? pSH[1].VirtualAddress : pModPe->cbImage;
2053 if (RVA < RVANext)
2054 {
2055 cbRead = RT_MIN(RVANext - RVA, cb);
2056 memset(pvBuf, 0, cbRead);
2057 if (cbRead == cb)
2058 return VINF_SUCCESS;
2059 cb -= cbRead;
2060 RVA += cbRead;
2061 pvBuf = (uint8_t *)pvBuf + cbRead;
2062 }
2063 }
2064
2065 AssertFailed();
2066 return VERR_INTERNAL_ERROR;
2067}
2068
2069
2070/**
2071 * Validates the data of some selected data directories entries.
2072 *
2073 * This requires a valid section table and thus has to wait
2074 * till after we've read and validated it.
2075 *
2076 * @returns iprt status code.
2077 * @param pModPe The PE module instance.
2078 * @param pOptHdr Pointer to the optional header (valid).
2079 * @param fFlags Loader flags, RTLDR_O_XXX.
2080 */
2081static int rtldrPEValidateDirectories(PRTLDRMODPE pModPe, const IMAGE_OPTIONAL_HEADER64 *pOptHdr, uint32_t fFlags)
2082{
2083 const char *pszLogName = pModPe->Core.pReader->pfnLogName(pModPe->Core.pReader); NOREF(pszLogName);
2084 union /* combine stuff we're reading to help reduce stack usage. */
2085 {
2086 IMAGE_LOAD_CONFIG_DIRECTORY64 Cfg64;
2087 } u;
2088
2089 /*
2090 * The load config entry may include lock prefix tables and whatnot which we don't implement.
2091 * It does also include a lot of stuff which we can ignore, so we'll have to inspect the
2092 * actual data before we can make up our mind about it all.
2093 */
2094 IMAGE_DATA_DIRECTORY Dir = pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG];
2095 if (Dir.Size)
2096 {
2097 const size_t cbExpect = pOptHdr->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC
2098 ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32)
2099 : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64);
2100 if ( Dir.Size != cbExpect
2101 && ( cbExpect == sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32)
2102 && Dir.Size != (uint32_t)RT_OFFSETOF(IMAGE_LOAD_CONFIG_DIRECTORY32, SEHandlerTable))
2103 )
2104 {
2105 Log(("rtldrPEOpen: %s: load cfg dir: unexpected dir size of %d bytes, expected %d.\n",
2106 pszLogName, Dir.Size, cbExpect));
2107 return VERR_LDRPE_LOAD_CONFIG_SIZE;
2108 }
2109
2110 /*
2111 * Read and convert to 64-bit.
2112 */
2113 memset(&u.Cfg64, 0, sizeof(u.Cfg64));
2114 int rc = rtldrPEReadRVA(pModPe, &u.Cfg64, Dir.Size, Dir.VirtualAddress);
2115 if (RT_FAILURE(rc))
2116 return rc;
2117 rtldrPEConvert32BitLoadConfigTo64Bit(&u.Cfg64);
2118
2119 if (u.Cfg64.Size != cbExpect)
2120 {
2121 Log(("rtldrPEOpen: %s: load cfg dir: unexpected header size of %d bytes, expected %d.\n",
2122 pszLogName, u.Cfg64.Size, cbExpect));
2123 return VERR_LDRPE_LOAD_CONFIG_SIZE;
2124 }
2125 if (u.Cfg64.LockPrefixTable)
2126 {
2127 Log(("rtldrPEOpen: %s: load cfg dir: lock prefix table at %RX64. We don't support lock prefix tables!\n",
2128 pszLogName, u.Cfg64.LockPrefixTable));
2129 return VERR_LDRPE_LOCK_PREFIX_TABLE;
2130 }
2131#if 0/* this seems to be safe to ignore. */
2132 if ( u.Cfg64.SEHandlerTable
2133 || u.Cfg64.SEHandlerCount)
2134 {
2135 Log(("rtldrPEOpen: %s: load cfg dir: SEHandlerTable=%RX64 and SEHandlerCount=%RX64 are unsupported!\n",
2136 pszLogName, u.Cfg64.SEHandlerTable, u.Cfg64.SEHandlerCount));
2137 return VERR_BAD_EXE_FORMAT;
2138 }
2139#endif
2140 if (u.Cfg64.EditList)
2141 {
2142 Log(("rtldrPEOpen: %s: load cfg dir: EditList=%RX64 is unsupported!\n",
2143 pszLogName, u.Cfg64.EditList));
2144 return VERR_BAD_EXE_FORMAT;
2145 }
2146 }
2147
2148 /*
2149 * If the image is signed and we're not doing this for debug purposes,
2150 * take a look at the signature.
2151 */
2152 Dir = pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
2153 if (Dir.Size && !(fFlags & RTLDR_O_FOR_DEBUG))
2154 {
2155 PWIN_CERTIFICATE pFirst = (PWIN_CERTIFICATE)RTMemTmpAlloc(Dir.Size);
2156 if (!pFirst)
2157 return VERR_NO_TMP_MEMORY;
2158 int rc = pModPe->Core.pReader->pfnRead(pModPe->Core.pReader, pFirst, Dir.Size, Dir.VirtualAddress);
2159 if (RT_SUCCESS(rc))
2160 {
2161 uint32_t off = 0;
2162 PWIN_CERTIFICATE pCur = pFirst;
2163 do
2164 {
2165 /* validate the members. */
2166 uint32_t const cbCur = RT_ALIGN_32(pCur->dwLength, 8);
2167 if ( cbCur < sizeof(WIN_CERTIFICATE)
2168 || cbCur + off > RT_ALIGN_32(Dir.Size, 8))
2169 {
2170 Log(("rtldrPEOpen: %s: cert at %#x/%#x: dwLength=%#x\n", pszLogName, off, Dir.Size, pCur->dwLength));
2171 rc = VERR_LDRPE_CERT_MALFORMED;
2172 break;
2173 }
2174 if ( pCur->wRevision != WIN_CERT_REVISION_2_0
2175 && pCur->wRevision != WIN_CERT_REVISION_1_0)
2176 {
2177 Log(("rtldrPEOpen: %s: cert at %#x/%#x: wRevision=%#x\n", pszLogName, off, Dir.Size, pCur->wRevision));
2178 rc = pCur->wRevision >= WIN_CERT_REVISION_1_0 ? VERR_LDRPE_CERT_UNSUPPORTED : VERR_LDRPE_CERT_MALFORMED;
2179 break;
2180 }
2181 if ( pCur->wCertificateType != WIN_CERT_TYPE_PKCS_SIGNED_DATA
2182 && pCur->wCertificateType != WIN_CERT_TYPE_X509
2183 /*&& pCur->wCertificateType != WIN_CERT_TYPE_RESERVED_1*/
2184 /*&& pCur->wCertificateType != WIN_CERT_TYPE_TS_STACK_SIGNED*/
2185 && pCur->wCertificateType != WIN_CERT_TYPE_EFI_PKCS115
2186 && pCur->wCertificateType != WIN_CERT_TYPE_EFI_GUID
2187 )
2188 {
2189 Log(("rtldrPEOpen: %s: cert at %#x/%#x: wRevision=%#x\n", pszLogName, off, Dir.Size, pCur->wRevision));
2190 rc = pCur->wCertificateType ? VERR_LDRPE_CERT_UNSUPPORTED : VERR_LDRPE_CERT_MALFORMED;
2191 break;
2192 }
2193
2194 /** @todo Rainy Day: Implement further verification using openssl. */
2195
2196 /* next */
2197 off += cbCur;
2198 pCur = (PWIN_CERTIFICATE)((uint8_t *)pCur + cbCur);
2199 } while (off < Dir.Size);
2200 }
2201 RTMemTmpFree(pFirst);
2202 if (RT_FAILURE(rc))
2203 return rc;
2204 }
2205
2206
2207 return VINF_SUCCESS;
2208}
2209
2210
2211/**
2212 * Open a PE image.
2213 *
2214 * @returns iprt status code.
2215 * @param pReader The loader reader instance which will provide the raw image bits.
2216 * @param fFlags Loader flags, RTLDR_O_XXX.
2217 * @param enmArch Architecture specifier.
2218 * @param offNtHdrs The offset of the NT headers (where you find "PE\0\0").
2219 * @param phLdrMod Where to store the handle.
2220 */
2221int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF offNtHdrs, PRTLDRMOD phLdrMod)
2222{
2223 /*
2224 * Read and validate the file header.
2225 */
2226 IMAGE_FILE_HEADER FileHdr;
2227 int rc = pReader->pfnRead(pReader, &FileHdr, sizeof(FileHdr), offNtHdrs + 4);
2228 if (RT_FAILURE(rc))
2229 return rc;
2230 RTLDRARCH enmArchImage;
2231 const char *pszLogName = pReader->pfnLogName(pReader);
2232 rc = rtldrPEValidateFileHeader(&FileHdr, fFlags, pszLogName, &enmArchImage);
2233 if (RT_FAILURE(rc))
2234 return rc;
2235
2236 /*
2237 * Match the CPU architecture.
2238 */
2239 if ( enmArch != RTLDRARCH_WHATEVER
2240 && enmArch != enmArchImage)
2241 return VERR_LDR_ARCH_MISMATCH;
2242
2243 /*
2244 * Read and validate the "optional" header. Convert 32->64 if necessary.
2245 */
2246 IMAGE_OPTIONAL_HEADER64 OptHdr;
2247 rc = pReader->pfnRead(pReader, &OptHdr, FileHdr.SizeOfOptionalHeader, offNtHdrs + 4 + sizeof(IMAGE_FILE_HEADER));
2248 if (RT_FAILURE(rc))
2249 return rc;
2250 if (FileHdr.SizeOfOptionalHeader != sizeof(OptHdr))
2251 rtldrPEConvert32BitOptionalHeaderTo64Bit(&OptHdr);
2252 rc = rtldrPEValidateOptionalHeader(&OptHdr, pszLogName, offNtHdrs, &FileHdr, pReader->pfnSize(pReader), fFlags);
2253 if (RT_FAILURE(rc))
2254 return rc;
2255
2256 /*
2257 * Read and validate section headers.
2258 */
2259 const size_t cbSections = sizeof(IMAGE_SECTION_HEADER) * FileHdr.NumberOfSections;
2260 PIMAGE_SECTION_HEADER paSections = (PIMAGE_SECTION_HEADER)RTMemAlloc(cbSections);
2261 if (!paSections)
2262 return VERR_NO_MEMORY;
2263 rc = pReader->pfnRead(pReader, paSections, cbSections,
2264 offNtHdrs + 4 + sizeof(IMAGE_FILE_HEADER) + FileHdr.SizeOfOptionalHeader);
2265 if (RT_SUCCESS(rc))
2266 {
2267 rc = rtldrPEValidateSectionHeaders(paSections, FileHdr.NumberOfSections, pszLogName,
2268 &OptHdr, pReader->pfnSize(pReader), fFlags);
2269 if (RT_SUCCESS(rc))
2270 {
2271 /*
2272 * Allocate and initialize the PE module structure.
2273 */
2274 PRTLDRMODPE pModPe = (PRTLDRMODPE)RTMemAllocZ(sizeof(*pModPe));
2275 if (pModPe)
2276 {
2277 pModPe->Core.u32Magic = RTLDRMOD_MAGIC;
2278 pModPe->Core.eState = LDR_STATE_OPENED;
2279 if (FileHdr.SizeOfOptionalHeader == sizeof(OptHdr))
2280 pModPe->Core.pOps = &s_rtldrPE64Ops.Core;
2281 else
2282 pModPe->Core.pOps = &s_rtldrPE32Ops.Core;
2283 pModPe->Core.pReader = pReader;
2284 pModPe->pvBits = NULL;
2285 pModPe->offNtHdrs = offNtHdrs;
2286 pModPe->offEndOfHdrs = offNtHdrs + 4 + sizeof(IMAGE_FILE_HEADER) + FileHdr.SizeOfOptionalHeader + cbSections;
2287 pModPe->u16Machine = FileHdr.Machine;
2288 pModPe->fFile = FileHdr.Characteristics;
2289 pModPe->cSections = FileHdr.NumberOfSections;
2290 pModPe->paSections = paSections;
2291 pModPe->uEntryPointRVA= OptHdr.AddressOfEntryPoint;
2292 pModPe->uImageBase = (RTUINTPTR)OptHdr.ImageBase;
2293 pModPe->cbImage = OptHdr.SizeOfImage;
2294 pModPe->cbHeaders = OptHdr.SizeOfHeaders;
2295 pModPe->uTimestamp = FileHdr.TimeDateStamp;
2296 pModPe->ImportDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
2297 pModPe->RelocDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
2298 pModPe->ExportDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
2299 pModPe->DebugDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
2300
2301 /*
2302 * Perform validation of some selected data directories which requires
2303 * inspection of the actual data.
2304 */
2305 rc = rtldrPEValidateDirectories(pModPe, &OptHdr, fFlags);
2306 if (RT_SUCCESS(rc))
2307 {
2308 *phLdrMod = &pModPe->Core;
2309 return VINF_SUCCESS;
2310 }
2311 RTMemFree(pModPe);
2312 }
2313 else
2314 rc = VERR_NO_MEMORY;
2315 }
2316 }
2317 RTMemFree(paSections);
2318 return rc;
2319}
2320
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