VirtualBox

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

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

Got the NT4 ntfs.sys case working. Turned out to be some memory saving strategy applied to some images during early (?) loading.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 83.2 KB
Line 
1/* $Id: ldrPE.cpp 46108 2013-05-15 19:22:38Z 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/** @copydoc RTLDROPS::pfnEnumSymbols */
896static DECLCALLBACK(int) rtldrPEEnumSymbols(PRTLDRMODINTERNAL pMod, unsigned fFlags, const void *pvBits, RTUINTPTR BaseAddress,
897 PFNRTLDRENUMSYMS pfnCallback, void *pvUser)
898{
899 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
900 NOREF(fFlags); /* ignored ... */
901
902 /*
903 * Check if there is actually anything to work on.
904 */
905 if ( !pModPe->ExportDir.VirtualAddress
906 || !pModPe->ExportDir.Size)
907 return VERR_SYMBOL_NOT_FOUND;
908
909 /*
910 * No bits supplied? Do we need to read the bits?
911 */
912 if (!pvBits)
913 {
914 if (!pModPe->pvBits)
915 {
916 int rc = rtldrPEReadBits(pModPe);
917 if (RT_FAILURE(rc))
918 return rc;
919 }
920 pvBits = pModPe->pvBits;
921 }
922
923 /*
924 * We enumerates by ordinal, which means using a slow linear search for
925 * getting any name
926 */
927 PIMAGE_EXPORT_DIRECTORY pExpDir = PE_RVA2TYPE(pvBits, pModPe->ExportDir.VirtualAddress, PIMAGE_EXPORT_DIRECTORY);
928 uint32_t *paAddress = PE_RVA2TYPE(pvBits, pExpDir->AddressOfFunctions, uint32_t *);
929 uint32_t *paRVANames = PE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, uint32_t *);
930 uint16_t *paOrdinals = PE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, uint16_t *);
931 uintptr_t uNamePrev = 0;
932 unsigned cOrdinals = RT_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions);
933 for (unsigned uOrdinal = 0; uOrdinal < cOrdinals; uOrdinal++)
934 {
935 if (paAddress[uOrdinal] /* needed? */)
936 {
937 /*
938 * Look for name.
939 */
940 const char *pszName = NULL;
941 /* Search from previous + 1 to the end. */
942 unsigned uName = uNamePrev + 1;
943 while (uName < pExpDir->NumberOfNames)
944 {
945 if (paOrdinals[uName] == uOrdinal)
946 {
947 pszName = PE_RVA2TYPE(pvBits, paRVANames[uName], const char *);
948 uNamePrev = uName;
949 break;
950 }
951 uName++;
952 }
953 if (!pszName)
954 {
955 /* Search from start to the previous. */
956 uName = 0;
957 for (uName = 0 ; uName <= uNamePrev; uName++)
958 {
959 if (paOrdinals[uName] == uOrdinal)
960 {
961 pszName = PE_RVA2TYPE(pvBits, paRVANames[uName], const char *);
962 uNamePrev = uName;
963 break;
964 }
965 }
966 }
967
968 /*
969 * Get address.
970 */
971 uintptr_t uRVAExport = paAddress[uOrdinal];
972 RTUINTPTR Value;
973 if ( uRVAExport - (uintptr_t)pModPe->ExportDir.VirtualAddress
974 < pModPe->ExportDir.Size)
975 {
976 /* Resolve forwarder. */
977 AssertMsgFailed(("Forwarders are not supported!\n"));
978 continue;
979 }
980
981 /* Get plain export address */
982 Value = PE_RVA2TYPE(BaseAddress, uRVAExport, RTUINTPTR);
983
984 /*
985 * Call back.
986 */
987 int rc = pfnCallback(pMod, pszName, uOrdinal + pExpDir->Base, Value, pvUser);
988 if (rc)
989 return rc;
990 }
991 }
992
993 return VINF_SUCCESS;
994}
995
996
997/** @copydoc RTLDROPS::pfnEnumDbgInfo. */
998static DECLCALLBACK(int) rtldrPE_EnumDbgInfo(PRTLDRMODINTERNAL pMod, const void *pvBits,
999 PFNRTLDRENUMDBG pfnCallback, void *pvUser)
1000{
1001 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1002 int rc;
1003
1004 /*
1005 * Debug info directory empty?
1006 */
1007 if ( !pModPe->DebugDir.VirtualAddress
1008 || !pModPe->DebugDir.Size)
1009 return VINF_SUCCESS;
1010
1011 /*
1012 * Get the debug directory.
1013 */
1014 if (!pvBits)
1015 pvBits = pModPe->pvBits;
1016
1017 PCIMAGE_DEBUG_DIRECTORY paDbgDir;
1018 int rcRet = rtldrPEReadPartByRva(pModPe, pvBits, pModPe->DebugDir.VirtualAddress, pModPe->DebugDir.Size,
1019 (void const **)&paDbgDir);
1020 if (RT_FAILURE(rcRet))
1021 return rcRet;
1022
1023 /*
1024 * Enumerate the debug directory.
1025 */
1026 uint32_t const cEntries = pModPe->DebugDir.Size / sizeof(paDbgDir[0]);
1027 for (uint32_t i = 0; i < cEntries; i++)
1028 {
1029 if (paDbgDir[i].PointerToRawData < pModPe->offEndOfHdrs)
1030 continue;
1031 if (paDbgDir[i].SizeOfData < 4)
1032 continue;
1033
1034 void const *pvPart = NULL;
1035 char szPath[RTPATH_MAX];
1036 RTLDRDBGINFO DbgInfo;
1037 RT_ZERO(DbgInfo.u);
1038 DbgInfo.iDbgInfo = i;
1039 DbgInfo.offFile = paDbgDir[i].PointerToRawData;
1040 DbgInfo.LinkAddress = paDbgDir[i].AddressOfRawData < pModPe->cbImage
1041 && paDbgDir[i].AddressOfRawData >= pModPe->offEndOfHdrs
1042 ? paDbgDir[i].AddressOfRawData : NIL_RTLDRADDR;
1043 DbgInfo.cb = paDbgDir[i].SizeOfData;
1044 DbgInfo.pszExtFile = NULL;
1045
1046 rc = VINF_SUCCESS;
1047 switch (paDbgDir[i].Type)
1048 {
1049 case IMAGE_DEBUG_TYPE_CODEVIEW:
1050 DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW;
1051 DbgInfo.u.Cv.uMajorVer = paDbgDir[i].MajorVersion;
1052 DbgInfo.u.Cv.uMinorVer = paDbgDir[i].MinorVersion;
1053 DbgInfo.u.Cv.uTimestamp = paDbgDir[i].TimeDateStamp;
1054 if ( paDbgDir[i].SizeOfData < sizeof(szPath)
1055 && paDbgDir[i].SizeOfData > 16
1056 && ( DbgInfo.LinkAddress != NIL_RTLDRADDR
1057 || DbgInfo.offFile > 0)
1058 )
1059 {
1060 rc = rtldrPEReadPart(pModPe, pvBits, DbgInfo.offFile, DbgInfo.LinkAddress, paDbgDir[i].SizeOfData, &pvPart);
1061 if (RT_SUCCESS(rc))
1062 {
1063 PCCVPDB20INFO pCv20 = (PCCVPDB20INFO)pvPart;
1064 if ( pCv20->u32Magic == CVPDB20INFO_MAGIC
1065 && pCv20->offDbgInfo == 0
1066 && paDbgDir[i].SizeOfData > RT_UOFFSETOF(CVPDB20INFO, szPdbFilename) )
1067 {
1068 DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW_PDB20;
1069 DbgInfo.u.Pdb20.cbImage = pModPe->cbImage;
1070 DbgInfo.u.Pdb20.uTimestamp = pCv20->uTimestamp;
1071 DbgInfo.u.Pdb20.uAge = pCv20->uAge;
1072 DbgInfo.pszExtFile = (const char *)&pCv20->szPdbFilename[0];
1073 }
1074 else if ( pCv20->u32Magic == CVPDB70INFO_MAGIC
1075 && paDbgDir[i].SizeOfData > RT_UOFFSETOF(CVPDB70INFO, szPdbFilename) )
1076 {
1077 PCCVPDB70INFO pCv70 = (PCCVPDB70INFO)pCv20;
1078 DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW_PDB70;
1079 DbgInfo.u.Pdb70.cbImage = pModPe->cbImage;
1080 DbgInfo.u.Pdb70.Uuid = pCv70->PdbUuid;
1081 DbgInfo.u.Pdb70.uAge = pCv70->uAge;
1082 DbgInfo.pszExtFile = (const char *)&pCv70->szPdbFilename[0];
1083 }
1084 }
1085 else
1086 rcRet = rc;
1087 }
1088 break;
1089
1090 case IMAGE_DEBUG_TYPE_MISC:
1091 DbgInfo.enmType = RTLDRDBGINFOTYPE_UNKNOWN;
1092 if ( paDbgDir[i].SizeOfData < sizeof(szPath)
1093 && paDbgDir[i].SizeOfData > RT_UOFFSETOF(IMAGE_DEBUG_MISC, Data))
1094 {
1095 DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW_DBG;
1096 DbgInfo.u.Dbg.cbImage = pModPe->cbImage;
1097 if (DbgInfo.LinkAddress != NIL_RTLDRADDR)
1098 DbgInfo.u.Dbg.uTimestamp = paDbgDir[i].TimeDateStamp;
1099 else
1100 DbgInfo.u.Dbg.uTimestamp = pModPe->uTimestamp; /* NT4 SP1 ntfs.sys hack. Generic? */
1101
1102 rc = rtldrPEReadPart(pModPe, pvBits, DbgInfo.offFile, DbgInfo.LinkAddress, paDbgDir[i].SizeOfData, &pvPart);
1103 if (RT_SUCCESS(rc))
1104 {
1105 PCIMAGE_DEBUG_MISC pMisc = (PCIMAGE_DEBUG_MISC)pvPart;
1106 if ( pMisc->DataType == IMAGE_DEBUG_MISC_EXENAME
1107 && pMisc->Length == paDbgDir[i].SizeOfData)
1108 {
1109 if (!pMisc->Unicode)
1110 DbgInfo.pszExtFile = (const char *)&pMisc->Data[0];
1111 else
1112 {
1113 char *pszPath = szPath;
1114 rc = RTUtf16ToUtf8Ex((PCRTUTF16)&pMisc->Data[0],
1115 (pMisc->Length - RT_OFFSETOF(IMAGE_DEBUG_MISC, Data)) / sizeof(RTUTF16),
1116 &pszPath, sizeof(szPath), NULL);
1117 if (RT_SUCCESS(rc))
1118 DbgInfo.pszExtFile = szPath;
1119 else
1120 rcRet = rc; /* continue without a filename. */
1121 }
1122 }
1123 }
1124 else
1125 rcRet = rc; /* continue without a filename. */
1126 }
1127 break;
1128
1129 default:
1130 DbgInfo.enmType = RTLDRDBGINFOTYPE_UNKNOWN;
1131 break;
1132 }
1133
1134 /* Fix (hack) the file name encoding. We don't have Windows-1252 handy,
1135 so we'll be using Latin-1 as a reasonable approximation.
1136 (I don't think we know exactly which encoding this is anyway, as
1137 it's probably the current ANSI/Windows code page for the process
1138 generating the image anyways.) */
1139 if (DbgInfo.pszExtFile && DbgInfo.pszExtFile != szPath)
1140 {
1141 char *pszPath = szPath;
1142 rc = RTLatin1ToUtf8Ex(DbgInfo.pszExtFile,
1143 paDbgDir[i].SizeOfData - ((uintptr_t)DbgInfo.pszExtFile - (uintptr_t)pvBits),
1144 &pszPath, sizeof(szPath), NULL);
1145 if (RT_FAILURE(rc))
1146 {
1147 rcRet = rc;
1148 DbgInfo.pszExtFile = NULL;
1149 }
1150 }
1151 if (DbgInfo.pszExtFile)
1152 RTPathChangeToUnixSlashes(szPath, true /*fForce*/);
1153
1154 rc = pfnCallback(pMod, &DbgInfo, pvUser);
1155 rtldrPEFreePart(pModPe, pvBits, pvPart);
1156 if (rc != VINF_SUCCESS)
1157 {
1158 rcRet = rc;
1159 break;
1160 }
1161 }
1162
1163 rtldrPEFreePart(pModPe, pvBits, paDbgDir);
1164 return rcRet;
1165}
1166
1167
1168/** @copydoc RTLDROPS::pfnEnumSegments. */
1169static DECLCALLBACK(int) rtldrPE_EnumSegments(PRTLDRMODINTERNAL pMod, PFNRTLDRENUMSEGS pfnCallback, void *pvUser)
1170{
1171 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1172 RTLDRSEG SegInfo;
1173
1174 /*
1175 * The first section is a fake one covering the headers.
1176 */
1177 SegInfo.pchName = "NtHdrs";
1178 SegInfo.cchName = 6;
1179 SegInfo.SelFlat = 0;
1180 SegInfo.Sel16bit = 0;
1181 SegInfo.fFlags = 0;
1182 SegInfo.fProt = RTMEM_PROT_READ;
1183 SegInfo.Alignment = 1;
1184 SegInfo.LinkAddress = pModPe->uImageBase;
1185 SegInfo.RVA = 0;
1186 SegInfo.offFile = 0;
1187 SegInfo.cb = pModPe->cbHeaders;
1188 SegInfo.cbFile = pModPe->cbHeaders;
1189 SegInfo.cbMapped = pModPe->cbHeaders;
1190 if ((pModPe->paSections[0].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
1191 SegInfo.cbMapped = pModPe->paSections[0].VirtualAddress;
1192 int rc = pfnCallback(pMod, &SegInfo, pvUser);
1193
1194 /*
1195 * Then all the normal sections.
1196 */
1197 PCIMAGE_SECTION_HEADER pSh = pModPe->paSections;
1198 for (uint32_t i = 0; i < pModPe->cSections && rc == VINF_SUCCESS; i++, pSh++)
1199 {
1200 SegInfo.pchName = (const char *)&pSh->Name[0];
1201 SegInfo.cchName = (uint32_t)RTStrNLen(SegInfo.pchName, sizeof(pSh->Name));
1202 SegInfo.SelFlat = 0;
1203 SegInfo.Sel16bit = 0;
1204 SegInfo.fFlags = 0;
1205 SegInfo.fProt = RTMEM_PROT_NONE;
1206 if (pSh->Characteristics & IMAGE_SCN_MEM_READ)
1207 SegInfo.fProt |= RTMEM_PROT_READ;
1208 if (pSh->Characteristics & IMAGE_SCN_MEM_WRITE)
1209 SegInfo.fProt |= RTMEM_PROT_WRITE;
1210 if (pSh->Characteristics & IMAGE_SCN_MEM_EXECUTE)
1211 SegInfo.fProt |= RTMEM_PROT_EXEC;
1212 SegInfo.Alignment = (pSh->Characteristics & IMAGE_SCN_ALIGN_MASK) >> IMAGE_SCN_ALIGN_SHIFT;
1213 if (SegInfo.Alignment > 0)
1214 SegInfo.Alignment = RT_BIT_64(SegInfo.Alignment - 1);
1215 if (pSh->Characteristics & IMAGE_SCN_TYPE_NOLOAD)
1216 {
1217 SegInfo.LinkAddress = NIL_RTLDRADDR;
1218 SegInfo.RVA = NIL_RTLDRADDR;
1219 SegInfo.cbMapped = pSh->Misc.VirtualSize;
1220 }
1221 else
1222 {
1223 SegInfo.LinkAddress = pSh->VirtualAddress + pModPe->uImageBase ;
1224 SegInfo.RVA = pSh->VirtualAddress;
1225 SegInfo.cbMapped = RT_ALIGN(SegInfo.cb, SegInfo.Alignment);
1226 if (i + 1 < pModPe->cSections && !(pSh[1].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
1227 SegInfo.cbMapped = pSh[1].VirtualAddress - pSh->VirtualAddress;
1228 }
1229 SegInfo.cb = pSh->Misc.VirtualSize;
1230 if (pSh->PointerToRawData == 0 || pSh->SizeOfRawData == 0)
1231 {
1232 SegInfo.offFile = -1;
1233 SegInfo.cbFile = 0;
1234 }
1235 else
1236 {
1237 SegInfo.offFile = pSh->PointerToRawData;
1238 SegInfo.cbFile = pSh->SizeOfRawData;
1239 }
1240
1241 rc = pfnCallback(pMod, &SegInfo, pvUser);
1242 }
1243
1244 return rc;
1245}
1246
1247
1248/** @copydoc RTLDROPS::pfnLinkAddressToSegOffset. */
1249static DECLCALLBACK(int) rtldrPE_LinkAddressToSegOffset(PRTLDRMODINTERNAL pMod, RTLDRADDR LinkAddress,
1250 uint32_t *piSeg, PRTLDRADDR poffSeg)
1251{
1252 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1253
1254 LinkAddress -= pModPe->uImageBase;
1255
1256 /* Special header segment. */
1257 if (LinkAddress < pModPe->paSections[0].VirtualAddress)
1258 {
1259 *piSeg = 0;
1260 *poffSeg = LinkAddress;
1261 return VINF_SUCCESS;
1262 }
1263
1264 /*
1265 * Search the normal sections. (Could do this in binary fashion, they're
1266 * sorted, but too much bother right now.)
1267 */
1268 if (LinkAddress > pModPe->cbImage)
1269 return VERR_LDR_INVALID_LINK_ADDRESS;
1270 uint32_t i = pModPe->cSections;
1271 PCIMAGE_SECTION_HEADER paShs = pModPe->paSections;
1272 while (i-- > 0)
1273 if (!(paShs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
1274 {
1275 uint32_t uAddr = paShs[i].VirtualAddress;
1276 if (LinkAddress >= uAddr)
1277 {
1278 *poffSeg = LinkAddress - uAddr;
1279 *piSeg = i + 1;
1280 return VINF_SUCCESS;
1281 }
1282 }
1283
1284 return VERR_LDR_INVALID_LINK_ADDRESS;
1285}
1286
1287
1288/** @copydoc RTLDROPS::pfnLinkAddressToRva. */
1289static DECLCALLBACK(int) rtldrPE_LinkAddressToRva(PRTLDRMODINTERNAL pMod, RTLDRADDR LinkAddress, PRTLDRADDR pRva)
1290{
1291 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1292
1293 LinkAddress -= pModPe->uImageBase;
1294 if (LinkAddress > pModPe->cbImage)
1295 return VERR_LDR_INVALID_LINK_ADDRESS;
1296 *pRva = LinkAddress;
1297
1298 return VINF_SUCCESS;
1299}
1300
1301
1302/** @copydoc RTLDROPS::pfnSegOffsetToRva. */
1303static DECLCALLBACK(int) rtldrPE_SegOffsetToRva(PRTLDRMODINTERNAL pMod, uint32_t iSeg, RTLDRADDR offSeg,
1304 PRTLDRADDR pRva)
1305{
1306 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1307
1308 if (iSeg > pModPe->cSections)
1309 return VERR_LDR_INVALID_SEG_OFFSET;
1310
1311 /** @todo should validate offSeg here... too lazy right now. */
1312 if (iSeg == 0)
1313 *pRva = offSeg;
1314 else if (pModPe->paSections[iSeg].Characteristics & IMAGE_SCN_TYPE_NOLOAD)
1315 return VERR_LDR_INVALID_SEG_OFFSET;
1316 else
1317 *pRva = offSeg + pModPe->paSections[iSeg].VirtualAddress;
1318 return VINF_SUCCESS;
1319}
1320
1321
1322/** @copydoc RTLDROPS::pfnRvaToSegOffset. */
1323static DECLCALLBACK(int) rtldrPE_RvaToSegOffset(PRTLDRMODINTERNAL pMod, RTLDRADDR Rva,
1324 uint32_t *piSeg, PRTLDRADDR poffSeg)
1325{
1326 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1327 int rc = rtldrPE_LinkAddressToSegOffset(pMod, Rva + pModPe->uImageBase, piSeg, poffSeg);
1328 if (RT_FAILURE(rc))
1329 rc = VERR_LDR_INVALID_RVA;
1330 return rc;
1331}
1332
1333
1334/** @copydoc RTLDROPS::pfnDone */
1335static DECLCALLBACK(int) rtldrPEDone(PRTLDRMODINTERNAL pMod)
1336{
1337 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1338 if (pModPe->pvBits)
1339 {
1340 RTMemFree(pModPe->pvBits);
1341 pModPe->pvBits = NULL;
1342 }
1343 return VINF_SUCCESS;
1344}
1345
1346/** @copydoc RTLDROPS::pfnClose */
1347static DECLCALLBACK(int) rtldrPEClose(PRTLDRMODINTERNAL pMod)
1348{
1349 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1350 if (pModPe->paSections)
1351 {
1352 RTMemFree(pModPe->paSections);
1353 pModPe->paSections = NULL;
1354 }
1355 if (pModPe->pvBits)
1356 {
1357 RTMemFree(pModPe->pvBits);
1358 pModPe->pvBits = NULL;
1359 }
1360 if (pModPe->Core.pReader)
1361 {
1362 int rc = pModPe->Core.pReader->pfnDestroy(pModPe->Core.pReader);
1363 AssertRC(rc);
1364 pModPe->Core.pReader = NULL;
1365 }
1366 return VINF_SUCCESS;
1367}
1368
1369
1370/**
1371 * Operations for a 32-bit PE module.
1372 */
1373static const RTLDROPSPE s_rtldrPE32Ops =
1374{
1375 {
1376 "pe32",
1377 rtldrPEClose,
1378 NULL,
1379 rtldrPEDone,
1380 rtldrPEEnumSymbols,
1381 /* ext */
1382 rtldrPEGetImageSize,
1383 rtldrPEGetBits,
1384 rtldrPERelocate,
1385 rtldrPEGetSymbolEx,
1386 rtldrPE_EnumDbgInfo,
1387 rtldrPE_EnumSegments,
1388 rtldrPE_LinkAddressToSegOffset,
1389 rtldrPE_LinkAddressToRva,
1390 rtldrPE_SegOffsetToRva,
1391 rtldrPE_RvaToSegOffset,
1392 42
1393 },
1394 rtldrPEResolveImports32,
1395 42
1396};
1397
1398
1399/**
1400 * Operations for a 64-bit PE module.
1401 */
1402static const RTLDROPSPE s_rtldrPE64Ops =
1403{
1404 {
1405 "pe64",
1406 rtldrPEClose,
1407 NULL,
1408 rtldrPEDone,
1409 rtldrPEEnumSymbols,
1410 /* ext */
1411 rtldrPEGetImageSize,
1412 rtldrPEGetBits,
1413 rtldrPERelocate,
1414 rtldrPEGetSymbolEx,
1415 rtldrPE_EnumDbgInfo,
1416 rtldrPE_EnumSegments,
1417 rtldrPE_LinkAddressToSegOffset,
1418 rtldrPE_LinkAddressToRva,
1419 rtldrPE_SegOffsetToRva,
1420 rtldrPE_RvaToSegOffset,
1421 42
1422 },
1423 rtldrPEResolveImports64,
1424 42
1425};
1426
1427
1428/**
1429 * Converts the optional header from 32 bit to 64 bit.
1430 * This is a rather simple task, if you start from the right end.
1431 *
1432 * @param pOptHdr On input this is a PIMAGE_OPTIONAL_HEADER32.
1433 * On output this will be a PIMAGE_OPTIONAL_HEADER64.
1434 */
1435static void rtldrPEConvert32BitOptionalHeaderTo64Bit(PIMAGE_OPTIONAL_HEADER64 pOptHdr)
1436{
1437 /*
1438 * volatile everywhere! Trying to prevent the compiler being a smarta$$ and reorder stuff.
1439 */
1440 IMAGE_OPTIONAL_HEADER32 volatile *pOptHdr32 = (IMAGE_OPTIONAL_HEADER32 volatile *)pOptHdr;
1441 IMAGE_OPTIONAL_HEADER64 volatile *pOptHdr64 = pOptHdr;
1442
1443 /* from LoaderFlags and out the difference is 4 * 32-bits. */
1444 Assert(RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, LoaderFlags) + 16 == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, LoaderFlags));
1445 Assert( RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]) + 16
1446 == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]));
1447 uint32_t volatile *pu32Dst = (uint32_t *)&pOptHdr64->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1;
1448 const uint32_t volatile *pu32Src = (uint32_t *)&pOptHdr32->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1;
1449 const uint32_t volatile *pu32SrcLast = (uint32_t *)&pOptHdr32->LoaderFlags;
1450 while (pu32Src >= pu32SrcLast)
1451 *pu32Dst-- = *pu32Src--;
1452
1453 /* the previous 4 fields are 32/64 and needs special attention. */
1454 pOptHdr64->SizeOfHeapCommit = pOptHdr32->SizeOfHeapCommit;
1455 pOptHdr64->SizeOfHeapReserve = pOptHdr32->SizeOfHeapReserve;
1456 pOptHdr64->SizeOfStackCommit = pOptHdr32->SizeOfStackCommit;
1457 uint32_t u32SizeOfStackReserve = pOptHdr32->SizeOfStackReserve;
1458 pOptHdr64->SizeOfStackReserve = u32SizeOfStackReserve;
1459
1460 /* The rest matches except for BaseOfData which has been merged into ImageBase in the 64-bit version..
1461 * Thus, ImageBase needs some special treatment. It will probably work fine assigning one to the
1462 * other since this is all declared volatile, but taking now chances, we'll use a temp variable.
1463 */
1464 Assert(RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, SizeOfStackReserve) == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, SizeOfStackReserve));
1465 Assert(RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, BaseOfData) == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, ImageBase));
1466 Assert(RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, SectionAlignment) == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, SectionAlignment));
1467 uint32_t u32ImageBase = pOptHdr32->ImageBase;
1468 pOptHdr64->ImageBase = u32ImageBase;
1469}
1470
1471
1472/**
1473 * Converts the load config directory from 32 bit to 64 bit.
1474 * This is a rather simple task, if you start from the right end.
1475 *
1476 * @param pLoadCfg On input this is a PIMAGE_LOAD_CONFIG_DIRECTORY32.
1477 * On output this will be a PIMAGE_LOAD_CONFIG_DIRECTORY64.
1478 */
1479static void rtldrPEConvert32BitLoadConfigTo64Bit(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg)
1480{
1481 /*
1482 * volatile everywhere! Trying to prevent the compiler being a smarta$$ and reorder stuff.
1483 */
1484 IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *pLoadCfg32 = (IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *)pLoadCfg;
1485 IMAGE_LOAD_CONFIG_DIRECTORY64 volatile *pLoadCfg64 = pLoadCfg;
1486
1487 pLoadCfg64->SEHandlerCount = pLoadCfg32->SEHandlerCount;
1488 pLoadCfg64->SEHandlerTable = pLoadCfg32->SEHandlerTable;
1489 pLoadCfg64->SecurityCookie = pLoadCfg32->SecurityCookie;
1490 pLoadCfg64->EditList = pLoadCfg32->EditList;
1491 pLoadCfg64->Reserved1 = pLoadCfg32->Reserved1;
1492 pLoadCfg64->CSDVersion = pLoadCfg32->CSDVersion;
1493 pLoadCfg64->ProcessHeapFlags = pLoadCfg32->ProcessHeapFlags; /* switched place with ProcessAffinityMask, but we're more than 16 byte off by now so it doesn't matter. */
1494 pLoadCfg64->ProcessAffinityMask = pLoadCfg32->ProcessAffinityMask;
1495 pLoadCfg64->VirtualMemoryThreshold = pLoadCfg32->VirtualMemoryThreshold;
1496 pLoadCfg64->MaximumAllocationSize = pLoadCfg32->MaximumAllocationSize;
1497 pLoadCfg64->LockPrefixTable = pLoadCfg32->LockPrefixTable;
1498 pLoadCfg64->DeCommitTotalFreeThreshold = pLoadCfg32->DeCommitTotalFreeThreshold;
1499 uint32_t u32DeCommitFreeBlockThreshold = pLoadCfg32->DeCommitFreeBlockThreshold;
1500 pLoadCfg64->DeCommitFreeBlockThreshold = u32DeCommitFreeBlockThreshold;
1501 /* the rest is equal. */
1502 Assert( RT_OFFSETOF(IMAGE_LOAD_CONFIG_DIRECTORY32, DeCommitFreeBlockThreshold)
1503 == RT_OFFSETOF(IMAGE_LOAD_CONFIG_DIRECTORY64, DeCommitFreeBlockThreshold));
1504}
1505
1506
1507/**
1508 * Validates the file header.
1509 *
1510 * @returns iprt status code.
1511 * @param pFileHdr Pointer to the file header that needs validating.
1512 * @param fFlags Valid RTLDR_O_XXX combination.
1513 * @param pszLogName The log name to prefix the errors with.
1514 * @param penmArch Where to store the CPU architecture.
1515 */
1516static int rtldrPEValidateFileHeader(PIMAGE_FILE_HEADER pFileHdr, uint32_t fFlags, const char *pszLogName, PRTLDRARCH penmArch)
1517{
1518 size_t cbOptionalHeader;
1519 switch (pFileHdr->Machine)
1520 {
1521 case IMAGE_FILE_MACHINE_I386:
1522 cbOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER32);
1523 *penmArch = RTLDRARCH_X86_32;
1524 break;
1525 case IMAGE_FILE_MACHINE_AMD64:
1526 cbOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER64);
1527 *penmArch = RTLDRARCH_AMD64;
1528 break;
1529
1530 default:
1531 Log(("rtldrPEOpen: %s: Unsupported Machine=%#x\n",
1532 pszLogName, pFileHdr->Machine));
1533 *penmArch = RTLDRARCH_INVALID;
1534 return VERR_BAD_EXE_FORMAT;
1535 }
1536 if (pFileHdr->SizeOfOptionalHeader != cbOptionalHeader)
1537 {
1538 Log(("rtldrPEOpen: %s: SizeOfOptionalHeader=%#x expected %#x\n",
1539 pszLogName, pFileHdr->SizeOfOptionalHeader, cbOptionalHeader));
1540 return VERR_BAD_EXE_FORMAT;
1541 }
1542 /* This restriction needs to be implemented elsewhere. */
1543 if ( (pFileHdr->Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
1544 && !(fFlags & RTLDR_O_FOR_DEBUG))
1545 {
1546 Log(("rtldrPEOpen: %s: IMAGE_FILE_RELOCS_STRIPPED\n", pszLogName));
1547 return VERR_BAD_EXE_FORMAT;
1548 }
1549 if (pFileHdr->NumberOfSections > 42)
1550 {
1551 Log(("rtldrPEOpen: %s: NumberOfSections=%d - our limit is 42, please raise it if the binary makes sense.(!!!)\n",
1552 pszLogName, pFileHdr->NumberOfSections));
1553 return VERR_BAD_EXE_FORMAT;
1554 }
1555 if (pFileHdr->NumberOfSections < 1)
1556 {
1557 Log(("rtldrPEOpen: %s: NumberOfSections=%d - we can't have an image without sections (!!!)\n",
1558 pszLogName, pFileHdr->NumberOfSections));
1559 return VERR_BAD_EXE_FORMAT;
1560 }
1561 return VINF_SUCCESS;
1562}
1563
1564
1565/**
1566 * Validates the optional header (64/32-bit)
1567 *
1568 * @returns iprt status code.
1569 * @param pOptHdr Pointer to the optional header which needs validation.
1570 * @param pszLogName The log name to prefix the errors with.
1571 * @param offNtHdrs The offset of the NT headers from the start of the file.
1572 * @param pFileHdr Pointer to the file header (valid).
1573 * @param cbRawImage The raw image size.
1574 * @param fFlags Loader flags.
1575 */
1576static int rtldrPEValidateOptionalHeader(const IMAGE_OPTIONAL_HEADER64 *pOptHdr, const char *pszLogName, RTFOFF offNtHdrs,
1577 const IMAGE_FILE_HEADER *pFileHdr, RTFOFF cbRawImage, uint32_t fFlags)
1578{
1579 const uint16_t CorrectMagic = pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
1580 ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC;
1581 if (pOptHdr->Magic != CorrectMagic)
1582 {
1583 Log(("rtldrPEOpen: %s: Magic=%#x - expected %#x!!!\n", pszLogName, pOptHdr->Magic, CorrectMagic));
1584 return VERR_BAD_EXE_FORMAT;
1585 }
1586 const uint32_t cbImage = pOptHdr->SizeOfImage;
1587 if (cbImage > _1G)
1588 {
1589 Log(("rtldrPEOpen: %s: SizeOfImage=%#x - Our limit is 1GB (%#x)!!!\n", pszLogName, cbImage, _1G));
1590 return VERR_BAD_EXE_FORMAT;
1591 }
1592 const uint32_t cbMinImageSize = pFileHdr->SizeOfOptionalHeader + sizeof(*pFileHdr) + 4 + (uint32_t)offNtHdrs;
1593 if (cbImage < cbMinImageSize)
1594 {
1595 Log(("rtldrPEOpen: %s: SizeOfImage=%#x to small, minimum %#x!!!\n", pszLogName, cbImage, cbMinImageSize));
1596 return VERR_BAD_EXE_FORMAT;
1597 }
1598 if (pOptHdr->AddressOfEntryPoint >= cbImage)
1599 {
1600 Log(("rtldrPEOpen: %s: AddressOfEntryPoint=%#x - beyond image size (%#x)!!!\n",
1601 pszLogName, pOptHdr->AddressOfEntryPoint, cbImage));
1602 return VERR_BAD_EXE_FORMAT;
1603 }
1604 if (pOptHdr->BaseOfCode >= cbImage)
1605 {
1606 Log(("rtldrPEOpen: %s: BaseOfCode=%#x - beyond image size (%#x)!!!\n",
1607 pszLogName, pOptHdr->BaseOfCode, cbImage));
1608 return VERR_BAD_EXE_FORMAT;
1609 }
1610#if 0/* only in 32-bit header */
1611 if (pOptHdr->BaseOfData >= cbImage)
1612 {
1613 Log(("rtldrPEOpen: %s: BaseOfData=%#x - beyond image size (%#x)!!!\n",
1614 pszLogName, pOptHdr->BaseOfData, cbImage));
1615 return VERR_BAD_EXE_FORMAT;
1616 }
1617#endif
1618 if (pOptHdr->SizeOfHeaders >= cbImage)
1619 {
1620 Log(("rtldrPEOpen: %s: SizeOfHeaders=%#x - beyond image size (%#x)!!!\n",
1621 pszLogName, pOptHdr->SizeOfHeaders, cbImage));
1622 return VERR_BAD_EXE_FORMAT;
1623 }
1624 /* don't know how to do the checksum, so ignore it. */
1625 if (pOptHdr->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN)
1626 {
1627 Log(("rtldrPEOpen: %s: Subsystem=%#x (unknown)!!!\n", pszLogName, pOptHdr->Subsystem));
1628 return VERR_BAD_EXE_FORMAT;
1629 }
1630 if (pOptHdr->SizeOfHeaders < cbMinImageSize + pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER))
1631 {
1632 Log(("rtldrPEOpen: %s: SizeOfHeaders=%#x - cbMinImageSize %#x + sections %#x = %#llx!!!\n",
1633 pszLogName, pOptHdr->SizeOfHeaders,
1634 cbImage, cbMinImageSize, pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER),
1635 cbMinImageSize + pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER)));
1636 return VERR_BAD_EXE_FORMAT;
1637 }
1638 if (pOptHdr->SizeOfStackReserve < pOptHdr->SizeOfStackCommit)
1639 {
1640 Log(("rtldrPEOpen: %s: SizeOfStackReserve %#x < SizeOfStackCommit %#x!!!\n",
1641 pszLogName, pOptHdr->SizeOfStackReserve, pOptHdr->SizeOfStackCommit));
1642 return VERR_BAD_EXE_FORMAT;
1643 }
1644 if (pOptHdr->SizeOfHeapReserve < pOptHdr->SizeOfHeapCommit)
1645 {
1646 Log(("rtldrPEOpen: %s: SizeOfStackReserve %#x < SizeOfStackCommit %#x!!!\n",
1647 pszLogName, pOptHdr->SizeOfStackReserve, pOptHdr->SizeOfStackCommit));
1648 return VERR_BAD_EXE_FORMAT;
1649 }
1650
1651 /* DataDirectory */
1652 if (pOptHdr->NumberOfRvaAndSizes != RT_ELEMENTS(pOptHdr->DataDirectory))
1653 {
1654 Log(("rtldrPEOpen: %s: NumberOfRvaAndSizes=%d!!!\n", pszLogName, pOptHdr->NumberOfRvaAndSizes));
1655 return VERR_BAD_EXE_FORMAT;
1656 }
1657 for (unsigned i = 0; i < RT_ELEMENTS(pOptHdr->DataDirectory); i++)
1658 {
1659 IMAGE_DATA_DIRECTORY const *pDir = &pOptHdr->DataDirectory[i];
1660 if (!pDir->Size)
1661 continue;
1662 size_t cb = cbImage;
1663 switch (i)
1664 {
1665 case IMAGE_DIRECTORY_ENTRY_EXPORT: // 0
1666 case IMAGE_DIRECTORY_ENTRY_IMPORT: // 1
1667 case IMAGE_DIRECTORY_ENTRY_RESOURCE: // 2
1668 case IMAGE_DIRECTORY_ENTRY_EXCEPTION: // 3
1669 case IMAGE_DIRECTORY_ENTRY_BASERELOC: // 5
1670 case IMAGE_DIRECTORY_ENTRY_DEBUG: // 6
1671 case IMAGE_DIRECTORY_ENTRY_COPYRIGHT: // 7
1672 case IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT: // 11
1673 case IMAGE_DIRECTORY_ENTRY_IAT: // 12 /* Import Address Table */
1674 break;
1675 case IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG: // 10 - need to check for lock prefixes.
1676 /* Delay inspection after section table is validated. */
1677 break;
1678
1679 case IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT: // 13
1680 Log(("rtldrPEOpen: %s: dir no. %d (DELAY_IMPORT) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1681 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1682 return VERR_LDRPE_DELAY_IMPORT;
1683
1684 case IMAGE_DIRECTORY_ENTRY_SECURITY: // 4
1685 /* The VirtualAddress is a PointerToRawData. */
1686 cb = (size_t)cbRawImage; Assert((RTFOFF)cb == cbRawImage);
1687 Log(("rtldrPEOpen: %s: dir no. %d (SECURITY) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1688 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1689 if (pDir->Size < sizeof(WIN_CERTIFICATE))
1690 {
1691 Log(("rtldrPEOpen: %s: Security directory is too small: %#x bytes\n", pszLogName, i, pDir->Size));
1692 return VERR_LDRPE_CERT_MALFORMED;
1693 }
1694 if (pDir->Size >= _1M)
1695 {
1696 Log(("rtldrPEOpen: %s: Security directory is too large: %#x bytes\n", pszLogName, i, pDir->Size));
1697 return VERR_LDRPE_CERT_MALFORMED;
1698 }
1699 if (pDir->VirtualAddress & 7)
1700 {
1701 Log(("rtldrPEOpen: %s: Security directory is misaligned: %#x\n", pszLogName, i, pDir->VirtualAddress));
1702 return VERR_LDRPE_CERT_MALFORMED;
1703 }
1704 break;
1705
1706 case IMAGE_DIRECTORY_ENTRY_GLOBALPTR: // 8 /* (MIPS GP) */
1707 Log(("rtldrPEOpen: %s: dir no. %d (GLOBALPTR) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1708 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1709 return VERR_LDRPE_GLOBALPTR;
1710
1711 case IMAGE_DIRECTORY_ENTRY_TLS: // 9
1712 Log(("rtldrPEOpen: %s: dir no. %d (TLS) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1713 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1714 return VERR_LDRPE_TLS;
1715
1716 case IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR:// 14
1717 Log(("rtldrPEOpen: %s: dir no. %d (COM_DESCRIPTOR) VirtualAddress=%#x Size=%#x is not supported!!!\n",
1718 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1719 return VERR_LDRPE_COM_DESCRIPTOR;
1720
1721 default:
1722 Log(("rtldrPEOpen: %s: dir no. %d VirtualAddress=%#x Size=%#x is not supported!!!\n",
1723 pszLogName, i, pDir->VirtualAddress, pDir->Size));
1724 return VERR_BAD_EXE_FORMAT;
1725 }
1726 if (pDir->VirtualAddress >= cb)
1727 {
1728 Log(("rtldrPEOpen: %s: dir no. %d VirtualAddress=%#x is invalid (limit %#x)!!!\n",
1729 pszLogName, i, pDir->VirtualAddress, cb));
1730 return VERR_BAD_EXE_FORMAT;
1731 }
1732 if (pDir->Size > cb - pDir->VirtualAddress)
1733 {
1734 Log(("rtldrPEOpen: %s: dir no. %d Size=%#x is invalid (rva=%#x, limit=%#x)!!!\n",
1735 pszLogName, i, pDir->Size, pDir->VirtualAddress, cb));
1736 return VERR_BAD_EXE_FORMAT;
1737 }
1738 }
1739 return VINF_SUCCESS;
1740}
1741
1742
1743/**
1744 * Validates the section headers.
1745 *
1746 * @returns iprt status code.
1747 * @param paSections Pointer to the array of sections that is to be validated.
1748 * @param cSections Number of sections in that array.
1749 * @param pszLogName The log name to prefix the errors with.
1750 * @param pOptHdr Pointer to the optional header (valid).
1751 * @param cbRawImage The raw image size.
1752 */
1753int rtldrPEValidateSectionHeaders(const IMAGE_SECTION_HEADER *paSections, unsigned cSections, const char *pszLogName,
1754 const IMAGE_OPTIONAL_HEADER64 *pOptHdr, RTFOFF cbRawImage)
1755{
1756 const uint32_t cbImage = pOptHdr->SizeOfImage;
1757 const IMAGE_SECTION_HEADER *pSH = &paSections[0];
1758 uint32_t uRvaPrev = pOptHdr->SizeOfHeaders;
1759 Log3(("RTLdrPE: Section Headers:\n"));
1760 for (unsigned cSHdrsLeft = cSections; cSHdrsLeft > 0; cSHdrsLeft--, pSH++)
1761 {
1762 const unsigned iSH = pSH - &paSections[0]; NOREF(iSH);
1763 Log3(("RTLdrPE: #%d '%-8.8s' Characteristics: %08RX32\n"
1764 "RTLdrPE: VirtAddr: %08RX32 VirtSize: %08RX32\n"
1765 "RTLdrPE: FileOff: %08RX32 FileSize: %08RX32\n"
1766 "RTLdrPE: RelocOff: %08RX32 #Relocs: %08RX32\n"
1767 "RTLdrPE: LineOff: %08RX32 #Lines: %08RX32\n",
1768 iSH, pSH->Name, pSH->Characteristics,
1769 pSH->VirtualAddress, pSH->Misc.VirtualSize,
1770 pSH->PointerToRawData, pSH->SizeOfRawData,
1771 pSH->PointerToRelocations, pSH->NumberOfRelocations,
1772 pSH->PointerToLinenumbers, pSH->NumberOfLinenumbers));
1773 if (pSH->Characteristics & (IMAGE_SCN_MEM_16BIT | IMAGE_SCN_MEM_FARDATA | IMAGE_SCN_MEM_PURGEABLE | IMAGE_SCN_MEM_PRELOAD))
1774 {
1775 Log(("rtldrPEOpen: %s: Unsupported section flag(s) %#x section #%d '%.*s'!!!\n",
1776 pszLogName, pSH->Characteristics, iSH, sizeof(pSH->Name), pSH->Name));
1777 return VERR_BAD_EXE_FORMAT;
1778 }
1779
1780 if ( pSH->Misc.VirtualSize
1781 && !(pSH->Characteristics & IMAGE_SCN_TYPE_NOLOAD)) /* binutils uses this for '.stab' even if it's reserved/obsoleted by MS. */
1782 {
1783 if (pSH->VirtualAddress < uRvaPrev)
1784 {
1785 Log(("rtldrPEOpen: %s: Overlaps previous section or sections aren't in ascending order, VirtualAddress=%#x uRvaPrev=%#x - section #%d '%.*s'!!!\n",
1786 pszLogName, pSH->VirtualAddress, uRvaPrev, iSH, sizeof(pSH->Name), pSH->Name));
1787 return VERR_BAD_EXE_FORMAT;
1788 }
1789 if (pSH->VirtualAddress > cbImage)
1790 {
1791 Log(("rtldrPEOpen: %s: VirtualAddress=%#x - beyond image size (%#x) - section #%d '%.*s'!!!\n",
1792 pszLogName, pSH->VirtualAddress, cbImage, iSH, sizeof(pSH->Name), pSH->Name));
1793 return VERR_BAD_EXE_FORMAT;
1794 }
1795
1796 if (pSH->VirtualAddress & (pOptHdr->SectionAlignment - 1)) //ASSUMES power of 2 alignment.
1797 {
1798 Log(("rtldrPEOpen: %s: VirtualAddress=%#x misaligned (%#x) - section #%d '%.*s'!!!\n",
1799 pszLogName, pSH->VirtualAddress, pOptHdr->SectionAlignment, iSH, sizeof(pSH->Name), pSH->Name));
1800 return VERR_BAD_EXE_FORMAT;
1801 }
1802
1803#ifdef PE_FILE_OFFSET_EQUALS_RVA
1804 /* Our loader code assume rva matches the file offset. */
1805 if ( pSH->SizeOfRawData
1806 && pSH->PointerToRawData != pSH->VirtualAddress)
1807 {
1808 Log(("rtldrPEOpen: %s: ASSUMPTION FAILED: file offset %#x != RVA %#x - section #%d '%.*s'!!!\n",
1809 pszLogName, pSH->PointerToRawData, pSH->VirtualAddress, iSH, sizeof(pSH->Name), pSH->Name));
1810 return VERR_BAD_EXE_FORMAT;
1811 }
1812#endif
1813 }
1814
1815 ///@todo only if SizeOfRawData > 0 ?
1816 if ( pSH->PointerToRawData > cbRawImage /// @todo pSH->PointerToRawData >= cbRawImage ?
1817 || pSH->SizeOfRawData > cbRawImage
1818 || pSH->PointerToRawData + pSH->SizeOfRawData > cbRawImage)
1819 {
1820 Log(("rtldrPEOpen: %s: PointerToRawData=%#x SizeOfRawData=%#x - beyond end of file (%#x) - section #%d '%.*s'!!!\n",
1821 pszLogName, pSH->PointerToRawData, pSH->SizeOfRawData, cbRawImage,
1822 iSH, sizeof(pSH->Name), pSH->Name));
1823 return VERR_BAD_EXE_FORMAT;
1824 }
1825
1826 if (pSH->PointerToRawData & (pOptHdr->FileAlignment - 1)) //ASSUMES power of 2 alignment.
1827 {
1828 Log(("rtldrPEOpen: %s: PointerToRawData=%#x misaligned (%#x) - section #%d '%.*s'!!!\n",
1829 pszLogName, pSH->PointerToRawData, pOptHdr->FileAlignment, iSH, sizeof(pSH->Name), pSH->Name));
1830 return VERR_BAD_EXE_FORMAT;
1831 }
1832
1833 /* ignore the relocations and linenumbers. */
1834
1835 uRvaPrev = pSH->VirtualAddress + pSH->Misc.VirtualSize;
1836 }
1837
1838 /** @todo r=bird: more sanity checks! */
1839 return VINF_SUCCESS;
1840}
1841
1842
1843/**
1844 * Reads image data by RVA using the section headers.
1845 *
1846 * @returns iprt status code.
1847 * @param pModPe The PE module instance.
1848 * @param pvBuf Where to store the bits.
1849 * @param cb Number of bytes to tread.
1850 * @param RVA Where to read from.
1851 */
1852static int rtldrPEReadRVA(PRTLDRMODPE pModPe, void *pvBuf, uint32_t cb, uint32_t RVA)
1853{
1854 const IMAGE_SECTION_HEADER *pSH = pModPe->paSections;
1855 PRTLDRREADER pReader = pModPe->Core.pReader;
1856 uint32_t cbRead;
1857 int rc;
1858
1859 /*
1860 * Is it the headers, i.e. prior to the first section.
1861 */
1862 if (RVA < pModPe->cbHeaders)
1863 {
1864 cbRead = RT_MIN(pModPe->cbHeaders - RVA, cb);
1865 rc = pReader->pfnRead(pReader, pvBuf, cbRead, RVA);
1866 if ( cbRead == cb
1867 || RT_FAILURE(rc))
1868 return rc;
1869 cb -= cbRead;
1870 RVA += cbRead;
1871 pvBuf = (uint8_t *)pvBuf + cbRead;
1872 }
1873
1874 /* In the zero space between headers and the first section? */
1875 if (RVA < pSH->VirtualAddress)
1876 {
1877 cbRead = RT_MIN(pSH->VirtualAddress - RVA, cb);
1878 memset(pvBuf, 0, cbRead);
1879 if (cbRead == cb)
1880 return VINF_SUCCESS;
1881 cb -= cbRead;
1882 RVA += cbRead;
1883 pvBuf = (uint8_t *)pvBuf + cbRead;
1884 }
1885
1886 /*
1887 * Iterate the sections.
1888 */
1889 for (unsigned cLeft = pModPe->cSections;
1890 cLeft > 0;
1891 cLeft--, pSH++)
1892 {
1893 uint32_t off = RVA - pSH->VirtualAddress;
1894 if (off < pSH->Misc.VirtualSize)
1895 {
1896 cbRead = RT_MIN(pSH->Misc.VirtualSize - off, cb);
1897 rc = pReader->pfnRead(pReader, pvBuf, cbRead, pSH->PointerToRawData + off);
1898 if ( cbRead == cb
1899 || RT_FAILURE(rc))
1900 return rc;
1901 cb -= cbRead;
1902 RVA += cbRead;
1903 pvBuf = (uint8_t *)pvBuf + cbRead;
1904 }
1905 uint32_t RVANext = cLeft ? pSH[1].VirtualAddress : pModPe->cbImage;
1906 if (RVA < RVANext)
1907 {
1908 cbRead = RT_MIN(RVANext - RVA, cb);
1909 memset(pvBuf, 0, cbRead);
1910 if (cbRead == cb)
1911 return VINF_SUCCESS;
1912 cb -= cbRead;
1913 RVA += cbRead;
1914 pvBuf = (uint8_t *)pvBuf + cbRead;
1915 }
1916 }
1917
1918 AssertFailed();
1919 return VERR_INTERNAL_ERROR;
1920}
1921
1922
1923/**
1924 * Validates the data of some selected data directories entries.
1925 *
1926 * This requires a valid section table and thus has to wait
1927 * till after we've read and validated it.
1928 *
1929 * @returns iprt status code.
1930 * @param pModPe The PE module instance.
1931 * @param pOptHdr Pointer to the optional header (valid).
1932 */
1933int rtldrPEValidateDirectories(PRTLDRMODPE pModPe, const IMAGE_OPTIONAL_HEADER64 *pOptHdr)
1934{
1935 const char *pszLogName = pModPe->Core.pReader->pfnLogName(pModPe->Core.pReader); NOREF(pszLogName);
1936 union /* combine stuff we're reading to help reduce stack usage. */
1937 {
1938 IMAGE_LOAD_CONFIG_DIRECTORY64 Cfg64;
1939 } u;
1940
1941 /*
1942 * The load config entry may include lock prefix tables and whatnot which we don't implement.
1943 * It does also include a lot of stuff which we can ignore, so we'll have to inspect the
1944 * actual data before we can make up our mind about it all.
1945 */
1946 IMAGE_DATA_DIRECTORY Dir = pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG];
1947 if (Dir.Size)
1948 {
1949 const size_t cbExpect = pOptHdr->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC
1950 ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32)
1951 : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64);
1952 if ( Dir.Size != cbExpect
1953 && ( cbExpect == sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32)
1954 && Dir.Size != (uint32_t)RT_OFFSETOF(IMAGE_LOAD_CONFIG_DIRECTORY32, SEHandlerTable))
1955 )
1956 {
1957 Log(("rtldrPEOpen: %s: load cfg dir: unexpected dir size of %d bytes, expected %d.\n",
1958 pszLogName, Dir.Size, cbExpect));
1959 return VERR_LDRPE_LOAD_CONFIG_SIZE;
1960 }
1961
1962 /*
1963 * Read and convert to 64-bit.
1964 */
1965 memset(&u.Cfg64, 0, sizeof(u.Cfg64));
1966 int rc = rtldrPEReadRVA(pModPe, &u.Cfg64, Dir.Size, Dir.VirtualAddress);
1967 if (RT_FAILURE(rc))
1968 return rc;
1969 rtldrPEConvert32BitLoadConfigTo64Bit(&u.Cfg64);
1970
1971 if (u.Cfg64.Size != cbExpect)
1972 {
1973 Log(("rtldrPEOpen: %s: load cfg dir: unexpected header size of %d bytes, expected %d.\n",
1974 pszLogName, u.Cfg64.Size, cbExpect));
1975 return VERR_LDRPE_LOAD_CONFIG_SIZE;
1976 }
1977 if (u.Cfg64.LockPrefixTable)
1978 {
1979 Log(("rtldrPEOpen: %s: load cfg dir: lock prefix table at %RX64. We don't support lock prefix tables!\n",
1980 pszLogName, u.Cfg64.LockPrefixTable));
1981 return VERR_LDRPE_LOCK_PREFIX_TABLE;
1982 }
1983#if 0/* this seems to be safe to ignore. */
1984 if ( u.Cfg64.SEHandlerTable
1985 || u.Cfg64.SEHandlerCount)
1986 {
1987 Log(("rtldrPEOpen: %s: load cfg dir: SEHandlerTable=%RX64 and SEHandlerCount=%RX64 are unsupported!\n",
1988 pszLogName, u.Cfg64.SEHandlerTable, u.Cfg64.SEHandlerCount));
1989 return VERR_BAD_EXE_FORMAT;
1990 }
1991#endif
1992 if (u.Cfg64.EditList)
1993 {
1994 Log(("rtldrPEOpen: %s: load cfg dir: EditList=%RX64 is unsupported!\n",
1995 pszLogName, u.Cfg64.EditList));
1996 return VERR_BAD_EXE_FORMAT;
1997 }
1998 }
1999
2000 /*
2001 * If the image is signed, take a look at the signature.
2002 */
2003 Dir = pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
2004 if (Dir.Size)
2005 {
2006 PWIN_CERTIFICATE pFirst = (PWIN_CERTIFICATE)RTMemTmpAlloc(Dir.Size);
2007 if (!pFirst)
2008 return VERR_NO_TMP_MEMORY;
2009 int rc = pModPe->Core.pReader->pfnRead(pModPe->Core.pReader, pFirst, Dir.Size, Dir.VirtualAddress);
2010 if (RT_SUCCESS(rc))
2011 {
2012 uint32_t off = 0;
2013 PWIN_CERTIFICATE pCur = pFirst;
2014 do
2015 {
2016 /* validate the members. */
2017 uint32_t const cbCur = RT_ALIGN_32(pCur->dwLength, 8);
2018 if ( cbCur < sizeof(WIN_CERTIFICATE)
2019 || cbCur + off > RT_ALIGN_32(Dir.Size, 8))
2020 {
2021 Log(("rtldrPEOpen: %s: cert at %#x/%#x: dwLength=%#x\n", pszLogName, off, Dir.Size, pCur->dwLength));
2022 rc = VERR_LDRPE_CERT_MALFORMED;
2023 break;
2024 }
2025 if ( pCur->wRevision != WIN_CERT_REVISION_2_0
2026 && pCur->wRevision != WIN_CERT_REVISION_1_0)
2027 {
2028 Log(("rtldrPEOpen: %s: cert at %#x/%#x: wRevision=%#x\n", pszLogName, off, Dir.Size, pCur->wRevision));
2029 rc = pCur->wRevision >= WIN_CERT_REVISION_1_0 ? VERR_LDRPE_CERT_UNSUPPORTED : VERR_LDRPE_CERT_MALFORMED;
2030 break;
2031 }
2032 if ( pCur->wCertificateType != WIN_CERT_TYPE_PKCS_SIGNED_DATA
2033 && pCur->wCertificateType != WIN_CERT_TYPE_X509
2034 /*&& pCur->wCertificateType != WIN_CERT_TYPE_RESERVED_1*/
2035 /*&& pCur->wCertificateType != WIN_CERT_TYPE_TS_STACK_SIGNED*/
2036 && pCur->wCertificateType != WIN_CERT_TYPE_EFI_PKCS115
2037 && pCur->wCertificateType != WIN_CERT_TYPE_EFI_GUID
2038 )
2039 {
2040 Log(("rtldrPEOpen: %s: cert at %#x/%#x: wRevision=%#x\n", pszLogName, off, Dir.Size, pCur->wRevision));
2041 rc = pCur->wCertificateType ? VERR_LDRPE_CERT_UNSUPPORTED : VERR_LDRPE_CERT_MALFORMED;
2042 break;
2043 }
2044
2045 /** @todo Rainy Day: Implement further verification using openssl. */
2046
2047 /* next */
2048 off += cbCur;
2049 pCur = (PWIN_CERTIFICATE)((uint8_t *)pCur + cbCur);
2050 } while (off < Dir.Size);
2051 }
2052 RTMemTmpFree(pFirst);
2053 if (RT_FAILURE(rc))
2054 return rc;
2055 }
2056
2057
2058 return VINF_SUCCESS;
2059}
2060
2061
2062/**
2063 * Open a PE image.
2064 *
2065 * @returns iprt status code.
2066 * @param pReader The loader reader instance which will provide the raw image bits.
2067 * @param fFlags Reserved, MBZ.
2068 * @param enmArch Architecture specifier.
2069 * @param offNtHdrs The offset of the NT headers (where you find "PE\0\0").
2070 * @param phLdrMod Where to store the handle.
2071 */
2072int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF offNtHdrs, PRTLDRMOD phLdrMod)
2073{
2074 /*
2075 * Read and validate the file header.
2076 */
2077 IMAGE_FILE_HEADER FileHdr;
2078 int rc = pReader->pfnRead(pReader, &FileHdr, sizeof(FileHdr), offNtHdrs + 4);
2079 if (RT_FAILURE(rc))
2080 return rc;
2081 RTLDRARCH enmArchImage;
2082 const char *pszLogName = pReader->pfnLogName(pReader);
2083 rc = rtldrPEValidateFileHeader(&FileHdr, fFlags, pszLogName, &enmArchImage);
2084 if (RT_FAILURE(rc))
2085 return rc;
2086
2087 /*
2088 * Match the CPU architecture.
2089 */
2090 if ( enmArch != RTLDRARCH_WHATEVER
2091 && enmArch != enmArchImage)
2092 return VERR_LDR_ARCH_MISMATCH;
2093
2094 /*
2095 * Read and validate the "optional" header. Convert 32->64 if necessary.
2096 */
2097 IMAGE_OPTIONAL_HEADER64 OptHdr;
2098 rc = pReader->pfnRead(pReader, &OptHdr, FileHdr.SizeOfOptionalHeader, offNtHdrs + 4 + sizeof(IMAGE_FILE_HEADER));
2099 if (RT_FAILURE(rc))
2100 return rc;
2101 if (FileHdr.SizeOfOptionalHeader != sizeof(OptHdr))
2102 rtldrPEConvert32BitOptionalHeaderTo64Bit(&OptHdr);
2103 rc = rtldrPEValidateOptionalHeader(&OptHdr, pszLogName, offNtHdrs, &FileHdr, pReader->pfnSize(pReader), fFlags);
2104 if (RT_FAILURE(rc))
2105 return rc;
2106
2107 /*
2108 * Read and validate section headers.
2109 */
2110 const size_t cbSections = sizeof(IMAGE_SECTION_HEADER) * FileHdr.NumberOfSections;
2111 PIMAGE_SECTION_HEADER paSections = (PIMAGE_SECTION_HEADER)RTMemAlloc(cbSections);
2112 if (!paSections)
2113 return VERR_NO_MEMORY;
2114 rc = pReader->pfnRead(pReader, paSections, cbSections,
2115 offNtHdrs + 4 + sizeof(IMAGE_FILE_HEADER) + FileHdr.SizeOfOptionalHeader);
2116 if (RT_SUCCESS(rc))
2117 {
2118 rc = rtldrPEValidateSectionHeaders(paSections, FileHdr.NumberOfSections, pszLogName,
2119 &OptHdr, pReader->pfnSize(pReader));
2120 if (RT_SUCCESS(rc))
2121 {
2122 /*
2123 * Allocate and initialize the PE module structure.
2124 */
2125 PRTLDRMODPE pModPe = (PRTLDRMODPE)RTMemAllocZ(sizeof(*pModPe));
2126 if (pModPe)
2127 {
2128 pModPe->Core.u32Magic = RTLDRMOD_MAGIC;
2129 pModPe->Core.eState = LDR_STATE_OPENED;
2130 if (FileHdr.SizeOfOptionalHeader == sizeof(OptHdr))
2131 pModPe->Core.pOps = &s_rtldrPE64Ops.Core;
2132 else
2133 pModPe->Core.pOps = &s_rtldrPE32Ops.Core;
2134 pModPe->Core.pReader = pReader;
2135 pModPe->pvBits = NULL;
2136 pModPe->offNtHdrs = offNtHdrs;
2137 pModPe->offEndOfHdrs = offNtHdrs + 4 + sizeof(IMAGE_FILE_HEADER) + FileHdr.SizeOfOptionalHeader + cbSections;
2138 pModPe->u16Machine = FileHdr.Machine;
2139 pModPe->fFile = FileHdr.Characteristics;
2140 pModPe->cSections = FileHdr.NumberOfSections;
2141 pModPe->paSections = paSections;
2142 pModPe->uEntryPointRVA= OptHdr.AddressOfEntryPoint;
2143 pModPe->uImageBase = (RTUINTPTR)OptHdr.ImageBase;
2144 pModPe->cbImage = OptHdr.SizeOfImage;
2145 pModPe->cbHeaders = OptHdr.SizeOfHeaders;
2146 pModPe->uTimestamp = FileHdr.TimeDateStamp;
2147 pModPe->ImportDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
2148 pModPe->RelocDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
2149 pModPe->ExportDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
2150 pModPe->DebugDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
2151
2152 /*
2153 * Perform validation of some selected data directories which requires
2154 * inspection of the actual data.
2155 */
2156 rc = rtldrPEValidateDirectories(pModPe, &OptHdr);
2157 if (RT_SUCCESS(rc))
2158 {
2159 *phLdrMod = &pModPe->Core;
2160 return VINF_SUCCESS;
2161 }
2162 RTMemFree(pModPe);
2163 }
2164 else
2165 rc = VERR_NO_MEMORY;
2166 }
2167 }
2168 RTMemFree(paSections);
2169 return rc;
2170}
2171
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