VirtualBox

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

Last change on this file since 25528 was 25342, checked in by vboxsync, 15 years ago

build fix.

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