VirtualBox

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

最後變更 在這個檔案從45994是 45994,由 vboxsync 提交於 12 年 前

RTDbgModCreateFromPeImage: Mostly implemented.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette