VirtualBox

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

Last change on this file since 50518 was 49044, checked in by vboxsync, 11 years ago

Darwin guest OS digger hacking in progress. Adding symbol cache util to iprt and started on the Mach-O code that'll make use of it (RTDbgModCreateFromMachOImage++). Updates kStuff from 53 to 55 for UUID query and 64-bit kext loading.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 91.8 KB
Line 
1/* $Id: ldrPE.cpp 49044 2013-10-11 01:06:28Z 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 = UINT32_MAX;
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.cbImage = pModPe->cbImage;
1189 DbgInfo.u.Cv.uMajorVer = paDbgDir[i].MajorVersion;
1190 DbgInfo.u.Cv.uMinorVer = paDbgDir[i].MinorVersion;
1191 DbgInfo.u.Cv.uTimestamp = paDbgDir[i].TimeDateStamp;
1192 if ( paDbgDir[i].SizeOfData < sizeof(szPath)
1193 && paDbgDir[i].SizeOfData > 16
1194 && ( DbgInfo.LinkAddress != NIL_RTLDRADDR
1195 || DbgInfo.offFile > 0)
1196 )
1197 {
1198 rc = rtldrPEReadPart(pModPe, pvBits, DbgInfo.offFile, DbgInfo.LinkAddress, paDbgDir[i].SizeOfData, &pvPart);
1199 if (RT_SUCCESS(rc))
1200 {
1201 PCCVPDB20INFO pCv20 = (PCCVPDB20INFO)pvPart;
1202 if ( pCv20->u32Magic == CVPDB20INFO_MAGIC
1203 && pCv20->offDbgInfo == 0
1204 && paDbgDir[i].SizeOfData > RT_UOFFSETOF(CVPDB20INFO, szPdbFilename) )
1205 {
1206 DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW_PDB20;
1207 DbgInfo.u.Pdb20.cbImage = pModPe->cbImage;
1208 DbgInfo.u.Pdb20.uTimestamp = pCv20->uTimestamp;
1209 DbgInfo.u.Pdb20.uAge = pCv20->uAge;
1210 DbgInfo.pszExtFile = (const char *)&pCv20->szPdbFilename[0];
1211 }
1212 else if ( pCv20->u32Magic == CVPDB70INFO_MAGIC
1213 && paDbgDir[i].SizeOfData > RT_UOFFSETOF(CVPDB70INFO, szPdbFilename) )
1214 {
1215 PCCVPDB70INFO pCv70 = (PCCVPDB70INFO)pCv20;
1216 DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW_PDB70;
1217 DbgInfo.u.Pdb70.cbImage = pModPe->cbImage;
1218 DbgInfo.u.Pdb70.Uuid = pCv70->PdbUuid;
1219 DbgInfo.u.Pdb70.uAge = pCv70->uAge;
1220 DbgInfo.pszExtFile = (const char *)&pCv70->szPdbFilename[0];
1221 }
1222 }
1223 else
1224 rcRet = rc;
1225 }
1226 break;
1227
1228 case IMAGE_DEBUG_TYPE_MISC:
1229 DbgInfo.enmType = RTLDRDBGINFOTYPE_UNKNOWN;
1230 if ( paDbgDir[i].SizeOfData < sizeof(szPath)
1231 && paDbgDir[i].SizeOfData > RT_UOFFSETOF(IMAGE_DEBUG_MISC, Data))
1232 {
1233 DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW_DBG;
1234 DbgInfo.u.Dbg.cbImage = pModPe->cbImage;
1235 if (DbgInfo.LinkAddress != NIL_RTLDRADDR)
1236 DbgInfo.u.Dbg.uTimestamp = paDbgDir[i].TimeDateStamp;
1237 else
1238 DbgInfo.u.Dbg.uTimestamp = pModPe->uTimestamp; /* NT4 SP1 ntfs.sys hack. Generic? */
1239
1240 rc = rtldrPEReadPart(pModPe, pvBits, DbgInfo.offFile, DbgInfo.LinkAddress, paDbgDir[i].SizeOfData, &pvPart);
1241 if (RT_SUCCESS(rc))
1242 {
1243 PCIMAGE_DEBUG_MISC pMisc = (PCIMAGE_DEBUG_MISC)pvPart;
1244 if ( pMisc->DataType == IMAGE_DEBUG_MISC_EXENAME
1245 && pMisc->Length == paDbgDir[i].SizeOfData)
1246 {
1247 if (!pMisc->Unicode)
1248 DbgInfo.pszExtFile = (const char *)&pMisc->Data[0];
1249 else
1250 {
1251 char *pszPath = szPath;
1252 rc = RTUtf16ToUtf8Ex((PCRTUTF16)&pMisc->Data[0],
1253 (pMisc->Length - RT_OFFSETOF(IMAGE_DEBUG_MISC, Data)) / sizeof(RTUTF16),
1254 &pszPath, sizeof(szPath), NULL);
1255 if (RT_SUCCESS(rc))
1256 DbgInfo.pszExtFile = szPath;
1257 else
1258 rcRet = rc; /* continue without a filename. */
1259 }
1260 }
1261 }
1262 else
1263 rcRet = rc; /* continue without a filename. */
1264 }
1265 break;
1266
1267 case IMAGE_DEBUG_TYPE_COFF:
1268 DbgInfo.enmType = RTLDRDBGINFOTYPE_COFF;
1269 DbgInfo.u.Coff.cbImage = pModPe->cbImage;
1270 DbgInfo.u.Coff.uMajorVer = paDbgDir[i].MajorVersion;
1271 DbgInfo.u.Coff.uMinorVer = paDbgDir[i].MinorVersion;
1272 DbgInfo.u.Coff.uTimestamp = paDbgDir[i].TimeDateStamp;
1273 break;
1274
1275 default:
1276 DbgInfo.enmType = RTLDRDBGINFOTYPE_UNKNOWN;
1277 break;
1278 }
1279
1280 /* Fix (hack) the file name encoding. We don't have Windows-1252 handy,
1281 so we'll be using Latin-1 as a reasonable approximation.
1282 (I don't think we know exactly which encoding this is anyway, as
1283 it's probably the current ANSI/Windows code page for the process
1284 generating the image anyways.) */
1285 if (DbgInfo.pszExtFile && DbgInfo.pszExtFile != szPath)
1286 {
1287 char *pszPath = szPath;
1288 rc = RTLatin1ToUtf8Ex(DbgInfo.pszExtFile,
1289 paDbgDir[i].SizeOfData - ((uintptr_t)DbgInfo.pszExtFile - (uintptr_t)pvBits),
1290 &pszPath, sizeof(szPath), NULL);
1291 if (RT_FAILURE(rc))
1292 {
1293 rcRet = rc;
1294 DbgInfo.pszExtFile = NULL;
1295 }
1296 }
1297 if (DbgInfo.pszExtFile)
1298 RTPathChangeToUnixSlashes(szPath, true /*fForce*/);
1299
1300 rc = pfnCallback(pMod, &DbgInfo, pvUser);
1301 rtldrPEFreePart(pModPe, pvBits, pvPart);
1302 if (rc != VINF_SUCCESS)
1303 {
1304 rcRet = rc;
1305 break;
1306 }
1307 }
1308
1309 rtldrPEFreePart(pModPe, pvBits, paDbgDir);
1310 return rcRet;
1311}
1312
1313
1314/** @copydoc RTLDROPS::pfnEnumSegments. */
1315static DECLCALLBACK(int) rtldrPE_EnumSegments(PRTLDRMODINTERNAL pMod, PFNRTLDRENUMSEGS pfnCallback, void *pvUser)
1316{
1317 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1318 RTLDRSEG SegInfo;
1319
1320 /*
1321 * The first section is a fake one covering the headers.
1322 */
1323 SegInfo.pszName = "NtHdrs";
1324 SegInfo.cchName = 6;
1325 SegInfo.SelFlat = 0;
1326 SegInfo.Sel16bit = 0;
1327 SegInfo.fFlags = 0;
1328 SegInfo.fProt = RTMEM_PROT_READ;
1329 SegInfo.Alignment = 1;
1330 SegInfo.LinkAddress = pModPe->uImageBase;
1331 SegInfo.RVA = 0;
1332 SegInfo.offFile = 0;
1333 SegInfo.cb = pModPe->cbHeaders;
1334 SegInfo.cbFile = pModPe->cbHeaders;
1335 SegInfo.cbMapped = pModPe->cbHeaders;
1336 if ((pModPe->paSections[0].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
1337 SegInfo.cbMapped = pModPe->paSections[0].VirtualAddress;
1338 int rc = pfnCallback(pMod, &SegInfo, pvUser);
1339
1340 /*
1341 * Then all the normal sections.
1342 */
1343 PCIMAGE_SECTION_HEADER pSh = pModPe->paSections;
1344 for (uint32_t i = 0; i < pModPe->cSections && rc == VINF_SUCCESS; i++, pSh++)
1345 {
1346 char szName[32];
1347 SegInfo.pszName = (const char *)&pSh->Name[0];
1348 SegInfo.cchName = (uint32_t)RTStrNLen(SegInfo.pszName, sizeof(pSh->Name));
1349 if (SegInfo.cchName >= sizeof(pSh->Name))
1350 {
1351 memcpy(szName, &pSh->Name[0], sizeof(pSh->Name));
1352 szName[sizeof(sizeof(pSh->Name))] = '\0';
1353 SegInfo.pszName = szName;
1354 }
1355 else if (SegInfo.cchName == 0)
1356 {
1357 SegInfo.pszName = szName;
1358 SegInfo.cchName = (uint32_t)RTStrPrintf(szName, sizeof(szName), "UnamedSect%02u", i);
1359 }
1360 SegInfo.SelFlat = 0;
1361 SegInfo.Sel16bit = 0;
1362 SegInfo.fFlags = 0;
1363 SegInfo.fProt = RTMEM_PROT_NONE;
1364 if (pSh->Characteristics & IMAGE_SCN_MEM_READ)
1365 SegInfo.fProt |= RTMEM_PROT_READ;
1366 if (pSh->Characteristics & IMAGE_SCN_MEM_WRITE)
1367 SegInfo.fProt |= RTMEM_PROT_WRITE;
1368 if (pSh->Characteristics & IMAGE_SCN_MEM_EXECUTE)
1369 SegInfo.fProt |= RTMEM_PROT_EXEC;
1370 SegInfo.Alignment = (pSh->Characteristics & IMAGE_SCN_ALIGN_MASK) >> IMAGE_SCN_ALIGN_SHIFT;
1371 if (SegInfo.Alignment > 0)
1372 SegInfo.Alignment = RT_BIT_64(SegInfo.Alignment - 1);
1373 if (pSh->Characteristics & IMAGE_SCN_TYPE_NOLOAD)
1374 {
1375 SegInfo.LinkAddress = NIL_RTLDRADDR;
1376 SegInfo.RVA = NIL_RTLDRADDR;
1377 SegInfo.cbMapped = pSh->Misc.VirtualSize;
1378 }
1379 else
1380 {
1381 SegInfo.LinkAddress = pSh->VirtualAddress + pModPe->uImageBase ;
1382 SegInfo.RVA = pSh->VirtualAddress;
1383 SegInfo.cbMapped = RT_ALIGN(SegInfo.cb, SegInfo.Alignment);
1384 if (i + 1 < pModPe->cSections && !(pSh[1].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
1385 SegInfo.cbMapped = pSh[1].VirtualAddress - pSh->VirtualAddress;
1386 }
1387 SegInfo.cb = pSh->Misc.VirtualSize;
1388 if (pSh->PointerToRawData == 0 || pSh->SizeOfRawData == 0)
1389 {
1390 SegInfo.offFile = -1;
1391 SegInfo.cbFile = 0;
1392 }
1393 else
1394 {
1395 SegInfo.offFile = pSh->PointerToRawData;
1396 SegInfo.cbFile = pSh->SizeOfRawData;
1397 }
1398
1399 rc = pfnCallback(pMod, &SegInfo, pvUser);
1400 }
1401
1402 return rc;
1403}
1404
1405
1406/** @copydoc RTLDROPS::pfnLinkAddressToSegOffset. */
1407static DECLCALLBACK(int) rtldrPE_LinkAddressToSegOffset(PRTLDRMODINTERNAL pMod, RTLDRADDR LinkAddress,
1408 uint32_t *piSeg, PRTLDRADDR poffSeg)
1409{
1410 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1411
1412 LinkAddress -= pModPe->uImageBase;
1413
1414 /* Special header segment. */
1415 if (LinkAddress < pModPe->paSections[0].VirtualAddress)
1416 {
1417 *piSeg = 0;
1418 *poffSeg = LinkAddress;
1419 return VINF_SUCCESS;
1420 }
1421
1422 /*
1423 * Search the normal sections. (Could do this in binary fashion, they're
1424 * sorted, but too much bother right now.)
1425 */
1426 if (LinkAddress > pModPe->cbImage)
1427 return VERR_LDR_INVALID_LINK_ADDRESS;
1428 uint32_t i = pModPe->cSections;
1429 PCIMAGE_SECTION_HEADER paShs = pModPe->paSections;
1430 while (i-- > 0)
1431 if (!(paShs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
1432 {
1433 uint32_t uAddr = paShs[i].VirtualAddress;
1434 if (LinkAddress >= uAddr)
1435 {
1436 *poffSeg = LinkAddress - uAddr;
1437 *piSeg = i + 1;
1438 return VINF_SUCCESS;
1439 }
1440 }
1441
1442 return VERR_LDR_INVALID_LINK_ADDRESS;
1443}
1444
1445
1446/** @copydoc RTLDROPS::pfnLinkAddressToRva. */
1447static DECLCALLBACK(int) rtldrPE_LinkAddressToRva(PRTLDRMODINTERNAL pMod, RTLDRADDR LinkAddress, PRTLDRADDR pRva)
1448{
1449 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1450
1451 LinkAddress -= pModPe->uImageBase;
1452 if (LinkAddress > pModPe->cbImage)
1453 return VERR_LDR_INVALID_LINK_ADDRESS;
1454 *pRva = LinkAddress;
1455
1456 return VINF_SUCCESS;
1457}
1458
1459
1460/** @copydoc RTLDROPS::pfnSegOffsetToRva. */
1461static DECLCALLBACK(int) rtldrPE_SegOffsetToRva(PRTLDRMODINTERNAL pMod, uint32_t iSeg, RTLDRADDR offSeg,
1462 PRTLDRADDR pRva)
1463{
1464 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1465
1466 if (iSeg > pModPe->cSections)
1467 return VERR_LDR_INVALID_SEG_OFFSET;
1468
1469 /** @todo should validate offSeg here... too lazy right now. */
1470 if (iSeg == 0)
1471 *pRva = offSeg;
1472 else if (pModPe->paSections[iSeg].Characteristics & IMAGE_SCN_TYPE_NOLOAD)
1473 return VERR_LDR_INVALID_SEG_OFFSET;
1474 else
1475 *pRva = offSeg + pModPe->paSections[iSeg].VirtualAddress;
1476 return VINF_SUCCESS;
1477}
1478
1479
1480/** @copydoc RTLDROPS::pfnRvaToSegOffset. */
1481static DECLCALLBACK(int) rtldrPE_RvaToSegOffset(PRTLDRMODINTERNAL pMod, RTLDRADDR Rva,
1482 uint32_t *piSeg, PRTLDRADDR poffSeg)
1483{
1484 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1485 int rc = rtldrPE_LinkAddressToSegOffset(pMod, Rva + pModPe->uImageBase, piSeg, poffSeg);
1486 if (RT_FAILURE(rc))
1487 rc = VERR_LDR_INVALID_RVA;
1488 return rc;
1489}
1490
1491
1492/** @interface_method_impl{RTLDROPS,pfnQueryProp} */
1493static DECLCALLBACK(int) rtldrPE_QueryProp(PRTLDRMODINTERNAL pMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf)
1494{
1495 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1496 switch (enmProp)
1497 {
1498 case RTLDRPROP_TIMESTAMP_SECONDS:
1499 if (cbBuf == sizeof(int32_t))
1500 *(int32_t *)pvBuf = pModPe->uTimestamp;
1501 else if (cbBuf == sizeof(int64_t))
1502 *(int64_t *)pvBuf = pModPe->uTimestamp;
1503 else
1504 return VERR_INVALID_PARAMETER;
1505 break;
1506
1507 default:
1508 return VERR_NOT_FOUND;
1509 }
1510 return VINF_SUCCESS;
1511}
1512
1513
1514/** @copydoc RTLDROPS::pfnDone */
1515static DECLCALLBACK(int) rtldrPEDone(PRTLDRMODINTERNAL pMod)
1516{
1517 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1518 if (pModPe->pvBits)
1519 {
1520 RTMemFree(pModPe->pvBits);
1521 pModPe->pvBits = NULL;
1522 }
1523 return VINF_SUCCESS;
1524}
1525
1526/** @copydoc RTLDROPS::pfnClose */
1527static DECLCALLBACK(int) rtldrPEClose(PRTLDRMODINTERNAL pMod)
1528{
1529 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1530 if (pModPe->paSections)
1531 {
1532 RTMemFree(pModPe->paSections);
1533 pModPe->paSections = NULL;
1534 }
1535 if (pModPe->pvBits)
1536 {
1537 RTMemFree(pModPe->pvBits);
1538 pModPe->pvBits = NULL;
1539 }
1540 return VINF_SUCCESS;
1541}
1542
1543
1544/**
1545 * Operations for a 32-bit PE module.
1546 */
1547static const RTLDROPSPE s_rtldrPE32Ops =
1548{
1549 {
1550 "pe32",
1551 rtldrPEClose,
1552 NULL,
1553 rtldrPEDone,
1554 rtldrPEEnumSymbols,
1555 /* ext */
1556 rtldrPEGetImageSize,
1557 rtldrPEGetBits,
1558 rtldrPERelocate,
1559 rtldrPEGetSymbolEx,
1560 rtldrPE_EnumDbgInfo,
1561 rtldrPE_EnumSegments,
1562 rtldrPE_LinkAddressToSegOffset,
1563 rtldrPE_LinkAddressToRva,
1564 rtldrPE_SegOffsetToRva,
1565 rtldrPE_RvaToSegOffset,
1566 NULL,
1567 rtldrPE_QueryProp,
1568 42
1569 },
1570 rtldrPEResolveImports32,
1571 42
1572};
1573
1574
1575/**
1576 * Operations for a 64-bit PE module.
1577 */
1578static const RTLDROPSPE s_rtldrPE64Ops =
1579{
1580 {
1581 "pe64",
1582 rtldrPEClose,
1583 NULL,
1584 rtldrPEDone,
1585 rtldrPEEnumSymbols,
1586 /* ext */
1587 rtldrPEGetImageSize,
1588 rtldrPEGetBits,
1589 rtldrPERelocate,
1590 rtldrPEGetSymbolEx,
1591 rtldrPE_EnumDbgInfo,
1592 rtldrPE_EnumSegments,
1593 rtldrPE_LinkAddressToSegOffset,
1594 rtldrPE_LinkAddressToRva,
1595 rtldrPE_SegOffsetToRva,
1596 rtldrPE_RvaToSegOffset,
1597 NULL,
1598 rtldrPE_QueryProp,
1599 42
1600 },
1601 rtldrPEResolveImports64,
1602 42
1603};
1604
1605
1606/**
1607 * Converts the optional header from 32 bit to 64 bit.
1608 * This is a rather simple task, if you start from the right end.
1609 *
1610 * @param pOptHdr On input this is a PIMAGE_OPTIONAL_HEADER32.
1611 * On output this will be a PIMAGE_OPTIONAL_HEADER64.
1612 */
1613static void rtldrPEConvert32BitOptionalHeaderTo64Bit(PIMAGE_OPTIONAL_HEADER64 pOptHdr)
1614{
1615 /*
1616 * volatile everywhere! Trying to prevent the compiler being a smarta$$ and reorder stuff.
1617 */
1618 IMAGE_OPTIONAL_HEADER32 volatile *pOptHdr32 = (IMAGE_OPTIONAL_HEADER32 volatile *)pOptHdr;
1619 IMAGE_OPTIONAL_HEADER64 volatile *pOptHdr64 = pOptHdr;
1620
1621 /* from LoaderFlags and out the difference is 4 * 32-bits. */
1622 Assert(RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, LoaderFlags) + 16 == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, LoaderFlags));
1623 Assert( RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]) + 16
1624 == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]));
1625 uint32_t volatile *pu32Dst = (uint32_t *)&pOptHdr64->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1;
1626 const uint32_t volatile *pu32Src = (uint32_t *)&pOptHdr32->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1;
1627 const uint32_t volatile *pu32SrcLast = (uint32_t *)&pOptHdr32->LoaderFlags;
1628 while (pu32Src >= pu32SrcLast)
1629 *pu32Dst-- = *pu32Src--;
1630
1631 /* the previous 4 fields are 32/64 and needs special attention. */
1632 pOptHdr64->SizeOfHeapCommit = pOptHdr32->SizeOfHeapCommit;
1633 pOptHdr64->SizeOfHeapReserve = pOptHdr32->SizeOfHeapReserve;
1634 pOptHdr64->SizeOfStackCommit = pOptHdr32->SizeOfStackCommit;
1635 uint32_t u32SizeOfStackReserve = pOptHdr32->SizeOfStackReserve;
1636 pOptHdr64->SizeOfStackReserve = u32SizeOfStackReserve;
1637
1638 /* The rest matches except for BaseOfData which has been merged into ImageBase in the 64-bit version..
1639 * Thus, ImageBase needs some special treatment. It will probably work fine assigning one to the
1640 * other since this is all declared volatile, but taking now chances, we'll use a temp variable.
1641 */
1642 Assert(RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, SizeOfStackReserve) == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, SizeOfStackReserve));
1643 Assert(RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, BaseOfData) == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, ImageBase));
1644 Assert(RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, SectionAlignment) == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, SectionAlignment));
1645 uint32_t u32ImageBase = pOptHdr32->ImageBase;
1646 pOptHdr64->ImageBase = u32ImageBase;
1647}
1648
1649
1650/**
1651 * Converts the load config directory from 32 bit to 64 bit.
1652 * This is a rather simple task, if you start from the right end.
1653 *
1654 * @param pLoadCfg On input this is a PIMAGE_LOAD_CONFIG_DIRECTORY32.
1655 * On output this will be a PIMAGE_LOAD_CONFIG_DIRECTORY64.
1656 */
1657static void rtldrPEConvert32BitLoadConfigTo64Bit(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg)
1658{
1659 /*
1660 * volatile everywhere! Trying to prevent the compiler being a smarta$$ and reorder stuff.
1661 */
1662 IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *pLoadCfg32 = (IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *)pLoadCfg;
1663 IMAGE_LOAD_CONFIG_DIRECTORY64 volatile *pLoadCfg64 = pLoadCfg;
1664
1665 pLoadCfg64->SEHandlerCount = pLoadCfg32->SEHandlerCount;
1666 pLoadCfg64->SEHandlerTable = pLoadCfg32->SEHandlerTable;
1667 pLoadCfg64->SecurityCookie = pLoadCfg32->SecurityCookie;
1668 pLoadCfg64->EditList = pLoadCfg32->EditList;
1669 pLoadCfg64->Reserved1 = pLoadCfg32->Reserved1;
1670 pLoadCfg64->CSDVersion = pLoadCfg32->CSDVersion;
1671 pLoadCfg64->ProcessHeapFlags = pLoadCfg32->ProcessHeapFlags; /* switched place with ProcessAffinityMask, but we're more than 16 byte off by now so it doesn't matter. */
1672 pLoadCfg64->ProcessAffinityMask = pLoadCfg32->ProcessAffinityMask;
1673 pLoadCfg64->VirtualMemoryThreshold = pLoadCfg32->VirtualMemoryThreshold;
1674 pLoadCfg64->MaximumAllocationSize = pLoadCfg32->MaximumAllocationSize;
1675 pLoadCfg64->LockPrefixTable = pLoadCfg32->LockPrefixTable;
1676 pLoadCfg64->DeCommitTotalFreeThreshold = pLoadCfg32->DeCommitTotalFreeThreshold;
1677 uint32_t u32DeCommitFreeBlockThreshold = pLoadCfg32->DeCommitFreeBlockThreshold;
1678 pLoadCfg64->DeCommitFreeBlockThreshold = u32DeCommitFreeBlockThreshold;
1679 /* the rest is equal. */
1680 Assert( RT_OFFSETOF(IMAGE_LOAD_CONFIG_DIRECTORY32, DeCommitFreeBlockThreshold)
1681 == RT_OFFSETOF(IMAGE_LOAD_CONFIG_DIRECTORY64, DeCommitFreeBlockThreshold));
1682}
1683
1684
1685/**
1686 * Validates the file header.
1687 *
1688 * @returns iprt status code.
1689 * @param pFileHdr Pointer to the file header that needs validating.
1690 * @param fFlags Valid RTLDR_O_XXX combination.
1691 * @param pszLogName The log name to prefix the errors with.
1692 * @param penmArch Where to store the CPU architecture.
1693 */
1694static int rtldrPEValidateFileHeader(PIMAGE_FILE_HEADER pFileHdr, uint32_t fFlags, const char *pszLogName, PRTLDRARCH penmArch)
1695{
1696 size_t cbOptionalHeader;
1697 switch (pFileHdr->Machine)
1698 {
1699 case IMAGE_FILE_MACHINE_I386:
1700 cbOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER32);
1701 *penmArch = RTLDRARCH_X86_32;
1702 break;
1703 case IMAGE_FILE_MACHINE_AMD64:
1704 cbOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER64);
1705 *penmArch = RTLDRARCH_AMD64;
1706 break;
1707
1708 default:
1709 Log(("rtldrPEOpen: %s: Unsupported Machine=%#x\n",
1710 pszLogName, pFileHdr->Machine));
1711 *penmArch = RTLDRARCH_INVALID;
1712 return VERR_BAD_EXE_FORMAT;
1713 }
1714 if (pFileHdr->SizeOfOptionalHeader != cbOptionalHeader)
1715 {
1716 Log(("rtldrPEOpen: %s: SizeOfOptionalHeader=%#x expected %#x\n",
1717 pszLogName, pFileHdr->SizeOfOptionalHeader, cbOptionalHeader));
1718 return VERR_BAD_EXE_FORMAT;
1719 }
1720 /* This restriction needs to be implemented elsewhere. */
1721 if ( (pFileHdr->Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
1722 && !(fFlags & RTLDR_O_FOR_DEBUG))
1723 {
1724 Log(("rtldrPEOpen: %s: IMAGE_FILE_RELOCS_STRIPPED\n", pszLogName));
1725 return VERR_BAD_EXE_FORMAT;
1726 }
1727 if (pFileHdr->NumberOfSections > 42)
1728 {
1729 Log(("rtldrPEOpen: %s: NumberOfSections=%d - our limit is 42, please raise it if the binary makes sense.(!!!)\n",
1730 pszLogName, pFileHdr->NumberOfSections));
1731 return VERR_BAD_EXE_FORMAT;
1732 }
1733 if (pFileHdr->NumberOfSections < 1)
1734 {
1735 Log(("rtldrPEOpen: %s: NumberOfSections=%d - we can't have an image without sections (!!!)\n",
1736 pszLogName, pFileHdr->NumberOfSections));
1737 return VERR_BAD_EXE_FORMAT;
1738 }
1739 return VINF_SUCCESS;
1740}
1741
1742
1743/**
1744 * Validates the optional header (64/32-bit)
1745 *
1746 * @returns iprt status code.
1747 * @param pOptHdr Pointer to the optional header which needs validation.
1748 * @param pszLogName The log name to prefix the errors with.
1749 * @param offNtHdrs The offset of the NT headers from the start of the file.
1750 * @param pFileHdr Pointer to the file header (valid).
1751 * @param cbRawImage The raw image size.
1752 * @param fFlags Loader flags, RTLDR_O_XXX.
1753 */
1754static int rtldrPEValidateOptionalHeader(const IMAGE_OPTIONAL_HEADER64 *pOptHdr, const char *pszLogName, RTFOFF offNtHdrs,
1755 const IMAGE_FILE_HEADER *pFileHdr, RTFOFF cbRawImage, uint32_t fFlags)
1756{
1757 const uint16_t CorrectMagic = pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
1758 ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC;
1759 if (pOptHdr->Magic != CorrectMagic)
1760 {
1761 Log(("rtldrPEOpen: %s: Magic=%#x - expected %#x!!!\n", pszLogName, pOptHdr->Magic, CorrectMagic));
1762 return VERR_BAD_EXE_FORMAT;
1763 }
1764 const uint32_t cbImage = pOptHdr->SizeOfImage;
1765 if (cbImage > _1G)
1766 {
1767 Log(("rtldrPEOpen: %s: SizeOfImage=%#x - Our limit is 1GB (%#x)!!!\n", pszLogName, cbImage, _1G));
1768 return VERR_BAD_EXE_FORMAT;
1769 }
1770 const uint32_t cbMinImageSize = pFileHdr->SizeOfOptionalHeader + sizeof(*pFileHdr) + 4 + (uint32_t)offNtHdrs;
1771 if (cbImage < cbMinImageSize)
1772 {
1773 Log(("rtldrPEOpen: %s: SizeOfImage=%#x to small, minimum %#x!!!\n", pszLogName, cbImage, cbMinImageSize));
1774 return VERR_BAD_EXE_FORMAT;
1775 }
1776 if (pOptHdr->AddressOfEntryPoint >= cbImage)
1777 {
1778 Log(("rtldrPEOpen: %s: AddressOfEntryPoint=%#x - beyond image size (%#x)!!!\n",
1779 pszLogName, pOptHdr->AddressOfEntryPoint, cbImage));
1780 return VERR_BAD_EXE_FORMAT;
1781 }
1782 if (pOptHdr->BaseOfCode >= cbImage)
1783 {
1784 Log(("rtldrPEOpen: %s: BaseOfCode=%#x - beyond image size (%#x)!!!\n",
1785 pszLogName, pOptHdr->BaseOfCode, cbImage));
1786 return VERR_BAD_EXE_FORMAT;
1787 }
1788#if 0/* only in 32-bit header */
1789 if (pOptHdr->BaseOfData >= cbImage)
1790 {
1791 Log(("rtldrPEOpen: %s: BaseOfData=%#x - beyond image size (%#x)!!!\n",
1792 pszLogName, pOptHdr->BaseOfData, cbImage));
1793 return VERR_BAD_EXE_FORMAT;
1794 }
1795#endif
1796 if (pOptHdr->SizeOfHeaders >= cbImage)
1797 {
1798 Log(("rtldrPEOpen: %s: SizeOfHeaders=%#x - beyond image size (%#x)!!!\n",
1799 pszLogName, pOptHdr->SizeOfHeaders, cbImage));
1800 return VERR_BAD_EXE_FORMAT;
1801 }
1802 /* don't know how to do the checksum, so ignore it. */
1803 if (pOptHdr->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN)
1804 {
1805 Log(("rtldrPEOpen: %s: Subsystem=%#x (unknown)!!!\n", pszLogName, pOptHdr->Subsystem));
1806 return VERR_BAD_EXE_FORMAT;
1807 }
1808 if (pOptHdr->SizeOfHeaders < cbMinImageSize + pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER))
1809 {
1810 Log(("rtldrPEOpen: %s: SizeOfHeaders=%#x - cbMinImageSize %#x + sections %#x = %#llx!!!\n",
1811 pszLogName, pOptHdr->SizeOfHeaders,
1812 cbImage, cbMinImageSize, pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER),
1813 cbMinImageSize + pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER)));
1814 return VERR_BAD_EXE_FORMAT;
1815 }
1816 if (pOptHdr->SizeOfStackReserve < pOptHdr->SizeOfStackCommit)
1817 {
1818 Log(("rtldrPEOpen: %s: SizeOfStackReserve %#x < SizeOfStackCommit %#x!!!\n",
1819 pszLogName, pOptHdr->SizeOfStackReserve, pOptHdr->SizeOfStackCommit));
1820 return VERR_BAD_EXE_FORMAT;
1821 }
1822 if (pOptHdr->SizeOfHeapReserve < pOptHdr->SizeOfHeapCommit)
1823 {
1824 Log(("rtldrPEOpen: %s: SizeOfStackReserve %#x < SizeOfStackCommit %#x!!!\n",
1825 pszLogName, pOptHdr->SizeOfStackReserve, pOptHdr->SizeOfStackCommit));
1826 return VERR_BAD_EXE_FORMAT;
1827 }
1828
1829 /* DataDirectory */
1830 if (pOptHdr->NumberOfRvaAndSizes != RT_ELEMENTS(pOptHdr->DataDirectory))
1831 {
1832 Log(("rtldrPEOpen: %s: NumberOfRvaAndSizes=%d!!!\n", pszLogName, pOptHdr->NumberOfRvaAndSizes));
1833 return VERR_BAD_EXE_FORMAT;
1834 }
1835 for (unsigned i = 0; i < RT_ELEMENTS(pOptHdr->DataDirectory); i++)
1836 {
1837 IMAGE_DATA_DIRECTORY const *pDir = &pOptHdr->DataDirectory[i];
1838 if (!pDir->Size)
1839 continue;
1840 size_t cb = cbImage;
1841 switch (i)
1842 {
1843 case IMAGE_DIRECTORY_ENTRY_EXPORT: // 0
1844 case IMAGE_DIRECTORY_ENTRY_IMPORT: // 1
1845 case IMAGE_DIRECTORY_ENTRY_RESOURCE: // 2
1846 case IMAGE_DIRECTORY_ENTRY_EXCEPTION: // 3
1847 case IMAGE_DIRECTORY_ENTRY_BASERELOC: // 5
1848 case IMAGE_DIRECTORY_ENTRY_DEBUG: // 6
1849 case IMAGE_DIRECTORY_ENTRY_COPYRIGHT: // 7
1850 case IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT: // 11
1851 case IMAGE_DIRECTORY_ENTRY_IAT: // 12 /* Import Address Table */
1852 break;
1853 case IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG: // 10 - need to check for lock prefixes.
1854 /* Delay inspection after section table is validated. */
1855 break;
1856
1857 case IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT: // 13
1858 Log(("rtldrPEOpen: %s: dir no. %d (DELAY_IMPORT) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1859 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1860 return VERR_LDRPE_DELAY_IMPORT;
1861
1862 case IMAGE_DIRECTORY_ENTRY_SECURITY: // 4
1863 /* The VirtualAddress is a PointerToRawData. */
1864 cb = (size_t)cbRawImage; Assert((RTFOFF)cb == cbRawImage);
1865 Log(("rtldrPEOpen: %s: dir no. %d (SECURITY) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1866 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1867 if (pDir->Size < sizeof(WIN_CERTIFICATE))
1868 {
1869 Log(("rtldrPEOpen: %s: Security directory is too small: %#x bytes\n", pszLogName, i, pDir->Size));
1870 return VERR_LDRPE_CERT_MALFORMED;
1871 }
1872 if (pDir->Size >= _1M)
1873 {
1874 Log(("rtldrPEOpen: %s: Security directory is too large: %#x bytes\n", pszLogName, i, pDir->Size));
1875 return VERR_LDRPE_CERT_MALFORMED;
1876 }
1877 if (pDir->VirtualAddress & 7)
1878 {
1879 Log(("rtldrPEOpen: %s: Security directory is misaligned: %#x\n", pszLogName, i, pDir->VirtualAddress));
1880 return VERR_LDRPE_CERT_MALFORMED;
1881 }
1882 /* When using the in-memory reader with a debugger, we may get
1883 into trouble here since we might not have access to the whole
1884 physical file. So skip the tests below. Makes VBoxGuest.sys
1885 load and check out just fine, for instance. */
1886 if (fFlags & RTLDR_O_FOR_DEBUG)
1887 continue;
1888 break;
1889
1890 case IMAGE_DIRECTORY_ENTRY_GLOBALPTR: // 8 /* (MIPS GP) */
1891 Log(("rtldrPEOpen: %s: dir no. %d (GLOBALPTR) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1892 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1893 return VERR_LDRPE_GLOBALPTR;
1894
1895 case IMAGE_DIRECTORY_ENTRY_TLS: // 9
1896 Log(("rtldrPEOpen: %s: dir no. %d (TLS) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1897 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1898 return VERR_LDRPE_TLS;
1899
1900 case IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR:// 14
1901 Log(("rtldrPEOpen: %s: dir no. %d (COM_DESCRIPTOR) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1902 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1903 return VERR_LDRPE_COM_DESCRIPTOR;
1904
1905 default:
1906 Log(("rtldrPEOpen: %s: dir no. %d VirtualAddress=%#x Size=%#x is not supported!!!\n",
1907 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1908 return VERR_BAD_EXE_FORMAT;
1909 }
1910 if (pDir->VirtualAddress >= cb)
1911 {
1912 Log(("rtldrPEOpen: %s: dir no. %d VirtualAddress=%#x is invalid (limit %#x)!!!\n",
1913 pszLogName, i, pDir->VirtualAddress, cb));
1914 return VERR_BAD_EXE_FORMAT;
1915 }
1916 if (pDir->Size > cb - pDir->VirtualAddress)
1917 {
1918 Log(("rtldrPEOpen: %s: dir no. %d Size=%#x is invalid (rva=%#x, limit=%#x)!!!\n",
1919 pszLogName, i, pDir->Size, pDir->VirtualAddress, cb));
1920 return VERR_BAD_EXE_FORMAT;
1921 }
1922 }
1923 return VINF_SUCCESS;
1924}
1925
1926
1927/**
1928 * Validates the section headers.
1929 *
1930 * @returns iprt status code.
1931 * @param paSections Pointer to the array of sections that is to be validated.
1932 * @param cSections Number of sections in that array.
1933 * @param pszLogName The log name to prefix the errors with.
1934 * @param pOptHdr Pointer to the optional header (valid).
1935 * @param cbRawImage The raw image size.
1936 * @param fFlags Loader flags, RTLDR_O_XXX.
1937 */
1938static int rtldrPEValidateSectionHeaders(const IMAGE_SECTION_HEADER *paSections, unsigned cSections, const char *pszLogName,
1939 const IMAGE_OPTIONAL_HEADER64 *pOptHdr, RTFOFF cbRawImage, uint32_t fFlags)
1940{
1941 const uint32_t cbImage = pOptHdr->SizeOfImage;
1942 const IMAGE_SECTION_HEADER *pSH = &paSections[0];
1943 uint32_t uRvaPrev = pOptHdr->SizeOfHeaders;
1944 Log3(("RTLdrPE: Section Headers:\n"));
1945 for (unsigned cSHdrsLeft = cSections; cSHdrsLeft > 0; cSHdrsLeft--, pSH++)
1946 {
1947 const unsigned iSH = pSH - &paSections[0]; NOREF(iSH);
1948 Log3(("RTLdrPE: #%d '%-8.8s' Characteristics: %08RX32\n"
1949 "RTLdrPE: VirtAddr: %08RX32 VirtSize: %08RX32\n"
1950 "RTLdrPE: FileOff: %08RX32 FileSize: %08RX32\n"
1951 "RTLdrPE: RelocOff: %08RX32 #Relocs: %08RX32\n"
1952 "RTLdrPE: LineOff: %08RX32 #Lines: %08RX32\n",
1953 iSH, pSH->Name, pSH->Characteristics,
1954 pSH->VirtualAddress, pSH->Misc.VirtualSize,
1955 pSH->PointerToRawData, pSH->SizeOfRawData,
1956 pSH->PointerToRelocations, pSH->NumberOfRelocations,
1957 pSH->PointerToLinenumbers, pSH->NumberOfLinenumbers));
1958
1959 AssertCompile(IMAGE_SCN_MEM_16BIT == IMAGE_SCN_MEM_PURGEABLE);
1960 if ( ( pSH->Characteristics & (IMAGE_SCN_MEM_PURGEABLE | IMAGE_SCN_MEM_PRELOAD | IMAGE_SCN_MEM_FARDATA) )
1961 && !(fFlags & RTLDR_O_FOR_DEBUG)) /* purgable/16-bit seen on w2ksp0 hal.dll, ignore the bunch. */
1962 {
1963 Log(("rtldrPEOpen: %s: Unsupported section flag(s) %#x section #%d '%.*s'!!!\n",
1964 pszLogName, pSH->Characteristics, iSH, sizeof(pSH->Name), pSH->Name));
1965 return VERR_BAD_EXE_FORMAT;
1966 }
1967
1968 if ( pSH->Misc.VirtualSize
1969 && !(pSH->Characteristics & IMAGE_SCN_TYPE_NOLOAD)) /* binutils uses this for '.stab' even if it's reserved/obsoleted by MS. */
1970 {
1971 if (pSH->VirtualAddress < uRvaPrev)
1972 {
1973 Log(("rtldrPEOpen: %s: Overlaps previous section or sections aren't in ascending order, VirtualAddress=%#x uRvaPrev=%#x - section #%d '%.*s'!!!\n",
1974 pszLogName, pSH->VirtualAddress, uRvaPrev, iSH, sizeof(pSH->Name), pSH->Name));
1975 return VERR_BAD_EXE_FORMAT;
1976 }
1977 if (pSH->VirtualAddress > cbImage)
1978 {
1979 Log(("rtldrPEOpen: %s: VirtualAddress=%#x - beyond image size (%#x) - section #%d '%.*s'!!!\n",
1980 pszLogName, pSH->VirtualAddress, cbImage, iSH, sizeof(pSH->Name), pSH->Name));
1981 return VERR_BAD_EXE_FORMAT;
1982 }
1983
1984 if (pSH->VirtualAddress & (pOptHdr->SectionAlignment - 1)) //ASSUMES power of 2 alignment.
1985 {
1986 Log(("rtldrPEOpen: %s: VirtualAddress=%#x misaligned (%#x) - section #%d '%.*s'!!!\n",
1987 pszLogName, pSH->VirtualAddress, pOptHdr->SectionAlignment, iSH, sizeof(pSH->Name), pSH->Name));
1988 return VERR_BAD_EXE_FORMAT;
1989 }
1990
1991#ifdef PE_FILE_OFFSET_EQUALS_RVA
1992 /* Our loader code assume rva matches the file offset. */
1993 if ( pSH->SizeOfRawData
1994 && pSH->PointerToRawData != pSH->VirtualAddress)
1995 {
1996 Log(("rtldrPEOpen: %s: ASSUMPTION FAILED: file offset %#x != RVA %#x - section #%d '%.*s'!!!\n",
1997 pszLogName, pSH->PointerToRawData, pSH->VirtualAddress, iSH, sizeof(pSH->Name), pSH->Name));
1998 return VERR_BAD_EXE_FORMAT;
1999 }
2000#endif
2001 }
2002
2003 ///@todo only if SizeOfRawData > 0 ?
2004 if ( pSH->PointerToRawData > cbRawImage /// @todo pSH->PointerToRawData >= cbRawImage ?
2005 || pSH->SizeOfRawData > cbRawImage
2006 || pSH->PointerToRawData + pSH->SizeOfRawData > cbRawImage)
2007 {
2008 Log(("rtldrPEOpen: %s: PointerToRawData=%#x SizeOfRawData=%#x - beyond end of file (%#x) - section #%d '%.*s'!!!\n",
2009 pszLogName, pSH->PointerToRawData, pSH->SizeOfRawData, cbRawImage,
2010 iSH, sizeof(pSH->Name), pSH->Name));
2011 return VERR_BAD_EXE_FORMAT;
2012 }
2013
2014 if (pSH->PointerToRawData & (pOptHdr->FileAlignment - 1)) //ASSUMES power of 2 alignment.
2015 {
2016 Log(("rtldrPEOpen: %s: PointerToRawData=%#x misaligned (%#x) - section #%d '%.*s'!!!\n",
2017 pszLogName, pSH->PointerToRawData, pOptHdr->FileAlignment, iSH, sizeof(pSH->Name), pSH->Name));
2018 return VERR_BAD_EXE_FORMAT;
2019 }
2020
2021 /* ignore the relocations and linenumbers. */
2022
2023 uRvaPrev = pSH->VirtualAddress + pSH->Misc.VirtualSize;
2024 }
2025
2026 /** @todo r=bird: more sanity checks! */
2027 return VINF_SUCCESS;
2028}
2029
2030
2031/**
2032 * Reads image data by RVA using the section headers.
2033 *
2034 * @returns iprt status code.
2035 * @param pModPe The PE module instance.
2036 * @param pvBuf Where to store the bits.
2037 * @param cb Number of bytes to tread.
2038 * @param RVA Where to read from.
2039 */
2040static int rtldrPEReadRVA(PRTLDRMODPE pModPe, void *pvBuf, uint32_t cb, uint32_t RVA)
2041{
2042 const IMAGE_SECTION_HEADER *pSH = pModPe->paSections;
2043 PRTLDRREADER pReader = pModPe->Core.pReader;
2044 uint32_t cbRead;
2045 int rc;
2046
2047 /*
2048 * Is it the headers, i.e. prior to the first section.
2049 */
2050 if (RVA < pModPe->cbHeaders)
2051 {
2052 cbRead = RT_MIN(pModPe->cbHeaders - RVA, cb);
2053 rc = pReader->pfnRead(pReader, pvBuf, cbRead, RVA);
2054 if ( cbRead == cb
2055 || RT_FAILURE(rc))
2056 return rc;
2057 cb -= cbRead;
2058 RVA += cbRead;
2059 pvBuf = (uint8_t *)pvBuf + cbRead;
2060 }
2061
2062 /* In the zero space between headers and the first section? */
2063 if (RVA < pSH->VirtualAddress)
2064 {
2065 cbRead = RT_MIN(pSH->VirtualAddress - RVA, cb);
2066 memset(pvBuf, 0, cbRead);
2067 if (cbRead == cb)
2068 return VINF_SUCCESS;
2069 cb -= cbRead;
2070 RVA += cbRead;
2071 pvBuf = (uint8_t *)pvBuf + cbRead;
2072 }
2073
2074 /*
2075 * Iterate the sections.
2076 */
2077 for (unsigned cLeft = pModPe->cSections;
2078 cLeft > 0;
2079 cLeft--, pSH++)
2080 {
2081 uint32_t off = RVA - pSH->VirtualAddress;
2082 if (off < pSH->Misc.VirtualSize)
2083 {
2084 cbRead = RT_MIN(pSH->Misc.VirtualSize - off, cb);
2085 rc = pReader->pfnRead(pReader, pvBuf, cbRead, pSH->PointerToRawData + off);
2086 if ( cbRead == cb
2087 || RT_FAILURE(rc))
2088 return rc;
2089 cb -= cbRead;
2090 RVA += cbRead;
2091 pvBuf = (uint8_t *)pvBuf + cbRead;
2092 }
2093 uint32_t RVANext = cLeft ? pSH[1].VirtualAddress : pModPe->cbImage;
2094 if (RVA < RVANext)
2095 {
2096 cbRead = RT_MIN(RVANext - RVA, cb);
2097 memset(pvBuf, 0, cbRead);
2098 if (cbRead == cb)
2099 return VINF_SUCCESS;
2100 cb -= cbRead;
2101 RVA += cbRead;
2102 pvBuf = (uint8_t *)pvBuf + cbRead;
2103 }
2104 }
2105
2106 AssertFailed();
2107 return VERR_INTERNAL_ERROR;
2108}
2109
2110
2111/**
2112 * Validates the data of some selected data directories entries.
2113 *
2114 * This requires a valid section table and thus has to wait
2115 * till after we've read and validated it.
2116 *
2117 * @returns iprt status code.
2118 * @param pModPe The PE module instance.
2119 * @param pOptHdr Pointer to the optional header (valid).
2120 * @param fFlags Loader flags, RTLDR_O_XXX.
2121 */
2122static int rtldrPEValidateDirectories(PRTLDRMODPE pModPe, const IMAGE_OPTIONAL_HEADER64 *pOptHdr, uint32_t fFlags)
2123{
2124 const char *pszLogName = pModPe->Core.pReader->pfnLogName(pModPe->Core.pReader); NOREF(pszLogName);
2125 union /* combine stuff we're reading to help reduce stack usage. */
2126 {
2127 IMAGE_LOAD_CONFIG_DIRECTORY64 Cfg64;
2128 } u;
2129
2130 /*
2131 * The load config entry may include lock prefix tables and whatnot which we don't implement.
2132 * It does also include a lot of stuff which we can ignore, so we'll have to inspect the
2133 * actual data before we can make up our mind about it all.
2134 */
2135 IMAGE_DATA_DIRECTORY Dir = pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG];
2136 if (Dir.Size)
2137 {
2138 const size_t cbExpect = pOptHdr->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC
2139 ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32)
2140 : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64);
2141 if ( Dir.Size != cbExpect
2142 && ( cbExpect == sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32)
2143 && Dir.Size != (uint32_t)RT_OFFSETOF(IMAGE_LOAD_CONFIG_DIRECTORY32, SEHandlerTable))
2144 )
2145 {
2146 Log(("rtldrPEOpen: %s: load cfg dir: unexpected dir size of %d bytes, expected %d.\n",
2147 pszLogName, Dir.Size, cbExpect));
2148 return VERR_LDRPE_LOAD_CONFIG_SIZE;
2149 }
2150
2151 /*
2152 * Read and convert to 64-bit.
2153 */
2154 memset(&u.Cfg64, 0, sizeof(u.Cfg64));
2155 int rc = rtldrPEReadRVA(pModPe, &u.Cfg64, Dir.Size, Dir.VirtualAddress);
2156 if (RT_FAILURE(rc))
2157 return rc;
2158 rtldrPEConvert32BitLoadConfigTo64Bit(&u.Cfg64);
2159
2160 if (u.Cfg64.Size != cbExpect)
2161 {
2162 Log(("rtldrPEOpen: %s: load cfg dir: unexpected header size of %d bytes, expected %d.\n",
2163 pszLogName, u.Cfg64.Size, cbExpect));
2164 return VERR_LDRPE_LOAD_CONFIG_SIZE;
2165 }
2166 if (u.Cfg64.LockPrefixTable)
2167 {
2168 Log(("rtldrPEOpen: %s: load cfg dir: lock prefix table at %RX64. We don't support lock prefix tables!\n",
2169 pszLogName, u.Cfg64.LockPrefixTable));
2170 return VERR_LDRPE_LOCK_PREFIX_TABLE;
2171 }
2172#if 0/* this seems to be safe to ignore. */
2173 if ( u.Cfg64.SEHandlerTable
2174 || u.Cfg64.SEHandlerCount)
2175 {
2176 Log(("rtldrPEOpen: %s: load cfg dir: SEHandlerTable=%RX64 and SEHandlerCount=%RX64 are unsupported!\n",
2177 pszLogName, u.Cfg64.SEHandlerTable, u.Cfg64.SEHandlerCount));
2178 return VERR_BAD_EXE_FORMAT;
2179 }
2180#endif
2181 if (u.Cfg64.EditList)
2182 {
2183 Log(("rtldrPEOpen: %s: load cfg dir: EditList=%RX64 is unsupported!\n",
2184 pszLogName, u.Cfg64.EditList));
2185 return VERR_BAD_EXE_FORMAT;
2186 }
2187 }
2188
2189 /*
2190 * If the image is signed and we're not doing this for debug purposes,
2191 * take a look at the signature.
2192 */
2193 Dir = pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
2194 if (Dir.Size && !(fFlags & RTLDR_O_FOR_DEBUG))
2195 {
2196 PWIN_CERTIFICATE pFirst = (PWIN_CERTIFICATE)RTMemTmpAlloc(Dir.Size);
2197 if (!pFirst)
2198 return VERR_NO_TMP_MEMORY;
2199 int rc = pModPe->Core.pReader->pfnRead(pModPe->Core.pReader, pFirst, Dir.Size, Dir.VirtualAddress);
2200 if (RT_SUCCESS(rc))
2201 {
2202 uint32_t off = 0;
2203 PWIN_CERTIFICATE pCur = pFirst;
2204 do
2205 {
2206 /* validate the members. */
2207 uint32_t const cbCur = RT_ALIGN_32(pCur->dwLength, 8);
2208 if ( cbCur < sizeof(WIN_CERTIFICATE)
2209 || cbCur + off > RT_ALIGN_32(Dir.Size, 8))
2210 {
2211 Log(("rtldrPEOpen: %s: cert at %#x/%#x: dwLength=%#x\n", pszLogName, off, Dir.Size, pCur->dwLength));
2212 rc = VERR_LDRPE_CERT_MALFORMED;
2213 break;
2214 }
2215 if ( pCur->wRevision != WIN_CERT_REVISION_2_0
2216 && pCur->wRevision != WIN_CERT_REVISION_1_0)
2217 {
2218 Log(("rtldrPEOpen: %s: cert at %#x/%#x: wRevision=%#x\n", pszLogName, off, Dir.Size, pCur->wRevision));
2219 rc = pCur->wRevision >= WIN_CERT_REVISION_1_0 ? VERR_LDRPE_CERT_UNSUPPORTED : VERR_LDRPE_CERT_MALFORMED;
2220 break;
2221 }
2222 if ( pCur->wCertificateType != WIN_CERT_TYPE_PKCS_SIGNED_DATA
2223 && pCur->wCertificateType != WIN_CERT_TYPE_X509
2224 /*&& pCur->wCertificateType != WIN_CERT_TYPE_RESERVED_1*/
2225 /*&& pCur->wCertificateType != WIN_CERT_TYPE_TS_STACK_SIGNED*/
2226 && pCur->wCertificateType != WIN_CERT_TYPE_EFI_PKCS115
2227 && pCur->wCertificateType != WIN_CERT_TYPE_EFI_GUID
2228 )
2229 {
2230 Log(("rtldrPEOpen: %s: cert at %#x/%#x: wRevision=%#x\n", pszLogName, off, Dir.Size, pCur->wRevision));
2231 rc = pCur->wCertificateType ? VERR_LDRPE_CERT_UNSUPPORTED : VERR_LDRPE_CERT_MALFORMED;
2232 break;
2233 }
2234
2235 /** @todo Rainy Day: Implement further verification using openssl. */
2236
2237 /* next */
2238 off += cbCur;
2239 pCur = (PWIN_CERTIFICATE)((uint8_t *)pCur + cbCur);
2240 } while (off < Dir.Size);
2241 }
2242 RTMemTmpFree(pFirst);
2243 if (RT_FAILURE(rc))
2244 return rc;
2245 }
2246
2247
2248 return VINF_SUCCESS;
2249}
2250
2251
2252/**
2253 * Open a PE image.
2254 *
2255 * @returns iprt status code.
2256 * @param pReader The loader reader instance which will provide the raw image bits.
2257 * @param fFlags Loader flags, RTLDR_O_XXX.
2258 * @param enmArch Architecture specifier.
2259 * @param offNtHdrs The offset of the NT headers (where you find "PE\0\0").
2260 * @param phLdrMod Where to store the handle.
2261 */
2262int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF offNtHdrs, PRTLDRMOD phLdrMod)
2263{
2264 /*
2265 * Read and validate the file header.
2266 */
2267 IMAGE_FILE_HEADER FileHdr;
2268 int rc = pReader->pfnRead(pReader, &FileHdr, sizeof(FileHdr), offNtHdrs + 4);
2269 if (RT_FAILURE(rc))
2270 return rc;
2271 RTLDRARCH enmArchImage;
2272 const char *pszLogName = pReader->pfnLogName(pReader);
2273 rc = rtldrPEValidateFileHeader(&FileHdr, fFlags, pszLogName, &enmArchImage);
2274 if (RT_FAILURE(rc))
2275 return rc;
2276
2277 /*
2278 * Match the CPU architecture.
2279 */
2280 if ( enmArch != RTLDRARCH_WHATEVER
2281 && enmArch != enmArchImage)
2282 return VERR_LDR_ARCH_MISMATCH;
2283
2284 /*
2285 * Read and validate the "optional" header. Convert 32->64 if necessary.
2286 */
2287 IMAGE_OPTIONAL_HEADER64 OptHdr;
2288 rc = pReader->pfnRead(pReader, &OptHdr, FileHdr.SizeOfOptionalHeader, offNtHdrs + 4 + sizeof(IMAGE_FILE_HEADER));
2289 if (RT_FAILURE(rc))
2290 return rc;
2291 if (FileHdr.SizeOfOptionalHeader != sizeof(OptHdr))
2292 rtldrPEConvert32BitOptionalHeaderTo64Bit(&OptHdr);
2293 rc = rtldrPEValidateOptionalHeader(&OptHdr, pszLogName, offNtHdrs, &FileHdr, pReader->pfnSize(pReader), fFlags);
2294 if (RT_FAILURE(rc))
2295 return rc;
2296
2297 /*
2298 * Read and validate section headers.
2299 */
2300 const size_t cbSections = sizeof(IMAGE_SECTION_HEADER) * FileHdr.NumberOfSections;
2301 PIMAGE_SECTION_HEADER paSections = (PIMAGE_SECTION_HEADER)RTMemAlloc(cbSections);
2302 if (!paSections)
2303 return VERR_NO_MEMORY;
2304 rc = pReader->pfnRead(pReader, paSections, cbSections,
2305 offNtHdrs + 4 + sizeof(IMAGE_FILE_HEADER) + FileHdr.SizeOfOptionalHeader);
2306 if (RT_SUCCESS(rc))
2307 {
2308 rc = rtldrPEValidateSectionHeaders(paSections, FileHdr.NumberOfSections, pszLogName,
2309 &OptHdr, pReader->pfnSize(pReader), fFlags);
2310 if (RT_SUCCESS(rc))
2311 {
2312 /*
2313 * Allocate and initialize the PE module structure.
2314 */
2315 PRTLDRMODPE pModPe = (PRTLDRMODPE)RTMemAllocZ(sizeof(*pModPe));
2316 if (pModPe)
2317 {
2318 pModPe->Core.u32Magic = RTLDRMOD_MAGIC;
2319 pModPe->Core.eState = LDR_STATE_OPENED;
2320 if (FileHdr.SizeOfOptionalHeader == sizeof(OptHdr))
2321 pModPe->Core.pOps = &s_rtldrPE64Ops.Core;
2322 else
2323 pModPe->Core.pOps = &s_rtldrPE32Ops.Core;
2324 pModPe->Core.pReader = pReader;
2325 pModPe->Core.enmFormat= RTLDRFMT_PE;
2326 pModPe->Core.enmType = FileHdr.Characteristics & IMAGE_FILE_DLL
2327 ? FileHdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED
2328 ? RTLDRTYPE_EXECUTABLE_FIXED
2329 : RTLDRTYPE_EXECUTABLE_RELOCATABLE
2330 : FileHdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED
2331 ? RTLDRTYPE_SHARED_LIBRARY_FIXED
2332 : RTLDRTYPE_SHARED_LIBRARY_RELOCATABLE;
2333 pModPe->Core.enmEndian= RTLDRENDIAN_LITTLE;
2334 pModPe->Core.enmArch = FileHdr.Machine == IMAGE_FILE_MACHINE_I386
2335 ? RTLDRARCH_X86_32
2336 : FileHdr.Machine == IMAGE_FILE_MACHINE_AMD64
2337 ? RTLDRARCH_AMD64
2338 : RTLDRARCH_WHATEVER;
2339 pModPe->pvBits = NULL;
2340 pModPe->offNtHdrs = offNtHdrs;
2341 pModPe->offEndOfHdrs = offNtHdrs + 4 + sizeof(IMAGE_FILE_HEADER) + FileHdr.SizeOfOptionalHeader + cbSections;
2342 pModPe->u16Machine = FileHdr.Machine;
2343 pModPe->fFile = FileHdr.Characteristics;
2344 pModPe->cSections = FileHdr.NumberOfSections;
2345 pModPe->paSections = paSections;
2346 pModPe->uEntryPointRVA= OptHdr.AddressOfEntryPoint;
2347 pModPe->uImageBase = (RTUINTPTR)OptHdr.ImageBase;
2348 pModPe->cbImage = OptHdr.SizeOfImage;
2349 pModPe->cbHeaders = OptHdr.SizeOfHeaders;
2350 pModPe->uTimestamp = FileHdr.TimeDateStamp;
2351 pModPe->ImportDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
2352 pModPe->RelocDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
2353 pModPe->ExportDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
2354 pModPe->DebugDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
2355
2356 /*
2357 * Perform validation of some selected data directories which requires
2358 * inspection of the actual data.
2359 */
2360 rc = rtldrPEValidateDirectories(pModPe, &OptHdr, fFlags);
2361 if (RT_SUCCESS(rc))
2362 {
2363 *phLdrMod = &pModPe->Core;
2364 return VINF_SUCCESS;
2365 }
2366 RTMemFree(pModPe);
2367 }
2368 else
2369 rc = VERR_NO_MEMORY;
2370 }
2371 }
2372 RTMemFree(paSections);
2373 return rc;
2374}
2375
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