VirtualBox

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

Last change on this file since 44417 was 41785, checked in by vboxsync, 13 years ago

Comment typos.

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