VirtualBox

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

Last change on this file since 60756 was 60715, checked in by vboxsync, 9 years ago

ldrPE.cpp: Sigh. Can't expect microsoft to update all their linkers. 32-bit ucrtbase.dll just had to use a different load config dir and header sizes. So, apply the fNewStructHack to kludge #2 as well, making it a much larger kludge.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 158.0 KB
Line 
1/* $Id: ldrPE.cpp 60715 2016-04-27 11:27:20Z vboxsync $ */
2/** @file
3 * IPRT - Binary Image Loader, Portable Executable (PE).
4 */
5
6/*
7 * Copyright (C) 2006-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP RTLOGGROUP_LDR
32#include <iprt/ldr.h>
33#include "internal/iprt.h"
34
35#include <iprt/assert.h>
36#include <iprt/asm.h>
37#include <iprt/err.h>
38#include <iprt/log.h>
39#include <iprt/md5.h>
40#include <iprt/mem.h>
41#include <iprt/path.h>
42#include <iprt/sha.h>
43#include <iprt/string.h>
44#ifndef IPRT_WITHOUT_LDR_VERIFY
45#include <iprt/zero.h>
46# include <iprt/crypto/pkcs7.h>
47# include <iprt/crypto/spc.h>
48# include <iprt/crypto/x509.h>
49#endif
50#include <iprt/formats/codeview.h>
51#include <iprt/formats/pecoff.h>
52#include "internal/ldr.h"
53
54
55/*********************************************************************************************************************************
56* Defined Constants And Macros *
57*********************************************************************************************************************************/
58/** Converts rva to a type.
59 * @param pvBits Pointer to base of image bits.
60 * @param rva Relative virtual address.
61 * @param type Type.
62 */
63#define PE_RVA2TYPE(pvBits, rva, type) ((type) ((uintptr_t)pvBits + (uintptr_t)(rva)) )
64
65/** The max size of the security directory. */
66#ifdef IN_RING3
67# define RTLDRMODPE_MAX_SECURITY_DIR_SIZE _4M
68#else
69# define RTLDRMODPE_MAX_SECURITY_DIR_SIZE _1M
70#endif
71
72
73/*********************************************************************************************************************************
74* Structures and Typedefs *
75*********************************************************************************************************************************/
76/**
77 * The PE loader structure.
78 */
79typedef struct RTLDRMODPE
80{
81 /** Core module structure. */
82 RTLDRMODINTERNAL Core;
83 /** Pointer to internal copy of image bits.
84 * @todo the reader should take care of this. */
85 void *pvBits;
86 /** The offset of the NT headers. */
87 RTFOFF offNtHdrs;
88 /** The offset of the first byte after the section table. */
89 RTFOFF offEndOfHdrs;
90
91 /** The machine type (IMAGE_FILE_HEADER::Machine). */
92 uint16_t u16Machine;
93 /** The file flags (IMAGE_FILE_HEADER::Characteristics). */
94 uint16_t fFile;
95 /** Number of sections (IMAGE_FILE_HEADER::NumberOfSections). */
96 unsigned cSections;
97 /** Pointer to an array of the section headers related to the file. */
98 PIMAGE_SECTION_HEADER paSections;
99
100 /** The RVA of the entry point (IMAGE_OPTIONAL_HEADER32::AddressOfEntryPoint). */
101 RTUINTPTR uEntryPointRVA;
102 /** The base address of the image at link time (IMAGE_OPTIONAL_HEADER32::ImageBase). */
103 RTUINTPTR uImageBase;
104 /** The size of the loaded image (IMAGE_OPTIONAL_HEADER32::SizeOfImage). */
105 uint32_t cbImage;
106 /** Size of the header (IMAGE_OPTIONAL_HEADER32::SizeOfHeaders). */
107 uint32_t cbHeaders;
108 /** The image timestamp. */
109 uint32_t uTimestamp;
110 /** The number of imports. UINT32_MAX if not determined. */
111 uint32_t cImports;
112 /** Set if the image is 64-bit, clear if 32-bit. */
113 bool f64Bit;
114 /** The import data directory entry. */
115 IMAGE_DATA_DIRECTORY ImportDir;
116 /** The base relocation data directory entry. */
117 IMAGE_DATA_DIRECTORY RelocDir;
118 /** The export data directory entry. */
119 IMAGE_DATA_DIRECTORY ExportDir;
120 /** The debug directory entry. */
121 IMAGE_DATA_DIRECTORY DebugDir;
122 /** The security directory entry. */
123 IMAGE_DATA_DIRECTORY SecurityDir;
124
125 /** Offset of the first PKCS \#7 SignedData signature if present. */
126 uint32_t offPkcs7SignedData;
127 /** Size of the first PKCS \#7 SignedData. */
128 uint32_t cbPkcs7SignedData;
129
130 /** Copy of the optional header field DllCharacteristics. */
131 uint16_t fDllCharacteristics;
132} RTLDRMODPE;
133/** Pointer to the instance data for a PE loader module. */
134typedef RTLDRMODPE *PRTLDRMODPE;
135
136
137/**
138 * PE Loader module operations.
139 *
140 * The PE loader has one operation which is a bit different between 32-bit and 64-bit PE images,
141 * and for historical and performance reasons have been split into separate functions. Thus the
142 * PE loader extends the RTLDROPS structure with this one entry.
143 */
144typedef struct RTLDROPSPE
145{
146 /** The usual ops. */
147 RTLDROPS Core;
148
149 /**
150 * Resolves all imports.
151 *
152 * @returns iprt status code.
153 * @param pModPe Pointer to the PE loader module structure.
154 * @param pvBitsR Where to read raw image bits. (optional)
155 * @param pvBitsW Where to store the imports. The size of this buffer is equal or
156 * larger to the value returned by pfnGetImageSize().
157 * @param pfnGetImport The callback function to use to resolve imports (aka unresolved externals).
158 * @param pvUser User argument to pass to the callback.
159 */
160 DECLCALLBACKMEMBER(int, pfnResolveImports)(PRTLDRMODPE pModPe, const void *pvBitsR, void *pvBitsW, PFNRTLDRIMPORT pfnGetImport, void *pvUser);
161
162 /** Dummy entry to make sure we've initialized it all. */
163 RTUINT uDummy;
164} RTLDROPSPE, *PRTLDROPSPE;
165
166
167/**
168 * PE hash context union.
169 */
170typedef union RTLDRPEHASHCTXUNION
171{
172 RTSHA512CONTEXT Sha512;
173 RTSHA256CONTEXT Sha256;
174 RTSHA1CONTEXT Sha1;
175 RTMD5CONTEXT Md5;
176} RTLDRPEHASHCTXUNION;
177/** Pointer to a PE hash context union. */
178typedef RTLDRPEHASHCTXUNION *PRTLDRPEHASHCTXUNION;
179
180
181/**
182 * PE hash digests
183 */
184typedef union RTLDRPEHASHRESUNION
185{
186 uint8_t abSha512[RTSHA512_HASH_SIZE];
187 uint8_t abSha256[RTSHA256_HASH_SIZE];
188 uint8_t abSha1[RTSHA1_HASH_SIZE];
189 uint8_t abMd5[RTMD5_HASH_SIZE];
190} RTLDRPEHASHRESUNION;
191/** Pointer to a PE hash work set. */
192typedef RTLDRPEHASHRESUNION *PRTLDRPEHASHRESUNION;
193
194/**
195 * Special places to watch out for when hashing a PE image.
196 */
197typedef struct RTLDRPEHASHSPECIALS
198{
199 uint32_t cbToHash;
200 uint32_t offCksum;
201 uint32_t cbCksum;
202 uint32_t offSecDir;
203 uint32_t cbSecDir;
204 uint32_t offEndSpecial;
205} RTLDRPEHASHSPECIALS;
206/** Pointer to the structure with the special hash places. */
207typedef RTLDRPEHASHSPECIALS *PRTLDRPEHASHSPECIALS;
208
209
210#ifndef IPRT_WITHOUT_LDR_VERIFY
211/**
212 * Parsed signature data.
213 */
214typedef struct RTLDRPESIGNATURE
215{
216 /** The outer content info wrapper. */
217 RTCRPKCS7CONTENTINFO ContentInfo;
218 /** Pointer to the decoded SignedData inside the ContentInfo member. */
219 PRTCRPKCS7SIGNEDDATA pSignedData;
220 /** Pointer to the indirect data content. */
221 PRTCRSPCINDIRECTDATACONTENT pIndData;
222 /** The digest type employed by the signature. */
223 RTDIGESTTYPE enmDigest;
224
225 /** Pointer to the raw signatures. This is allocated in the continuation of
226 * this structure to keep things simple. The size is given by the security
227 * export directory. */
228 WIN_CERTIFICATE const *pRawData;
229
230 /** Hash scratch data. */
231 RTLDRPEHASHCTXUNION HashCtx;
232 /** Hash result. */
233 RTLDRPEHASHRESUNION HashRes;
234} RTLDRPESIGNATURE;
235/** Pointed to SigneData parsing stat and output. */
236typedef RTLDRPESIGNATURE *PRTLDRPESIGNATURE;
237#endif
238
239
240/*********************************************************************************************************************************
241* Internal Functions *
242*********************************************************************************************************************************/
243static void rtldrPEConvert32BitOptionalHeaderTo64Bit(PIMAGE_OPTIONAL_HEADER64 pOptHdr);
244static void rtldrPEConvert32BitLoadConfigTo64Bit(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg);
245static int rtldrPEApplyFixups(PRTLDRMODPE pModPe, const void *pvBitsR, void *pvBitsW, RTUINTPTR BaseAddress, RTUINTPTR OldBaseAddress);
246
247
248
249/**
250 * Reads a section of a PE image given by RVA + size, using mapped bits if
251 * available or allocating heap memory and reading from the file.
252 *
253 * @returns IPRT status code.
254 * @param pThis Pointer to the PE loader module structure.
255 * @param pvBits Read only bits if available. NULL if not.
256 * @param uRva The RVA to read at.
257 * @param cbMem The number of bytes to read.
258 * @param ppvMem Where to return the memory on success (heap or
259 * inside pvBits).
260 */
261static int rtldrPEReadPartByRva(PRTLDRMODPE pThis, const void *pvBits, uint32_t uRva, uint32_t cbMem, void const **ppvMem)
262{
263 *ppvMem = NULL;
264 if (!cbMem)
265 return VINF_SUCCESS;
266
267 /*
268 * Use bits if we've got some.
269 */
270 if (pvBits)
271 {
272 *ppvMem = (uint8_t const *)pvBits + uRva;
273 return VINF_SUCCESS;
274 }
275 if (pThis->pvBits)
276 {
277 *ppvMem = (uint8_t const *)pThis->pvBits + uRva;
278 return VINF_SUCCESS;
279 }
280
281 /*
282 * Allocate a buffer and read the bits from the file (or whatever).
283 */
284 if (!pThis->Core.pReader)
285 return VERR_ACCESS_DENIED;
286
287 uint8_t *pbMem = (uint8_t *)RTMemAllocZ(cbMem);
288 if (!pbMem)
289 return VERR_NO_MEMORY;
290 *ppvMem = pbMem;
291
292 /* Do the reading on a per section base. */
293 RTFOFF const cbFile = pThis->Core.pReader->pfnSize(pThis->Core.pReader);
294 for (;;)
295 {
296 /* Translate the RVA into a file offset. */
297 uint32_t offFile = uRva;
298 uint32_t cbToRead = cbMem;
299 uint32_t cbToAdv = cbMem;
300
301 if (uRva < pThis->paSections[0].VirtualAddress)
302 {
303 /* Special header section. */
304 cbToRead = pThis->paSections[0].VirtualAddress - uRva;
305 if (cbToRead > cbMem)
306 cbToRead = cbMem;
307 cbToAdv = cbToRead;
308
309 /* The following capping is an approximation. */
310 uint32_t offFirstRawData = RT_ALIGN(pThis->cbHeaders, _4K);
311 if ( pThis->paSections[0].PointerToRawData > 0
312 && pThis->paSections[0].SizeOfRawData > 0)
313 offFirstRawData = pThis->paSections[0].PointerToRawData;
314 if (offFile >= offFirstRawData)
315 cbToRead = 0;
316 else if (offFile + cbToRead > offFirstRawData)
317 cbToRead = offFile - offFirstRawData;
318 }
319 else
320 {
321 /* Find the matching section and its mapping size. */
322 uint32_t j = 0;
323 uint32_t cbMapping = 0;
324 uint32_t offSection = 0;
325 while (j < pThis->cSections)
326 {
327 cbMapping = (j + 1 < pThis->cSections ? pThis->paSections[j + 1].VirtualAddress : pThis->cbImage)
328 - pThis->paSections[j].VirtualAddress;
329 offSection = uRva - pThis->paSections[j].VirtualAddress;
330 if (offSection < cbMapping)
331 break;
332 j++;
333 }
334 if (j >= cbMapping)
335 break; /* This shouldn't happen, just return zeros if it does. */
336
337 /* Adjust the sizes and calc the file offset. */
338 if (offSection + cbToAdv > cbMapping)
339 cbToAdv = cbToRead = cbMapping - offSection;
340
341 if ( pThis->paSections[j].PointerToRawData > 0
342 && pThis->paSections[j].SizeOfRawData > 0)
343 {
344 offFile = offSection;
345 if (offFile + cbToRead > pThis->paSections[j].SizeOfRawData)
346 cbToRead = pThis->paSections[j].SizeOfRawData - offFile;
347 offFile += pThis->paSections[j].PointerToRawData;
348 }
349 else
350 {
351 offFile = UINT32_MAX;
352 cbToRead = 0;
353 }
354 }
355
356 /* Perform the read after adjusting a little (paranoia). */
357 if (offFile > cbFile)
358 cbToRead = 0;
359 if (cbToRead)
360 {
361 if ((RTFOFF)offFile + cbToRead > cbFile)
362 cbToRead = (uint32_t)(cbFile - (RTFOFF)offFile);
363 int rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pbMem, cbToRead, offFile);
364 if (RT_FAILURE(rc))
365 {
366 RTMemFree((void *)*ppvMem);
367 *ppvMem = NULL;
368 return rc;
369 }
370 }
371
372 /* Advance */
373 if (cbMem <= cbToAdv)
374 break;
375 cbMem -= cbToAdv;
376 pbMem += cbToAdv;
377 uRva += cbToAdv;
378 }
379
380 return VINF_SUCCESS;
381}
382
383
384/**
385 * Reads a part of a PE file from the file and into a heap block.
386 *
387 * @returns IRPT status code.
388 * @param pThis Pointer to the PE loader module structure..
389 * @param offFile The file offset.
390 * @param cbMem The number of bytes to read.
391 * @param ppvMem Where to return the heap block with the bytes on
392 * success.
393 */
394static int rtldrPEReadPartFromFile(PRTLDRMODPE pThis, uint32_t offFile, uint32_t cbMem, void const **ppvMem)
395{
396 *ppvMem = NULL;
397 if (!cbMem)
398 return VINF_SUCCESS;
399
400 /*
401 * Allocate a buffer and read the bits from the file (or whatever).
402 */
403 if (!pThis->Core.pReader)
404 return VERR_ACCESS_DENIED;
405
406 uint8_t *pbMem = (uint8_t *)RTMemAlloc(cbMem);
407 if (!pbMem)
408 return VERR_NO_MEMORY;
409
410 int rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pbMem, cbMem, offFile);
411 if (RT_FAILURE(rc))
412 {
413 RTMemFree((void *)*ppvMem);
414 return rc;
415 }
416
417 *ppvMem = pbMem;
418 return VINF_SUCCESS;
419}
420
421
422/**
423 * Reads a part of a PE image into memory one way or another.
424 *
425 * Either the RVA or the offFile must be valid. We'll prefer the RVA if
426 * possible.
427 *
428 * @returns IPRT status code.
429 * @param pThis Pointer to the PE loader module structure.
430 * @param pvBits Read only bits if available. NULL if not.
431 * @param uRva The RVA to read at.
432 * @param offFile The file offset.
433 * @param cbMem The number of bytes to read.
434 * @param ppvMem Where to return the memory on success (heap or
435 * inside pvBits).
436 */
437static int rtldrPEReadPart(PRTLDRMODPE pThis, const void *pvBits, RTFOFF offFile, RTLDRADDR uRva,
438 uint32_t cbMem, void const **ppvMem)
439{
440 if ( uRva == NIL_RTLDRADDR
441 || uRva > pThis->cbImage
442 || cbMem > pThis->cbImage
443 || uRva + cbMem > pThis->cbImage)
444 {
445 if (offFile < 0 || offFile >= UINT32_MAX)
446 return VERR_INVALID_PARAMETER;
447 return rtldrPEReadPartFromFile(pThis, (uint32_t)offFile, cbMem, ppvMem);
448 }
449 return rtldrPEReadPartByRva(pThis, pvBits, (uint32_t)uRva, cbMem, ppvMem);
450}
451
452
453/**
454 * Frees up memory returned by rtldrPEReadPart*.
455 *
456 * @param pThis Pointer to the PE loader module structure..
457 * @param pvBits Read only bits if available. NULL if not..
458 * @param pvMem The memory we were given by the reader method.
459 */
460static void rtldrPEFreePart(PRTLDRMODPE pThis, const void *pvBits, void const *pvMem)
461{
462 if (!pvMem)
463 return;
464
465 if (pvBits && (uintptr_t)pvMem - (uintptr_t)pvBits < pThis->cbImage)
466 return;
467 if (pThis->pvBits && (uintptr_t)pvMem - (uintptr_t)pThis->pvBits < pThis->cbImage)
468 return;
469
470 RTMemFree((void *)pvMem);
471}
472
473
474/** @interface_method_impl{RTLDROPS,pfnGetImageSize} */
475static DECLCALLBACK(size_t) rtldrPEGetImageSize(PRTLDRMODINTERNAL pMod)
476{
477 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
478 return pModPe->cbImage;
479}
480
481
482/**
483 * Reads the image into memory.
484 *
485 * @returns iprt status code.
486 * @param pModPe The PE module.
487 * @param pvBits Where to store the bits, this buffer is at least pItem->Core.cbImage in size.
488 */
489static int rtldrPEGetBitsNoImportsNorFixups(PRTLDRMODPE pModPe, void *pvBits)
490{
491 /*
492 * Both these checks are related to pfnDone().
493 */
494 PRTLDRREADER pReader = pModPe->Core.pReader;
495 if (!pReader)
496 {
497 AssertMsgFailed(("You've called done!\n"));
498 return VERR_WRONG_ORDER;
499 }
500 if (!pvBits)
501 return VERR_NO_MEMORY;
502
503 /*
504 * Zero everything (could be done per section).
505 */
506 memset(pvBits, 0, pModPe->cbImage);
507
508#ifdef PE_FILE_OFFSET_EQUALS_RVA
509 /*
510 * Read the entire image / file.
511 */
512 const RTFOFF cbRawImage = pReader->pfnSize(pReader)
513 rc = pReader->pfnRead(pReader, pvBits, RT_MIN(pModPe->cbImage, cbRawImage), 0);
514 if (RT_FAILURE(rc))
515 Log(("rtldrPE: %s: Reading %#x bytes at offset %#x failed, %Rrc!!! (the entire image)\n",
516 pReader->pfnLogName(pReader), RT_MIN(pModPe->cbImage, cbRawImage), 0, rc));
517#else
518
519 /*
520 * Read the headers.
521 */
522 int rc = pReader->pfnRead(pReader, pvBits, pModPe->cbHeaders, 0);
523 if (RT_SUCCESS(rc))
524 {
525 /*
526 * Read the sections.
527 */
528 PIMAGE_SECTION_HEADER pSH = pModPe->paSections;
529 for (unsigned cLeft = pModPe->cSections; cLeft > 0; cLeft--, pSH++)
530 if (pSH->SizeOfRawData && pSH->Misc.VirtualSize)
531 {
532 rc = pReader->pfnRead(pReader, (uint8_t *)pvBits + pSH->VirtualAddress, pSH->SizeOfRawData, pSH->PointerToRawData);
533 if (RT_FAILURE(rc))
534 {
535 Log(("rtldrPE: %s: Reading %#x bytes at offset %#x failed, %Rrc - section #%d '%.*s'!!!\n",
536 pReader->pfnLogName(pReader), pSH->SizeOfRawData, pSH->PointerToRawData, rc,
537 pSH - pModPe->paSections, sizeof(pSH->Name), pSH->Name));
538 break;
539 }
540 }
541 }
542 else
543 Log(("rtldrPE: %s: Reading %#x bytes at offset %#x failed, %Rrc!!!\n",
544 pReader->pfnLogName(pReader), pModPe->cbHeaders, 0, rc));
545#endif
546 return rc;
547}
548
549
550/**
551 * Reads the bits into the internal buffer pointed to by PRTLDRMODPE::pvBits.
552 *
553 * @returns iprt status code.
554 * @param pModPe The PE module.
555 */
556static int rtldrPEReadBits(PRTLDRMODPE pModPe)
557{
558 Assert(!pModPe->pvBits);
559 void *pvBitsW = RTMemAllocZ(pModPe->cbImage);
560 if (!pvBitsW)
561 return VERR_NO_MEMORY;
562 int rc = rtldrPEGetBitsNoImportsNorFixups(pModPe, pvBitsW);
563 if (RT_SUCCESS(rc))
564 pModPe->pvBits = pvBitsW;
565 else
566 RTMemFree(pvBitsW);
567 return rc;
568}
569
570
571/** @interface_method_impl{RTLDROPS,pfnGetBits} */
572static DECLCALLBACK(int) rtldrPEGetBits(PRTLDRMODINTERNAL pMod, void *pvBits, RTUINTPTR BaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser)
573{
574 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
575
576 /*
577 * Read the image.
578 */
579 int rc = rtldrPEGetBitsNoImportsNorFixups(pModPe, pvBits);
580 if (RT_SUCCESS(rc))
581 {
582 /*
583 * Resolve imports.
584 */
585 if (pfnGetImport)
586 rc = ((PRTLDROPSPE)pMod->pOps)->pfnResolveImports(pModPe, pvBits, pvBits, pfnGetImport, pvUser);
587 if (RT_SUCCESS(rc))
588 {
589 /*
590 * Apply relocations.
591 */
592 rc = rtldrPEApplyFixups(pModPe, pvBits, pvBits, BaseAddress, pModPe->uImageBase);
593 if (RT_SUCCESS(rc))
594 return rc;
595 AssertMsgFailed(("Failed to apply fixups. rc=%Rrc\n", rc));
596 }
597 else
598 AssertMsgFailed(("Failed to resolve imports. rc=%Rrc\n", rc));
599 }
600 return rc;
601}
602
603
604/* The image_thunk_data32/64 structures are not very helpful except for getting RSI. keep them around till all the code has been converted. */
605typedef struct _IMAGE_THUNK_DATA32
606{
607 union
608 {
609 uint32_t ForwarderString;
610 uint32_t Function;
611 uint32_t Ordinal;
612 uint32_t AddressOfData;
613 } u1;
614} IMAGE_THUNK_DATA32;
615typedef IMAGE_THUNK_DATA32 *PIMAGE_THUNK_DATA32;
616
617
618/** @copydoc RTLDROPSPE::pfnResolveImports */
619static DECLCALLBACK(int) rtldrPEResolveImports32(PRTLDRMODPE pModPe, const void *pvBitsR, void *pvBitsW, PFNRTLDRIMPORT pfnGetImport, void *pvUser)
620{
621 /*
622 * Check if there is actually anything to work on.
623 */
624 if ( !pModPe->ImportDir.VirtualAddress
625 || !pModPe->ImportDir.Size)
626 return 0;
627
628 /*
629 * Walk the IMAGE_IMPORT_DESCRIPTOR table.
630 */
631 int rc = VINF_SUCCESS;
632 PIMAGE_IMPORT_DESCRIPTOR pImps;
633 for (pImps = PE_RVA2TYPE(pvBitsR, pModPe->ImportDir.VirtualAddress, PIMAGE_IMPORT_DESCRIPTOR);
634 !rc && pImps->Name != 0 && pImps->FirstThunk != 0;
635 pImps++)
636 {
637 AssertReturn(pImps->Name < pModPe->cbImage, VERR_BAD_EXE_FORMAT);
638 const char *pszModName = PE_RVA2TYPE(pvBitsR, pImps->Name, const char *);
639 AssertReturn(pImps->FirstThunk < pModPe->cbImage, VERR_BAD_EXE_FORMAT);
640 AssertReturn(pImps->u.OriginalFirstThunk < pModPe->cbImage, VERR_BAD_EXE_FORMAT);
641
642 Log3(("RTLdrPE: Import descriptor: %s\n", pszModName));
643 Log4(("RTLdrPE: OriginalFirstThunk = %#RX32\n"
644 "RTLdrPE: TimeDateStamp = %#RX32\n"
645 "RTLdrPE: ForwarderChain = %#RX32\n"
646 "RTLdrPE: Name = %#RX32\n"
647 "RTLdrPE: FirstThunk = %#RX32\n",
648 pImps->u.OriginalFirstThunk, pImps->TimeDateStamp,
649 pImps->ForwarderChain, pImps->Name, pImps->FirstThunk));
650
651 /*
652 * Walk the thunks table(s).
653 */
654 PIMAGE_THUNK_DATA32 pFirstThunk = PE_RVA2TYPE(pvBitsW, pImps->FirstThunk, PIMAGE_THUNK_DATA32); /* update this. */
655 PIMAGE_THUNK_DATA32 pThunk = pImps->u.OriginalFirstThunk == 0 /* read from this. */
656 ? PE_RVA2TYPE(pvBitsR, pImps->FirstThunk, PIMAGE_THUNK_DATA32)
657 : PE_RVA2TYPE(pvBitsR, pImps->u.OriginalFirstThunk, PIMAGE_THUNK_DATA32);
658 while (!rc && pThunk->u1.Ordinal != 0)
659 {
660 RTUINTPTR Value = 0;
661 if (pThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG32)
662 {
663 rc = pfnGetImport(&pModPe->Core, pszModName, NULL, IMAGE_ORDINAL32(pThunk->u1.Ordinal), &Value, pvUser);
664 Log4((RT_SUCCESS(rc) ? "RTLdrPE: %RTptr #%u\n" : "RTLdrPE: %08RX32 #%u rc=%Rrc\n",
665 (uint32_t)Value, IMAGE_ORDINAL32(pThunk->u1.Ordinal), rc));
666 }
667 else if ( pThunk->u1.Ordinal > 0
668 && pThunk->u1.Ordinal < pModPe->cbImage)
669 {
670 rc = pfnGetImport(&pModPe->Core, pszModName, PE_RVA2TYPE(pvBitsR, (char*)(uintptr_t)pThunk->u1.AddressOfData + 2, const char *),
671 ~0, &Value, pvUser);
672 Log4((RT_SUCCESS(rc) ? "RTLdrPE: %RTptr %s\n" : "RTLdrPE: %08RX32 %s rc=%Rrc\n",
673 (uint32_t)Value, PE_RVA2TYPE(pvBitsR, (char*)(uintptr_t)pThunk->u1.AddressOfData + 2, const char *), rc));
674 }
675 else
676 {
677 AssertMsgFailed(("bad import data thunk!\n"));
678 rc = VERR_BAD_EXE_FORMAT;
679 }
680 pFirstThunk->u1.Function = (uint32_t)Value;
681 if (pFirstThunk->u1.Function != Value)
682 {
683 AssertMsgFailed(("external symbol address to big!\n"));
684 rc = VERR_ADDRESS_CONFLICT; /** @todo get me a better error status code. */
685 }
686 pThunk++;
687 pFirstThunk++;
688 }
689 }
690
691 return rc;
692}
693
694
695/* The image_thunk_data32/64 structures are not very helpful except for getting RSI. keep them around till all the code has been converted. */
696typedef struct _IMAGE_THUNK_DATA64
697{
698 union
699 {
700 uint64_t ForwarderString;
701 uint64_t Function;
702 uint64_t Ordinal;
703 uint64_t AddressOfData;
704 } u1;
705} IMAGE_THUNK_DATA64;
706typedef IMAGE_THUNK_DATA64 *PIMAGE_THUNK_DATA64;
707
708
709/** @copydoc RTLDROPSPE::pfnResolveImports */
710static DECLCALLBACK(int) rtldrPEResolveImports64(PRTLDRMODPE pModPe, const void *pvBitsR, void *pvBitsW, PFNRTLDRIMPORT pfnGetImport, void *pvUser)
711{
712 /*
713 * Check if there is actually anything to work on.
714 */
715 if ( !pModPe->ImportDir.VirtualAddress
716 || !pModPe->ImportDir.Size)
717 return 0;
718
719 /*
720 * Walk the IMAGE_IMPORT_DESCRIPTOR table.
721 */
722 int rc = VINF_SUCCESS;
723 PIMAGE_IMPORT_DESCRIPTOR pImps;
724 for (pImps = PE_RVA2TYPE(pvBitsR, pModPe->ImportDir.VirtualAddress, PIMAGE_IMPORT_DESCRIPTOR);
725 !rc && pImps->Name != 0 && pImps->FirstThunk != 0;
726 pImps++)
727 {
728 AssertReturn(pImps->Name < pModPe->cbImage, VERR_BAD_EXE_FORMAT);
729 const char *pszModName = PE_RVA2TYPE(pvBitsR, pImps->Name, const char *);
730 AssertReturn(pImps->FirstThunk < pModPe->cbImage, VERR_BAD_EXE_FORMAT);
731 AssertReturn(pImps->u.OriginalFirstThunk < pModPe->cbImage, VERR_BAD_EXE_FORMAT);
732
733 Log3(("RTLdrPE: Import descriptor: %s\n", pszModName));
734 Log4(("RTLdrPE: OriginalFirstThunk = %#RX32\n"
735 "RTLdrPE: TimeDateStamp = %#RX32\n"
736 "RTLdrPE: ForwarderChain = %#RX32\n"
737 "RTLdrPE: Name = %#RX32\n"
738 "RTLdrPE: FirstThunk = %#RX32\n",
739 pImps->u.OriginalFirstThunk, pImps->TimeDateStamp,
740 pImps->ForwarderChain, pImps->Name, pImps->FirstThunk));
741
742 /*
743 * Walk the thunks table(s).
744 */
745 PIMAGE_THUNK_DATA64 pFirstThunk = PE_RVA2TYPE(pvBitsW, pImps->FirstThunk, PIMAGE_THUNK_DATA64); /* update this. */
746 PIMAGE_THUNK_DATA64 pThunk = pImps->u.OriginalFirstThunk == 0 /* read from this. */
747 ? PE_RVA2TYPE(pvBitsR, pImps->FirstThunk, PIMAGE_THUNK_DATA64)
748 : PE_RVA2TYPE(pvBitsR, pImps->u.OriginalFirstThunk, PIMAGE_THUNK_DATA64);
749 while (!rc && pThunk->u1.Ordinal != 0)
750 {
751 RTUINTPTR Value = 0;
752 if (pThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG64)
753 {
754 rc = pfnGetImport(&pModPe->Core, pszModName, NULL, (unsigned)IMAGE_ORDINAL64(pThunk->u1.Ordinal), &Value, pvUser);
755 Log4((RT_SUCCESS(rc) ? "RTLdrPE: %016RX64 #%u\n" : "RTLdrPE: %016RX64 #%u rc=%Rrc\n",
756 (uint64_t)Value, (unsigned)IMAGE_ORDINAL64(pThunk->u1.Ordinal), rc));
757 }
758 else if ( pThunk->u1.Ordinal > 0
759 && pThunk->u1.Ordinal < pModPe->cbImage)
760 {
761 /** @todo add validation of the string pointer! */
762 rc = pfnGetImport(&pModPe->Core, pszModName, PE_RVA2TYPE(pvBitsR, (uintptr_t)pThunk->u1.AddressOfData + 2, const char *),
763 ~0, &Value, pvUser);
764 Log4((RT_SUCCESS(rc) ? "RTLdrPE: %016RX64 %s\n" : "RTLdrPE: %016RX64 %s rc=%Rrc\n",
765 (uint64_t)Value, PE_RVA2TYPE(pvBitsR, (uintptr_t)pThunk->u1.AddressOfData + 2, const char *), rc));
766 }
767 else
768 {
769 AssertMsgFailed(("bad import data thunk!\n"));
770 rc = VERR_BAD_EXE_FORMAT;
771 }
772 pFirstThunk->u1.Function = Value;
773 pThunk++;
774 pFirstThunk++;
775 }
776 }
777
778 return rc;
779}
780
781
782/**
783 * Applies fixups.
784 */
785static int rtldrPEApplyFixups(PRTLDRMODPE pModPe, const void *pvBitsR, void *pvBitsW, RTUINTPTR BaseAddress, RTUINTPTR OldBaseAddress)
786{
787 if ( !pModPe->RelocDir.VirtualAddress
788 || !pModPe->RelocDir.Size)
789 return 0;
790
791 /*
792 * Apply delta fixups iterating fixup chunks.
793 */
794 PIMAGE_BASE_RELOCATION pbr = PE_RVA2TYPE(pvBitsR, pModPe->RelocDir.VirtualAddress, PIMAGE_BASE_RELOCATION);
795 PIMAGE_BASE_RELOCATION pBaseRelocs = pbr;
796 unsigned cbBaseRelocs = pModPe->RelocDir.Size;
797 RTUINTPTR uDelta = BaseAddress - OldBaseAddress;
798 Log2(("RTLdrPE: Fixups: uDelta=%#RTptr BaseAddress=%#RTptr OldBaseAddress=%#RTptr\n", uDelta, BaseAddress, OldBaseAddress));
799 Log4(("RTLdrPE: BASERELOC: VirtualAddres=%RX32 Size=%RX32\n", pModPe->RelocDir.VirtualAddress, pModPe->RelocDir.Size));
800 Assert(sizeof(*pbr) == sizeof(uint32_t) * 2);
801
802 while ( (uintptr_t)pbr - (uintptr_t)pBaseRelocs + 8 < cbBaseRelocs /* 8= VirtualAddress and SizeOfBlock members */
803 && pbr->SizeOfBlock >= 8)
804 {
805 uint16_t *pwoffFixup = (uint16_t *)(pbr + 1);
806 uint32_t cRelocations = (pbr->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(uint16_t);
807 Log3(("RTLdrPE: base relocs for %#010x, size %#06x (%d relocs)\n", pbr->VirtualAddress, pbr->SizeOfBlock, cRelocations));
808
809 /* Some bound checking just to be sure it works... */
810 if ((uintptr_t)pbr - (uintptr_t)pBaseRelocs + pbr->SizeOfBlock > cbBaseRelocs)
811 cRelocations = (uint32_t)( (((uintptr_t)pBaseRelocs + cbBaseRelocs) - (uintptr_t)pbr - sizeof(IMAGE_BASE_RELOCATION))
812 / sizeof(uint16_t) );
813
814 /*
815 * Loop thru the fixups in this chunk.
816 */
817 while (cRelocations != 0)
818 {
819 /*
820 * Common fixup
821 */
822 static const char * const s_apszReloc[16] =
823 {
824 "ABS", "HIGH", "LOW", "HIGHLOW", "HIGHADJ", "MIPS_JMPADDR", "RES6", "RES7",
825 "RES8", "IA64_IMM64", "DIR64", "HIGH3ADJ", "RES12", "RES13", "RES14", "RES15"
826 }; NOREF(s_apszReloc);
827 union
828 {
829 uint16_t *pu16;
830 uint32_t *pu32;
831 uint64_t *pu64;
832 } u;
833 const int offFixup = *pwoffFixup & 0xfff;
834 u.pu32 = PE_RVA2TYPE(pvBitsW, offFixup + pbr->VirtualAddress, uint32_t *);
835 const int fType = *pwoffFixup >> 12;
836 Log4(("RTLdrPE: %08x %s\n", offFixup + pbr->VirtualAddress, s_apszReloc[fType]));
837 switch (fType)
838 {
839 case IMAGE_REL_BASED_HIGHLOW: /* 32-bit, add delta. */
840 *u.pu32 += (uint32_t)uDelta;
841 break;
842 case IMAGE_REL_BASED_DIR64: /* 64-bit, add delta. */
843 *u.pu64 += (RTINTPTR)uDelta;
844 break;
845 case IMAGE_REL_BASED_ABSOLUTE: /* Alignment placeholder. */
846 break;
847 /* odd ones */
848 case IMAGE_REL_BASED_LOW: /* 16-bit, add 1st 16-bit part of the delta. */
849 *u.pu16 += (uint16_t)uDelta;
850 break;
851 case IMAGE_REL_BASED_HIGH: /* 16-bit, add 2nd 16-bit part of the delta. */
852 *u.pu16 += (uint16_t)(uDelta >> 16);
853 break;
854 /* never ever seen these next two, and I'm not 100% sure they are correctly implemented here. */
855 case IMAGE_REL_BASED_HIGHADJ:
856 {
857 if (cRelocations <= 1)
858 {
859 AssertMsgFailed(("HIGHADJ missing 2nd record!\n"));
860 return VERR_BAD_EXE_FORMAT;
861 }
862 cRelocations--;
863 pwoffFixup++;
864 int32_t i32 = (uint32_t)(*u.pu16 << 16) | *pwoffFixup;
865 i32 += (uint32_t)uDelta;
866 i32 += 0x8000; //??
867 *u.pu16 = (uint16_t)(i32 >> 16);
868 break;
869 }
870 case IMAGE_REL_BASED_HIGH3ADJ:
871 {
872 if (cRelocations <= 2)
873 {
874 AssertMsgFailed(("HIGHADJ3 missing 2nd record!\n"));
875 return VERR_BAD_EXE_FORMAT;
876 }
877 cRelocations -= 2;
878 pwoffFixup++;
879 int64_t i64 = ((uint64_t)*u.pu16 << 32) | *(uint32_t *)pwoffFixup++;
880 i64 += (int64_t)uDelta << 16; //??
881 i64 += 0x80000000;//??
882 *u.pu16 = (uint16_t)(i64 >> 32);
883 break;
884 }
885 default:
886 AssertMsgFailed(("Unknown fixup type %d offset=%#x\n", fType, offFixup));
887 break;
888 }
889
890 /*
891 * Next offset/type
892 */
893 pwoffFixup++;
894 cRelocations--;
895 } /* while loop */
896
897 /*
898 * Next Fixup chunk. (i.e. next page)
899 */
900 pbr = (PIMAGE_BASE_RELOCATION)((uintptr_t)pbr + pbr->SizeOfBlock);
901 } /* while loop */
902
903 return 0;
904}
905
906
907/** @interface_method_impl{RTLDROPS,pfnRelocate} */
908static DECLCALLBACK(int) rtldrPERelocate(PRTLDRMODINTERNAL pMod, void *pvBits, RTUINTPTR NewBaseAddress, RTUINTPTR OldBaseAddress,
909 PFNRTLDRIMPORT pfnGetImport, void *pvUser)
910{
911 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
912
913 /*
914 * Do we have to read the image bits?
915 */
916 if (!pModPe->pvBits)
917 {
918 int rc = rtldrPEReadBits(pModPe);
919 if (RT_FAILURE(rc))
920 return rc;
921 }
922
923 /*
924 * Process imports.
925 */
926 int rc = ((PRTLDROPSPE)pMod->pOps)->pfnResolveImports(pModPe, pModPe->pvBits, pvBits, pfnGetImport, pvUser);
927 if (RT_SUCCESS(rc))
928 {
929 /*
930 * Apply relocations.
931 */
932 rc = rtldrPEApplyFixups(pModPe, pModPe->pvBits, pvBits, NewBaseAddress, OldBaseAddress);
933 AssertRC(rc);
934 }
935 return rc;
936}
937
938
939/**
940 * Internal worker for pfnGetSymbolEx and pfnQueryForwarderInfo.
941 *
942 * @returns IPRT status code.
943 * @param pModPe The PE module instance.
944 * @param iOrdinal The symbol ordinal, UINT32_MAX if named symbol.
945 * @param pszSymbol The symbol name.
946 * @param ppvBits The image bits pointer (input/output).
947 * @param puRvaExport Where to return the symbol RVA.
948 * @param puOrdinal Where to return the ordinal number. Optional.
949 */
950static int rtLdrPE_ExportToRva(PRTLDRMODPE pModPe, uint32_t iOrdinal, const char *pszSymbol,
951 const void **ppvBits, uint32_t *puRvaExport, uint32_t *puOrdinal)
952{
953 /*
954 * Check if there is actually anything to work on.
955 */
956 if ( !pModPe->ExportDir.VirtualAddress
957 || !pModPe->ExportDir.Size)
958 return VERR_SYMBOL_NOT_FOUND;
959
960 /*
961 * No bits supplied? Do we need to read the bits?
962 */
963 void const *pvBits = *ppvBits;
964 if (!pvBits)
965 {
966 if (!pModPe->pvBits)
967 {
968 int rc = rtldrPEReadBits(pModPe);
969 if (RT_FAILURE(rc))
970 return rc;
971 }
972 *ppvBits = pvBits = pModPe->pvBits;
973 }
974
975 PIMAGE_EXPORT_DIRECTORY pExpDir = PE_RVA2TYPE(pvBits, pModPe->ExportDir.VirtualAddress, PIMAGE_EXPORT_DIRECTORY);
976 int iExpOrdinal = 0; /* index into address table. */
977 if (iOrdinal != UINT32_MAX)
978 {
979 /*
980 * Find ordinal export: Simple table lookup.
981 */
982 if ( iOrdinal >= pExpDir->Base + RT_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions)
983 || iOrdinal < pExpDir->Base)
984 return VERR_SYMBOL_NOT_FOUND;
985 iExpOrdinal = iOrdinal - pExpDir->Base;
986 }
987 else
988 {
989 /*
990 * Find Named Export: Do binary search on the name table.
991 */
992 uint32_t *paRVANames = PE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, uint32_t *);
993 uint16_t *paOrdinals = PE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, uint16_t *);
994 int iStart = 1;
995 int iEnd = pExpDir->NumberOfNames;
996
997 for (;;)
998 {
999 /* end of search? */
1000 if (iStart > iEnd)
1001 {
1002#ifdef RT_STRICT
1003 /* do a linear search just to verify the correctness of the above algorithm */
1004 for (unsigned i = 0; i < pExpDir->NumberOfNames; i++)
1005 {
1006 AssertMsg(i == 0 || strcmp(PE_RVA2TYPE(pvBits, paRVANames[i], const char *), PE_RVA2TYPE(pvBits, paRVANames[i - 1], const char *)) > 0,
1007 ("bug in binary export search!!!\n"));
1008 AssertMsg(strcmp(PE_RVA2TYPE(pvBits, paRVANames[i], const char *), pszSymbol) != 0,
1009 ("bug in binary export search!!!\n"));
1010 }
1011#endif
1012 return VERR_SYMBOL_NOT_FOUND;
1013 }
1014
1015 int i = (iEnd - iStart) / 2 + iStart;
1016 const char *pszExpName = PE_RVA2TYPE(pvBits, paRVANames[i - 1], const char *);
1017 int diff = strcmp(pszExpName, pszSymbol);
1018 if (diff > 0) /* pszExpName > pszSymbol: search chunck before i */
1019 iEnd = i - 1;
1020 else if (diff) /* pszExpName < pszSymbol: search chunk after i */
1021 iStart = i + 1;
1022 else /* pszExpName == pszSymbol */
1023 {
1024 iExpOrdinal = paOrdinals[i - 1];
1025 break;
1026 }
1027 } /* binary search thru name table */
1028 }
1029
1030 /*
1031 * Found export (iExpOrdinal).
1032 */
1033 uint32_t *paAddress = PE_RVA2TYPE(pvBits, pExpDir->AddressOfFunctions, uint32_t *);
1034 *puRvaExport = paAddress[iExpOrdinal];
1035 if (puOrdinal)
1036 *puOrdinal = iExpOrdinal;
1037 return VINF_SUCCESS;
1038}
1039
1040
1041/** @interface_method_impl{RTLDROPS,pfnGetSymbolEx} */
1042static DECLCALLBACK(int) rtldrPEGetSymbolEx(PRTLDRMODINTERNAL pMod, const void *pvBits, RTUINTPTR BaseAddress,
1043 uint32_t iOrdinal, const char *pszSymbol, RTUINTPTR *pValue)
1044{
1045 PRTLDRMODPE pThis = (PRTLDRMODPE)pMod;
1046 uint32_t uRvaExport;
1047 int rc = rtLdrPE_ExportToRva(pThis, iOrdinal, pszSymbol, &pvBits, &uRvaExport, NULL);
1048 if (RT_SUCCESS(rc))
1049 {
1050
1051 uint32_t offForwarder = uRvaExport - pThis->ExportDir.VirtualAddress;
1052 if (offForwarder >= pThis->ExportDir.Size)
1053 /* Get plain export address */
1054 *pValue = PE_RVA2TYPE(BaseAddress, uRvaExport, RTUINTPTR);
1055 else
1056 {
1057 /* Return the approximate length of the forwarder buffer. */
1058 const char *pszForwarder = PE_RVA2TYPE(pvBits, uRvaExport, const char *);
1059 *pValue = sizeof(RTLDRIMPORTINFO) + RTStrNLen(pszForwarder, offForwarder - pThis->ExportDir.Size);
1060 rc = VERR_LDR_FORWARDER;
1061 }
1062 }
1063 return rc;
1064}
1065
1066
1067/** @interface_method_impl{RTLDROPS,pfnQueryForwarderInfo} */
1068static DECLCALLBACK(int) rtldrPE_QueryForwarderInfo(PRTLDRMODINTERNAL pMod, const void *pvBits, uint32_t iOrdinal,
1069 const char *pszSymbol, PRTLDRIMPORTINFO pInfo, size_t cbInfo)
1070{
1071 AssertReturn(cbInfo >= sizeof(*pInfo), VERR_INVALID_PARAMETER);
1072
1073 PRTLDRMODPE pThis = (PRTLDRMODPE)pMod;
1074 uint32_t uRvaExport;
1075 int rc = rtLdrPE_ExportToRva(pThis, iOrdinal, pszSymbol, &pvBits, &uRvaExport, &iOrdinal);
1076 if (RT_SUCCESS(rc))
1077 {
1078 uint32_t offForwarder = uRvaExport - pThis->ExportDir.VirtualAddress;
1079 if (offForwarder < pThis->ExportDir.Size)
1080 {
1081 const char *pszForwarder = PE_RVA2TYPE(pvBits, uRvaExport, const char *);
1082
1083 /*
1084 * Parse and validate the string. We must make sure it's valid
1085 * UTF-8, so we restrict it to ASCII.
1086 */
1087 const char *pszEnd = RTStrEnd(pszForwarder, offForwarder - pThis->ExportDir.Size);
1088 if (pszEnd)
1089 {
1090 /* The module name. */
1091 char ch;
1092 uint32_t off = 0;
1093 while ((ch = pszForwarder[off]) != '.' && ch != '\0')
1094 {
1095 if (RT_UNLIKELY((uint8_t)ch >= 0x80))
1096 return VERR_LDR_BAD_FORWARDER;
1097 off++;
1098 }
1099 if (RT_UNLIKELY(ch != '.'))
1100 return VERR_LDR_BAD_FORWARDER;
1101 uint32_t const offDot = off;
1102 off++;
1103
1104 /* The function name or ordinal number. Ordinals starts with a hash. */
1105 uint32_t iImpOrdinal;
1106 if (pszForwarder[off] != '#')
1107 {
1108 iImpOrdinal = UINT32_MAX;
1109 while ((ch = pszForwarder[off]) != '\0')
1110 {
1111 if (RT_UNLIKELY((uint8_t)ch >= 0x80))
1112 return VERR_LDR_BAD_FORWARDER;
1113 off++;
1114 }
1115 if (RT_UNLIKELY(off == offDot + 1))
1116 return VERR_LDR_BAD_FORWARDER;
1117 }
1118 else
1119 {
1120 rc = RTStrToUInt32Full(&pszForwarder[off + 1], 10, &iImpOrdinal);
1121 if (RT_UNLIKELY(rc != VINF_SUCCESS || iImpOrdinal > UINT16_MAX))
1122 return VERR_LDR_BAD_FORWARDER;
1123 }
1124
1125 /*
1126 * Enough buffer?
1127 */
1128 uint32_t cbNeeded = RT_OFFSETOF(RTLDRIMPORTINFO, szModule[iImpOrdinal != UINT32_MAX ? offDot + 1 : off + 1]);
1129 if (cbNeeded > cbInfo)
1130 return VERR_BUFFER_OVERFLOW;
1131
1132 /*
1133 * Fill in the return buffer.
1134 */
1135 pInfo->iSelfOrdinal = iOrdinal;
1136 pInfo->iOrdinal = iImpOrdinal;
1137 if (iImpOrdinal == UINT32_MAX)
1138 {
1139 pInfo->pszSymbol = &pInfo->szModule[offDot + 1];
1140 memcpy(&pInfo->szModule[0], pszForwarder, off + 1);
1141 }
1142 else
1143 {
1144 pInfo->pszSymbol = NULL;
1145 memcpy(&pInfo->szModule[0], pszForwarder, offDot);
1146 }
1147 pInfo->szModule[offDot] = '\0';
1148 rc = VINF_SUCCESS;
1149 }
1150 else
1151 rc = VERR_LDR_BAD_FORWARDER;
1152 }
1153 else
1154 rc = VERR_LDR_NOT_FORWARDER;
1155 }
1156 return rc;
1157}
1158
1159
1160/**
1161 * Slow version of rtldrPEEnumSymbols that'll work without all of the image
1162 * being accessible.
1163 *
1164 * This is mainly for use in debuggers and similar.
1165 */
1166static int rtldrPEEnumSymbolsSlow(PRTLDRMODPE pThis, unsigned fFlags, RTUINTPTR BaseAddress,
1167 PFNRTLDRENUMSYMS pfnCallback, void *pvUser)
1168{
1169 /*
1170 * We enumerates by ordinal, which means using a slow linear search for
1171 * getting any name
1172 */
1173 PCIMAGE_EXPORT_DIRECTORY pExpDir = NULL;
1174 int rc = rtldrPEReadPartByRva(pThis, NULL, pThis->ExportDir.VirtualAddress, pThis->ExportDir.Size,
1175 (void const **)&pExpDir);
1176 if (RT_FAILURE(rc))
1177 return rc;
1178 uint32_t const cOrdinals = RT_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions);
1179
1180 uint32_t const *paAddress = NULL;
1181 rc = rtldrPEReadPartByRva(pThis, NULL, pExpDir->AddressOfFunctions, cOrdinals * sizeof(uint32_t),
1182 (void const **)&paAddress);
1183 uint32_t const *paRVANames = NULL;
1184 if (RT_SUCCESS(rc) && pExpDir->NumberOfNames)
1185 rc = rtldrPEReadPartByRva(pThis, NULL, pExpDir->AddressOfNames, pExpDir->NumberOfNames * sizeof(uint32_t),
1186 (void const **)&paRVANames);
1187 uint16_t const *paOrdinals = NULL;
1188 if (RT_SUCCESS(rc) && pExpDir->NumberOfNames)
1189 rc = rtldrPEReadPartByRva(pThis, NULL, pExpDir->AddressOfNameOrdinals, pExpDir->NumberOfNames * sizeof(uint16_t),
1190 (void const **)&paOrdinals);
1191 if (RT_SUCCESS(rc))
1192 {
1193 uint32_t uNamePrev = 0;
1194 for (uint32_t uOrdinal = 0; uOrdinal < cOrdinals; uOrdinal++)
1195 {
1196 if (paAddress[uOrdinal] /* needed? */)
1197 {
1198 /*
1199 * Look for name.
1200 */
1201 uint32_t uRvaName = UINT32_MAX;
1202 /* Search from previous + 1 to the end. */
1203 unsigned uName = uNamePrev + 1;
1204 while (uName < pExpDir->NumberOfNames)
1205 {
1206 if (paOrdinals[uName] == uOrdinal)
1207 {
1208 uRvaName = paRVANames[uName];
1209 uNamePrev = uName;
1210 break;
1211 }
1212 uName++;
1213 }
1214 if (uRvaName == UINT32_MAX)
1215 {
1216 /* Search from start to the previous. */
1217 uName = 0;
1218 for (uName = 0 ; uName <= uNamePrev; uName++)
1219 {
1220 if (paOrdinals[uName] == uOrdinal)
1221 {
1222 uRvaName = paRVANames[uName];
1223 uNamePrev = uName;
1224 break;
1225 }
1226 }
1227 }
1228
1229 /*
1230 * Get address.
1231 */
1232 uintptr_t uRVAExport = paAddress[uOrdinal];
1233 RTUINTPTR Value;
1234 if ( uRVAExport - (uintptr_t)pThis->ExportDir.VirtualAddress
1235 < pThis->ExportDir.Size)
1236 {
1237 if (!(fFlags & RTLDR_ENUM_SYMBOL_FLAGS_NO_FWD))
1238 {
1239 /* Resolve forwarder. */
1240 AssertMsgFailed(("Forwarders are not supported!\n"));
1241 }
1242 continue;
1243 }
1244
1245 /* Get plain export address */
1246 Value = PE_RVA2TYPE(BaseAddress, uRVAExport, RTUINTPTR);
1247
1248 /* Read in the name if found one. */
1249 char szAltName[32];
1250 const char *pszName = NULL;
1251 if (uRvaName != UINT32_MAX)
1252 {
1253 uint32_t cbName = 0x1000 - (uRvaName & 0xfff);
1254 if (cbName < 10 || cbName > 512)
1255 cbName = 128;
1256 rc = rtldrPEReadPartByRva(pThis, NULL, uRvaName, cbName, (void const **)&pszName);
1257 while (RT_SUCCESS(rc) && RTStrNLen(pszName, cbName) == cbName)
1258 {
1259 rtldrPEFreePart(pThis, NULL, pszName);
1260 pszName = NULL;
1261 if (cbName >= _4K)
1262 break;
1263 cbName += 128;
1264 rc = rtldrPEReadPartByRva(pThis, NULL, uRvaName, cbName, (void const **)&pszName);
1265 }
1266 }
1267 if (!pszName)
1268 {
1269 RTStrPrintf(szAltName, sizeof(szAltName), "Ordinal%#x", uOrdinal);
1270 pszName = szAltName;
1271 }
1272
1273 /*
1274 * Call back.
1275 */
1276 rc = pfnCallback(&pThis->Core, pszName, uOrdinal + pExpDir->Base, Value, pvUser);
1277 if (pszName != szAltName && pszName)
1278 rtldrPEFreePart(pThis, NULL, pszName);
1279 if (rc)
1280 break;
1281 }
1282 }
1283 }
1284
1285 rtldrPEFreePart(pThis, NULL, paOrdinals);
1286 rtldrPEFreePart(pThis, NULL, paRVANames);
1287 rtldrPEFreePart(pThis, NULL, paAddress);
1288 rtldrPEFreePart(pThis, NULL, pExpDir);
1289 return rc;
1290
1291}
1292
1293
1294/** @interface_method_impl{RTLDROPS,pfnEnumSymbols} */
1295static DECLCALLBACK(int) rtldrPEEnumSymbols(PRTLDRMODINTERNAL pMod, unsigned fFlags, const void *pvBits, RTUINTPTR BaseAddress,
1296 PFNRTLDRENUMSYMS pfnCallback, void *pvUser)
1297{
1298 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1299 NOREF(fFlags); /* ignored ... */
1300
1301 /*
1302 * Check if there is actually anything to work on.
1303 */
1304 if ( !pModPe->ExportDir.VirtualAddress
1305 || !pModPe->ExportDir.Size)
1306 return VERR_SYMBOL_NOT_FOUND;
1307
1308 /*
1309 * No bits supplied? Do we need to read the bits?
1310 */
1311 if (!pvBits)
1312 {
1313 if (!pModPe->pvBits)
1314 {
1315 int rc = rtldrPEReadBits(pModPe);
1316 if (RT_FAILURE(rc))
1317 return rtldrPEEnumSymbolsSlow(pModPe, fFlags, BaseAddress, pfnCallback, pvUser);
1318 }
1319 pvBits = pModPe->pvBits;
1320 }
1321
1322 /*
1323 * We enumerates by ordinal, which means using a slow linear search for
1324 * getting any name
1325 */
1326 PIMAGE_EXPORT_DIRECTORY pExpDir = PE_RVA2TYPE(pvBits, pModPe->ExportDir.VirtualAddress, PIMAGE_EXPORT_DIRECTORY);
1327 uint32_t *paAddress = PE_RVA2TYPE(pvBits, pExpDir->AddressOfFunctions, uint32_t *);
1328 uint32_t *paRVANames = PE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, uint32_t *);
1329 uint16_t *paOrdinals = PE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, uint16_t *);
1330 uint32_t uNamePrev = 0;
1331 unsigned cOrdinals = RT_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions);
1332 for (unsigned uOrdinal = 0; uOrdinal < cOrdinals; uOrdinal++)
1333 {
1334 if (paAddress[uOrdinal] /* needed? */)
1335 {
1336 /*
1337 * Look for name.
1338 */
1339 const char *pszName = NULL;
1340 /* Search from previous + 1 to the end. */
1341 uint32_t uName = uNamePrev + 1;
1342 while (uName < pExpDir->NumberOfNames)
1343 {
1344 if (paOrdinals[uName] == uOrdinal)
1345 {
1346 pszName = PE_RVA2TYPE(pvBits, paRVANames[uName], const char *);
1347 uNamePrev = uName;
1348 break;
1349 }
1350 uName++;
1351 }
1352 if (!pszName)
1353 {
1354 /* Search from start to the previous. */
1355 uName = 0;
1356 for (uName = 0 ; uName <= uNamePrev; uName++)
1357 {
1358 if (paOrdinals[uName] == uOrdinal)
1359 {
1360 pszName = PE_RVA2TYPE(pvBits, paRVANames[uName], const char *);
1361 uNamePrev = uName;
1362 break;
1363 }
1364 }
1365 }
1366
1367 /*
1368 * Get address.
1369 */
1370 uintptr_t uRVAExport = paAddress[uOrdinal];
1371 RTUINTPTR Value;
1372 if ( uRVAExport - (uintptr_t)pModPe->ExportDir.VirtualAddress
1373 < pModPe->ExportDir.Size)
1374 {
1375 if (!(fFlags & RTLDR_ENUM_SYMBOL_FLAGS_NO_FWD))
1376 {
1377 /* Resolve forwarder. */
1378 AssertMsgFailed(("Forwarders are not supported!\n"));
1379 }
1380 continue;
1381 }
1382
1383 /* Get plain export address */
1384 Value = PE_RVA2TYPE(BaseAddress, uRVAExport, RTUINTPTR);
1385
1386 /*
1387 * Call back.
1388 */
1389 int rc = pfnCallback(pMod, pszName, uOrdinal + pExpDir->Base, Value, pvUser);
1390 if (rc)
1391 return rc;
1392 }
1393 }
1394
1395 return VINF_SUCCESS;
1396}
1397
1398
1399/** @interface_method_impl{RTLDROPS,pfnEnumDbgInfo} */
1400static DECLCALLBACK(int) rtldrPE_EnumDbgInfo(PRTLDRMODINTERNAL pMod, const void *pvBits,
1401 PFNRTLDRENUMDBG pfnCallback, void *pvUser)
1402{
1403 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1404 int rc;
1405
1406 /*
1407 * Debug info directory empty?
1408 */
1409 if ( !pModPe->DebugDir.VirtualAddress
1410 || !pModPe->DebugDir.Size)
1411 return VINF_SUCCESS;
1412
1413 /*
1414 * Allocate temporary memory for a path buffer (this code is also compiled
1415 * and maybe even used in stack starved environments).
1416 */
1417 char *pszPath = (char *)RTMemTmpAlloc(RTPATH_MAX);
1418 if (!pszPath)
1419 return VERR_NO_TMP_MEMORY;
1420
1421 /*
1422 * Get the debug directory.
1423 */
1424 if (!pvBits)
1425 pvBits = pModPe->pvBits;
1426
1427 PCIMAGE_DEBUG_DIRECTORY paDbgDir;
1428 int rcRet = rtldrPEReadPartByRva(pModPe, pvBits, pModPe->DebugDir.VirtualAddress, pModPe->DebugDir.Size,
1429 (void const **)&paDbgDir);
1430 if (RT_FAILURE(rcRet))
1431 {
1432 RTMemTmpFree(pszPath);
1433 return rcRet;
1434 }
1435
1436 /*
1437 * Enumerate the debug directory.
1438 */
1439 uint32_t const cEntries = pModPe->DebugDir.Size / sizeof(paDbgDir[0]);
1440 for (uint32_t i = 0; i < cEntries; i++)
1441 {
1442 if (paDbgDir[i].PointerToRawData < pModPe->offEndOfHdrs)
1443 continue;
1444 if (paDbgDir[i].SizeOfData < 4)
1445 continue;
1446
1447 void const *pvPart = NULL;
1448 RTLDRDBGINFO DbgInfo;
1449 RT_ZERO(DbgInfo.u);
1450 DbgInfo.iDbgInfo = i;
1451 DbgInfo.offFile = paDbgDir[i].PointerToRawData;
1452 DbgInfo.LinkAddress = paDbgDir[i].AddressOfRawData < pModPe->cbImage
1453 && paDbgDir[i].AddressOfRawData >= pModPe->offEndOfHdrs
1454 ? paDbgDir[i].AddressOfRawData : NIL_RTLDRADDR;
1455 DbgInfo.cb = paDbgDir[i].SizeOfData;
1456 DbgInfo.pszExtFile = NULL;
1457
1458 rc = VINF_SUCCESS;
1459 switch (paDbgDir[i].Type)
1460 {
1461 case IMAGE_DEBUG_TYPE_CODEVIEW:
1462 DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW;
1463 DbgInfo.u.Cv.cbImage = pModPe->cbImage;
1464 DbgInfo.u.Cv.uMajorVer = paDbgDir[i].MajorVersion;
1465 DbgInfo.u.Cv.uMinorVer = paDbgDir[i].MinorVersion;
1466 DbgInfo.u.Cv.uTimestamp = paDbgDir[i].TimeDateStamp;
1467 if ( paDbgDir[i].SizeOfData < RTPATH_MAX
1468 && paDbgDir[i].SizeOfData > 16
1469 && ( DbgInfo.LinkAddress != NIL_RTLDRADDR
1470 || DbgInfo.offFile > 0)
1471 )
1472 {
1473 rc = rtldrPEReadPart(pModPe, pvBits, DbgInfo.offFile, DbgInfo.LinkAddress, paDbgDir[i].SizeOfData, &pvPart);
1474 if (RT_SUCCESS(rc))
1475 {
1476 PCCVPDB20INFO pCv20 = (PCCVPDB20INFO)pvPart;
1477 if ( pCv20->u32Magic == CVPDB20INFO_MAGIC
1478 && pCv20->offDbgInfo == 0
1479 && paDbgDir[i].SizeOfData > RT_UOFFSETOF(CVPDB20INFO, szPdbFilename) )
1480 {
1481 DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW_PDB20;
1482 DbgInfo.u.Pdb20.cbImage = pModPe->cbImage;
1483 DbgInfo.u.Pdb20.uTimestamp = pCv20->uTimestamp;
1484 DbgInfo.u.Pdb20.uAge = pCv20->uAge;
1485 DbgInfo.pszExtFile = (const char *)&pCv20->szPdbFilename[0];
1486 }
1487 else if ( pCv20->u32Magic == CVPDB70INFO_MAGIC
1488 && paDbgDir[i].SizeOfData > RT_UOFFSETOF(CVPDB70INFO, szPdbFilename) )
1489 {
1490 PCCVPDB70INFO pCv70 = (PCCVPDB70INFO)pCv20;
1491 DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW_PDB70;
1492 DbgInfo.u.Pdb70.cbImage = pModPe->cbImage;
1493 DbgInfo.u.Pdb70.Uuid = pCv70->PdbUuid;
1494 DbgInfo.u.Pdb70.uAge = pCv70->uAge;
1495 DbgInfo.pszExtFile = (const char *)&pCv70->szPdbFilename[0];
1496 }
1497 }
1498 else
1499 rcRet = rc;
1500 }
1501 break;
1502
1503 case IMAGE_DEBUG_TYPE_MISC:
1504 DbgInfo.enmType = RTLDRDBGINFOTYPE_UNKNOWN;
1505 if ( paDbgDir[i].SizeOfData < RTPATH_MAX
1506 && paDbgDir[i].SizeOfData > RT_UOFFSETOF(IMAGE_DEBUG_MISC, Data))
1507 {
1508 DbgInfo.enmType = RTLDRDBGINFOTYPE_CODEVIEW_DBG;
1509 DbgInfo.u.Dbg.cbImage = pModPe->cbImage;
1510 if (DbgInfo.LinkAddress != NIL_RTLDRADDR)
1511 DbgInfo.u.Dbg.uTimestamp = paDbgDir[i].TimeDateStamp;
1512 else
1513 DbgInfo.u.Dbg.uTimestamp = pModPe->uTimestamp; /* NT4 SP1 ntfs.sys hack. Generic? */
1514
1515 rc = rtldrPEReadPart(pModPe, pvBits, DbgInfo.offFile, DbgInfo.LinkAddress, paDbgDir[i].SizeOfData, &pvPart);
1516 if (RT_SUCCESS(rc))
1517 {
1518 PCIMAGE_DEBUG_MISC pMisc = (PCIMAGE_DEBUG_MISC)pvPart;
1519 if ( pMisc->DataType == IMAGE_DEBUG_MISC_EXENAME
1520 && pMisc->Length == paDbgDir[i].SizeOfData)
1521 {
1522 if (!pMisc->Unicode)
1523 DbgInfo.pszExtFile = (const char *)&pMisc->Data[0];
1524 else
1525 {
1526 rc = RTUtf16ToUtf8Ex((PCRTUTF16)&pMisc->Data[0],
1527 (pMisc->Length - RT_OFFSETOF(IMAGE_DEBUG_MISC, Data)) / sizeof(RTUTF16),
1528 &pszPath, RTPATH_MAX, NULL);
1529 if (RT_SUCCESS(rc))
1530 DbgInfo.pszExtFile = pszPath;
1531 else
1532 rcRet = rc; /* continue without a filename. */
1533 }
1534 }
1535 }
1536 else
1537 rcRet = rc; /* continue without a filename. */
1538 }
1539 break;
1540
1541 case IMAGE_DEBUG_TYPE_COFF:
1542 DbgInfo.enmType = RTLDRDBGINFOTYPE_COFF;
1543 DbgInfo.u.Coff.cbImage = pModPe->cbImage;
1544 DbgInfo.u.Coff.uMajorVer = paDbgDir[i].MajorVersion;
1545 DbgInfo.u.Coff.uMinorVer = paDbgDir[i].MinorVersion;
1546 DbgInfo.u.Coff.uTimestamp = paDbgDir[i].TimeDateStamp;
1547 break;
1548
1549 default:
1550 DbgInfo.enmType = RTLDRDBGINFOTYPE_UNKNOWN;
1551 break;
1552 }
1553
1554 /* Fix (hack) the file name encoding. We don't have Windows-1252 handy,
1555 so we'll be using Latin-1 as a reasonable approximation.
1556 (I don't think we know exactly which encoding this is anyway, as
1557 it's probably the current ANSI/Windows code page for the process
1558 generating the image anyways.) */
1559 if (DbgInfo.pszExtFile && DbgInfo.pszExtFile != pszPath)
1560 {
1561 rc = RTLatin1ToUtf8Ex(DbgInfo.pszExtFile,
1562 paDbgDir[i].SizeOfData - ((uintptr_t)DbgInfo.pszExtFile - (uintptr_t)pvBits),
1563 &pszPath, RTPATH_MAX, NULL);
1564 if (RT_FAILURE(rc))
1565 {
1566 rcRet = rc;
1567 DbgInfo.pszExtFile = NULL;
1568 }
1569 }
1570 if (DbgInfo.pszExtFile)
1571 RTPathChangeToUnixSlashes(pszPath, true /*fForce*/);
1572
1573 rc = pfnCallback(pMod, &DbgInfo, pvUser);
1574 rtldrPEFreePart(pModPe, pvBits, pvPart);
1575 if (rc != VINF_SUCCESS)
1576 {
1577 rcRet = rc;
1578 break;
1579 }
1580 }
1581
1582 rtldrPEFreePart(pModPe, pvBits, paDbgDir);
1583 RTMemTmpFree(pszPath);
1584 return rcRet;
1585}
1586
1587
1588/** @interface_method_impl{RTLDROPS,pfnEnumSegments} */
1589static DECLCALLBACK(int) rtldrPE_EnumSegments(PRTLDRMODINTERNAL pMod, PFNRTLDRENUMSEGS pfnCallback, void *pvUser)
1590{
1591 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1592 RTLDRSEG SegInfo;
1593
1594 /*
1595 * The first section is a fake one covering the headers.
1596 */
1597 SegInfo.pszName = "NtHdrs";
1598 SegInfo.cchName = 6;
1599 SegInfo.SelFlat = 0;
1600 SegInfo.Sel16bit = 0;
1601 SegInfo.fFlags = 0;
1602 SegInfo.fProt = RTMEM_PROT_READ;
1603 SegInfo.Alignment = 1;
1604 SegInfo.LinkAddress = pModPe->uImageBase;
1605 SegInfo.RVA = 0;
1606 SegInfo.offFile = 0;
1607 SegInfo.cb = pModPe->cbHeaders;
1608 SegInfo.cbFile = pModPe->cbHeaders;
1609 SegInfo.cbMapped = pModPe->cbHeaders;
1610 if ((pModPe->paSections[0].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
1611 SegInfo.cbMapped = pModPe->paSections[0].VirtualAddress;
1612 int rc = pfnCallback(pMod, &SegInfo, pvUser);
1613
1614 /*
1615 * Then all the normal sections.
1616 */
1617 PCIMAGE_SECTION_HEADER pSh = pModPe->paSections;
1618 for (uint32_t i = 0; i < pModPe->cSections && rc == VINF_SUCCESS; i++, pSh++)
1619 {
1620 char szName[32];
1621 SegInfo.pszName = (const char *)&pSh->Name[0];
1622 SegInfo.cchName = (uint32_t)RTStrNLen(SegInfo.pszName, sizeof(pSh->Name));
1623 if (SegInfo.cchName >= sizeof(pSh->Name))
1624 {
1625 memcpy(szName, &pSh->Name[0], sizeof(pSh->Name));
1626 szName[sizeof(pSh->Name)] = '\0';
1627 SegInfo.pszName = szName;
1628 }
1629 else if (SegInfo.cchName == 0)
1630 {
1631 SegInfo.pszName = szName;
1632 SegInfo.cchName = (uint32_t)RTStrPrintf(szName, sizeof(szName), "UnamedSect%02u", i);
1633 }
1634 SegInfo.SelFlat = 0;
1635 SegInfo.Sel16bit = 0;
1636 SegInfo.fFlags = 0;
1637 SegInfo.fProt = RTMEM_PROT_NONE;
1638 if (pSh->Characteristics & IMAGE_SCN_MEM_READ)
1639 SegInfo.fProt |= RTMEM_PROT_READ;
1640 if (pSh->Characteristics & IMAGE_SCN_MEM_WRITE)
1641 SegInfo.fProt |= RTMEM_PROT_WRITE;
1642 if (pSh->Characteristics & IMAGE_SCN_MEM_EXECUTE)
1643 SegInfo.fProt |= RTMEM_PROT_EXEC;
1644 SegInfo.Alignment = (pSh->Characteristics & IMAGE_SCN_ALIGN_MASK) >> IMAGE_SCN_ALIGN_SHIFT;
1645 if (SegInfo.Alignment > 0)
1646 SegInfo.Alignment = RT_BIT_64(SegInfo.Alignment - 1);
1647 if (pSh->Characteristics & IMAGE_SCN_TYPE_NOLOAD)
1648 {
1649 SegInfo.LinkAddress = NIL_RTLDRADDR;
1650 SegInfo.RVA = NIL_RTLDRADDR;
1651 SegInfo.cbMapped = pSh->Misc.VirtualSize;
1652 }
1653 else
1654 {
1655 SegInfo.LinkAddress = pSh->VirtualAddress + pModPe->uImageBase ;
1656 SegInfo.RVA = pSh->VirtualAddress;
1657 SegInfo.cbMapped = RT_ALIGN(SegInfo.cb, SegInfo.Alignment);
1658 if (i + 1 < pModPe->cSections && !(pSh[1].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
1659 SegInfo.cbMapped = pSh[1].VirtualAddress - pSh->VirtualAddress;
1660 }
1661 SegInfo.cb = pSh->Misc.VirtualSize;
1662 if (pSh->PointerToRawData == 0 || pSh->SizeOfRawData == 0)
1663 {
1664 SegInfo.offFile = -1;
1665 SegInfo.cbFile = 0;
1666 }
1667 else
1668 {
1669 SegInfo.offFile = pSh->PointerToRawData;
1670 SegInfo.cbFile = pSh->SizeOfRawData;
1671 }
1672
1673 rc = pfnCallback(pMod, &SegInfo, pvUser);
1674 }
1675
1676 return rc;
1677}
1678
1679
1680/** @interface_method_impl{RTLDROPS,pfnLinkAddressToSegOffset} */
1681static DECLCALLBACK(int) rtldrPE_LinkAddressToSegOffset(PRTLDRMODINTERNAL pMod, RTLDRADDR LinkAddress,
1682 uint32_t *piSeg, PRTLDRADDR poffSeg)
1683{
1684 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1685
1686 LinkAddress -= pModPe->uImageBase;
1687
1688 /* Special header segment. */
1689 if (LinkAddress < pModPe->paSections[0].VirtualAddress)
1690 {
1691 *piSeg = 0;
1692 *poffSeg = LinkAddress;
1693 return VINF_SUCCESS;
1694 }
1695
1696 /*
1697 * Search the normal sections. (Could do this in binary fashion, they're
1698 * sorted, but too much bother right now.)
1699 */
1700 if (LinkAddress > pModPe->cbImage)
1701 return VERR_LDR_INVALID_LINK_ADDRESS;
1702 uint32_t i = pModPe->cSections;
1703 PCIMAGE_SECTION_HEADER paShs = pModPe->paSections;
1704 while (i-- > 0)
1705 if (!(paShs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
1706 {
1707 uint32_t uAddr = paShs[i].VirtualAddress;
1708 if (LinkAddress >= uAddr)
1709 {
1710 *poffSeg = LinkAddress - uAddr;
1711 *piSeg = i + 1;
1712 return VINF_SUCCESS;
1713 }
1714 }
1715
1716 return VERR_LDR_INVALID_LINK_ADDRESS;
1717}
1718
1719
1720/** @interface_method_impl{RTLDROPS,pfnLinkAddressToRva} */
1721static DECLCALLBACK(int) rtldrPE_LinkAddressToRva(PRTLDRMODINTERNAL pMod, RTLDRADDR LinkAddress, PRTLDRADDR pRva)
1722{
1723 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1724
1725 LinkAddress -= pModPe->uImageBase;
1726 if (LinkAddress > pModPe->cbImage)
1727 return VERR_LDR_INVALID_LINK_ADDRESS;
1728 *pRva = LinkAddress;
1729
1730 return VINF_SUCCESS;
1731}
1732
1733
1734/** @interface_method_impl{RTLDROPS,pfnSegOffsetToRva} */
1735static DECLCALLBACK(int) rtldrPE_SegOffsetToRva(PRTLDRMODINTERNAL pMod, uint32_t iSeg, RTLDRADDR offSeg,
1736 PRTLDRADDR pRva)
1737{
1738 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1739
1740 if (iSeg > pModPe->cSections)
1741 return VERR_LDR_INVALID_SEG_OFFSET;
1742
1743 /** @todo should validate offSeg here... too lazy right now. */
1744 if (iSeg == 0)
1745 *pRva = offSeg;
1746 else if (pModPe->paSections[iSeg].Characteristics & IMAGE_SCN_TYPE_NOLOAD)
1747 return VERR_LDR_INVALID_SEG_OFFSET;
1748 else
1749 *pRva = offSeg + pModPe->paSections[iSeg].VirtualAddress;
1750 return VINF_SUCCESS;
1751}
1752
1753
1754/** @interface_method_impl{RTLDROPS,pfnRvaToSegOffset} */
1755static DECLCALLBACK(int) rtldrPE_RvaToSegOffset(PRTLDRMODINTERNAL pMod, RTLDRADDR Rva,
1756 uint32_t *piSeg, PRTLDRADDR poffSeg)
1757{
1758 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1759 int rc = rtldrPE_LinkAddressToSegOffset(pMod, Rva + pModPe->uImageBase, piSeg, poffSeg);
1760 if (RT_FAILURE(rc))
1761 rc = VERR_LDR_INVALID_RVA;
1762 return rc;
1763}
1764
1765
1766/**
1767 * Worker for rtLdrPE_QueryProp and rtLdrPE_QueryImportModule that counts the
1768 * number of imports, storing the result in RTLDRMODPE::cImports.
1769 *
1770 * @returns IPRT status code.
1771 * @param pThis The PE module instance.
1772 * @param pvBits Image bits if the caller had them available, NULL if
1773 * not. Saves a couple of file accesses.
1774 */
1775static int rtLdrPE_CountImports(PRTLDRMODPE pThis, void const *pvBits)
1776{
1777 PCIMAGE_IMPORT_DESCRIPTOR paImpDescs;
1778 int rc = rtldrPEReadPartByRva(pThis, pvBits, pThis->ImportDir.VirtualAddress, pThis->ImportDir.Size,
1779 (void const **)&paImpDescs);
1780 if (RT_SUCCESS(rc))
1781 {
1782 uint32_t const cMax = pThis->ImportDir.Size / sizeof(IMAGE_IMPORT_DESCRIPTOR);
1783 uint32_t i = 0;
1784 while ( i < cMax
1785 && paImpDescs[i].Name > pThis->offNtHdrs
1786 && paImpDescs[i].Name < pThis->cbImage
1787 && paImpDescs[i].FirstThunk > pThis->offNtHdrs
1788 && paImpDescs[i].FirstThunk < pThis->cbImage)
1789 i++;
1790 pThis->cImports = i;
1791
1792 rtldrPEFreePart(pThis, pvBits, paImpDescs);
1793 }
1794 return rc;
1795}
1796
1797
1798/**
1799 * Worker for rtLdrPE_QueryProp that retrievs the name of an import DLL.
1800 *
1801 * @returns IPRT status code. If VERR_BUFFER_OVERFLOW, pcbBuf is required size.
1802 * @param pThis The PE module instance.
1803 * @param pvBits Image bits if the caller had them available, NULL if
1804 * not. Saves a couple of file accesses.
1805 * @param iImport The index of the import table descriptor to fetch
1806 * the name from.
1807 * @param pvBuf The output buffer.
1808 * @param cbBuf The buffer size.
1809 * @param pcbRet Where to return the number of bytes we've returned
1810 * (or in case of VERR_BUFFER_OVERFLOW would have).
1811 */
1812static int rtLdrPE_QueryImportModule(PRTLDRMODPE pThis, void const *pvBits, uint32_t iImport,
1813 void *pvBuf, size_t cbBuf, size_t *pcbRet)
1814{
1815 /*
1816 * Make sure we got the import count.
1817 */
1818 int rc;
1819 if (pThis->cImports == UINT32_MAX)
1820 {
1821 rc = rtLdrPE_CountImports(pThis, pvBits);
1822 if (RT_FAILURE(rc))
1823 return rc;
1824 }
1825
1826 /*
1827 * Check the index first, converting it to an RVA.
1828 */
1829 if (iImport < pThis->cImports)
1830 {
1831 uint32_t offEntry = iImport * sizeof(IMAGE_IMPORT_DESCRIPTOR) + pThis->ImportDir.VirtualAddress;
1832
1833 /*
1834 * Retrieve the import table descriptor.
1835 */
1836 PCIMAGE_IMPORT_DESCRIPTOR pImpDesc;
1837 rc = rtldrPEReadPartByRva(pThis, pvBits, offEntry, sizeof(*pImpDesc), (void const **)&pImpDesc);
1838 if (RT_SUCCESS(rc))
1839 {
1840 if ( pImpDesc->Name >= pThis->cbHeaders
1841 && pImpDesc->Name < pThis->cbImage)
1842 {
1843 /*
1844 * Limit the name to 1024 bytes (more than enough for everyone).
1845 */
1846 uint32_t cchNameMax = pThis->cbImage - pImpDesc->Name;
1847 if (cchNameMax > 1024)
1848 cchNameMax = 1024;
1849 char *pszName;
1850 rc = rtldrPEReadPartByRva(pThis, pvBits, pImpDesc->Name, cchNameMax, (void const **)&pszName);
1851 if (RT_SUCCESS(rc))
1852 {
1853 /*
1854 * Make sure it's null terminated and valid UTF-8 encoding.
1855 *
1856 * Which encoding this really is isn't defined, I think,
1857 * but we need to make sure we don't get bogus UTF-8 into
1858 * the process, so making sure it's valid UTF-8 is a good
1859 * as anything else since it covers ASCII.
1860 */
1861 size_t cchName = RTStrNLen(pszName, cchNameMax);
1862 if (cchName < cchNameMax)
1863 {
1864 rc = RTStrValidateEncodingEx(pszName, cchName, 0 /*fFlags*/);
1865 if (RT_SUCCESS(rc))
1866 {
1867 /*
1868 * Copy out the result and we're done.
1869 * (We have to do all the cleanup code though, so no return success here.)
1870 */
1871 *pcbRet = cchName + 1;
1872 if (cbBuf >= cchName + 1)
1873 memcpy(pvBuf, pszName, cchName + 1);
1874 else
1875 rc = VERR_BUFFER_OVERFLOW;
1876 }
1877 }
1878 else
1879 rc = VERR_BAD_EXE_FORMAT;
1880 rtldrPEFreePart(pThis, pvBits, pszName);
1881 }
1882 }
1883 else
1884 rc = VERR_BAD_EXE_FORMAT;
1885 rtldrPEFreePart(pThis, pvBits, pImpDesc);
1886 }
1887 }
1888 else
1889 rc = VERR_NOT_FOUND;
1890
1891 if (RT_SUCCESS(rc))
1892 return VINF_SUCCESS;
1893
1894 *pcbRet = 0;
1895 return rc;
1896}
1897
1898
1899/** @interface_method_impl{RTLDROPS,pfnQueryProp} */
1900static DECLCALLBACK(int) rtldrPE_QueryProp(PRTLDRMODINTERNAL pMod, RTLDRPROP enmProp, void const *pvBits,
1901 void *pvBuf, size_t cbBuf, size_t *pcbRet)
1902{
1903 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
1904 switch (enmProp)
1905 {
1906 case RTLDRPROP_TIMESTAMP_SECONDS:
1907 Assert(*pcbRet == cbBuf);
1908 if (cbBuf == sizeof(int32_t))
1909 *(int32_t *)pvBuf = pModPe->uTimestamp;
1910 else if (cbBuf == sizeof(int64_t))
1911 *(int64_t *)pvBuf = pModPe->uTimestamp;
1912 else
1913 AssertFailedReturn(VERR_INTERNAL_ERROR_3);
1914 break;
1915
1916 case RTLDRPROP_IS_SIGNED:
1917 Assert(cbBuf == sizeof(bool));
1918 Assert(*pcbRet == cbBuf);
1919 *(bool *)pvBuf = pModPe->offPkcs7SignedData != 0;
1920 break;
1921
1922 case RTLDRPROP_PKCS7_SIGNED_DATA:
1923 {
1924 if (pModPe->cbPkcs7SignedData == 0)
1925 return VERR_NOT_FOUND;
1926 Assert(pModPe->offPkcs7SignedData > pModPe->SecurityDir.VirtualAddress);
1927
1928 *pcbRet = pModPe->cbPkcs7SignedData;
1929 if (cbBuf < pModPe->cbPkcs7SignedData)
1930 return VERR_BUFFER_OVERFLOW;
1931 return pModPe->Core.pReader->pfnRead(pModPe->Core.pReader, pvBuf, pModPe->cbPkcs7SignedData,
1932 pModPe->offPkcs7SignedData);
1933 }
1934
1935 case RTLDRPROP_SIGNATURE_CHECKS_ENFORCED:
1936 Assert(cbBuf == sizeof(bool));
1937 Assert(*pcbRet == cbBuf);
1938 *(bool *)pvBuf = pModPe->offPkcs7SignedData > 0
1939 && (pModPe->fDllCharacteristics & IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY);
1940 break;
1941
1942 case RTLDRPROP_IMPORT_COUNT:
1943 Assert(cbBuf == sizeof(uint32_t));
1944 Assert(*pcbRet == cbBuf);
1945 if (pModPe->cImports == UINT32_MAX)
1946 {
1947 int rc = rtLdrPE_CountImports(pModPe, pvBits);
1948 if (RT_FAILURE(rc))
1949 return rc;
1950 }
1951 *(uint32_t *)pvBuf = pModPe->cImports;
1952 break;
1953
1954
1955 case RTLDRPROP_IMPORT_MODULE:
1956 Assert(cbBuf >= sizeof(uint32_t));
1957 return rtLdrPE_QueryImportModule(pModPe, pvBits, *(uint32_t *)pvBuf, pvBuf, cbBuf, pcbRet);
1958
1959 default:
1960 return VERR_NOT_FOUND;
1961 }
1962 return VINF_SUCCESS;
1963}
1964
1965
1966
1967/*
1968 * Lots of Authenticode fun ahead.
1969 */
1970
1971
1972/**
1973 * Initializes the hash context.
1974 *
1975 * @returns VINF_SUCCESS or VERR_NOT_SUPPORTED.
1976 * @param pHashCtx The hash context union.
1977 * @param enmDigest The hash type we're calculating..
1978 */
1979static int rtLdrPE_HashInit(PRTLDRPEHASHCTXUNION pHashCtx, RTDIGESTTYPE enmDigest)
1980{
1981 switch (enmDigest)
1982 {
1983 case RTDIGESTTYPE_SHA512: RTSha512Init(&pHashCtx->Sha512); break;
1984 case RTDIGESTTYPE_SHA256: RTSha256Init(&pHashCtx->Sha256); break;
1985 case RTDIGESTTYPE_SHA1: RTSha1Init(&pHashCtx->Sha1); break;
1986 case RTDIGESTTYPE_MD5: RTMd5Init(&pHashCtx->Md5); break;
1987 default: AssertFailedReturn(VERR_NOT_SUPPORTED);
1988 }
1989 return VINF_SUCCESS;
1990}
1991
1992
1993/**
1994 * Updates the hash with more data.
1995 *
1996 * @param pHashCtx The hash context union.
1997 * @param enmDigest The hash type we're calculating..
1998 * @param pvBuf Pointer to a buffer with bytes to add to thash.
1999 * @param cbBuf How many bytes to add from @a pvBuf.
2000 */
2001static void rtLdrPE_HashUpdate(PRTLDRPEHASHCTXUNION pHashCtx, RTDIGESTTYPE enmDigest, void const *pvBuf, size_t cbBuf)
2002{
2003 switch (enmDigest)
2004 {
2005 case RTDIGESTTYPE_SHA512: RTSha512Update(&pHashCtx->Sha512, pvBuf, cbBuf); break;
2006 case RTDIGESTTYPE_SHA256: RTSha256Update(&pHashCtx->Sha256, pvBuf, cbBuf); break;
2007 case RTDIGESTTYPE_SHA1: RTSha1Update(&pHashCtx->Sha1, pvBuf, cbBuf); break;
2008 case RTDIGESTTYPE_MD5: RTMd5Update(&pHashCtx->Md5, pvBuf, cbBuf); break;
2009 default: AssertReleaseFailed();
2010 }
2011}
2012
2013
2014/**
2015 * Finalizes the hash calculations.
2016 *
2017 * @param pHashCtx The hash context union.
2018 * @param enmDigest The hash type we're calculating..
2019 * @param pHashRes The hash result union.
2020 */
2021static void rtLdrPE_HashFinalize(PRTLDRPEHASHCTXUNION pHashCtx, RTDIGESTTYPE enmDigest, PRTLDRPEHASHRESUNION pHashRes)
2022{
2023 switch (enmDigest)
2024 {
2025 case RTDIGESTTYPE_SHA512: RTSha512Final(&pHashCtx->Sha512, pHashRes->abSha512); break;
2026 case RTDIGESTTYPE_SHA256: RTSha256Final(&pHashCtx->Sha256, pHashRes->abSha256); break;
2027 case RTDIGESTTYPE_SHA1: RTSha1Final(&pHashCtx->Sha1, pHashRes->abSha1); break;
2028 case RTDIGESTTYPE_MD5: RTMd5Final(pHashRes->abMd5, &pHashCtx->Md5); break;
2029 default: AssertReleaseFailed();
2030 }
2031}
2032
2033
2034/**
2035 * Returns the digest size for the given digest type.
2036 *
2037 * @returns Size in bytes.
2038 * @param enmDigest The hash type in question.
2039 */
2040static uint32_t rtLdrPE_HashGetHashSize(RTDIGESTTYPE enmDigest)
2041{
2042 switch (enmDigest)
2043 {
2044 case RTDIGESTTYPE_SHA512: return RTSHA512_HASH_SIZE;
2045 case RTDIGESTTYPE_SHA256: return RTSHA256_HASH_SIZE;
2046 case RTDIGESTTYPE_SHA1: return RTSHA1_HASH_SIZE;
2047 case RTDIGESTTYPE_MD5: return RTMD5_HASH_SIZE;
2048 default: AssertReleaseFailedReturn(0);
2049 }
2050}
2051
2052
2053/**
2054 * Calculate the special too watch out for when hashing the image.
2055 *
2056 * @returns IPRT status code.
2057 * @param pModPe The PE module.
2058 * @param pPlaces The structure where to store the special places.
2059 * @param pErrInfo Optional error info.
2060 */
2061static int rtldrPe_CalcSpecialHashPlaces(PRTLDRMODPE pModPe, PRTLDRPEHASHSPECIALS pPlaces, PRTERRINFO pErrInfo)
2062{
2063 /*
2064 * If we're here despite a missing signature, we need to get the file size.
2065 */
2066 pPlaces->cbToHash = pModPe->SecurityDir.VirtualAddress;
2067 if (pPlaces->cbToHash == 0)
2068 {
2069 RTFOFF cbFile = pModPe->Core.pReader->pfnSize(pModPe->Core.pReader);
2070 pPlaces->cbToHash = (uint32_t)cbFile;
2071 if (pPlaces->cbToHash != (RTFOFF)cbFile)
2072 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_FILE_LENGTH_ERROR, "File is too large: %RTfoff", cbFile);
2073 }
2074
2075 /*
2076 * Calculate the special places.
2077 */
2078 pPlaces->offCksum = (uint32_t)pModPe->offNtHdrs
2079 + (pModPe->f64Bit
2080 ? RT_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.CheckSum)
2081 : RT_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.CheckSum));
2082 pPlaces->cbCksum = RT_SIZEOFMEMB(IMAGE_NT_HEADERS32, OptionalHeader.CheckSum);
2083 pPlaces->offSecDir = (uint32_t)pModPe->offNtHdrs
2084 + (pModPe->f64Bit
2085 ? RT_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY])
2086 : RT_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]));
2087 pPlaces->cbSecDir = sizeof(IMAGE_DATA_DIRECTORY);
2088 pPlaces->offEndSpecial = pPlaces->offSecDir + pPlaces->cbSecDir;
2089 return VINF_SUCCESS;
2090}
2091
2092
2093/**
2094 * Calculates the whole image hash.
2095 *
2096 * The Authenticode_PE.docx version 1.0 explains how the hash is calculated,
2097 * points 8 thru 14 are bogus. If you study them a little carefully, it is
2098 * clear that the algorithm will only work if the raw data for the section have
2099 * no gaps between them or in front of them. So, this elaborate section sorting
2100 * by PointerToRawData and working them section by section could simply be
2101 * replaced by one point:
2102 *
2103 * 8. Add all the file content between SizeOfHeaders and the
2104 * attribute certificate table to the hash. Then finalize
2105 * the hash.
2106 *
2107 * Not sure if Microsoft is screwing with us on purpose here or whether they
2108 * assigned some of this work to less talented engineers and tech writers. I
2109 * love fact that they say it's "simplified" and should yield the correct hash
2110 * for "almost all" files. Stupid, Stupid, Microsofties!!
2111 *
2112 * My simplified implementation that just hashes the entire file up to the
2113 * signature or end of the file produces the same SHA1 values as "signtool
2114 * verify /v" does both for edited executables with gaps between/before/after
2115 * sections raw data and normal executables without any gaps.
2116 *
2117 * @returns IPRT status code.
2118 * @param pModPe The PE module.
2119 * @param pvScratch Scratch buffer.
2120 * @param cbScratch Size of the scratch buffer.
2121 * @param enmDigest The hash digest type we're calculating.
2122 * @param pHashCtx Hash context scratch area.
2123 * @param pHashRes Hash result buffer.
2124 * @param pErrInfo Optional error info buffer.
2125 */
2126static int rtldrPE_HashImageCommon(PRTLDRMODPE pModPe, void *pvScratch, uint32_t cbScratch, RTDIGESTTYPE enmDigest,
2127 PRTLDRPEHASHCTXUNION pHashCtx, PRTLDRPEHASHRESUNION pHashRes, PRTERRINFO pErrInfo)
2128{
2129 int rc = rtLdrPE_HashInit(pHashCtx, enmDigest);
2130 if (RT_FAILURE(rc))
2131 return rc;
2132
2133 /*
2134 * Calculate the special places.
2135 */
2136 RTLDRPEHASHSPECIALS SpecialPlaces = { 0, 0, 0, 0, 0, 0 }; /* shut up gcc */
2137 rc = rtldrPe_CalcSpecialHashPlaces(pModPe, &SpecialPlaces, pErrInfo);
2138 if (RT_FAILURE(rc))
2139 return rc;
2140
2141 /*
2142 * Work our way thru the image data.
2143 */
2144 uint32_t off = 0;
2145 while (off < SpecialPlaces.cbToHash)
2146 {
2147 uint32_t cbRead = RT_MIN(SpecialPlaces.cbToHash - off, cbScratch);
2148 uint8_t *pbCur = (uint8_t *)pvScratch;
2149 rc = pModPe->Core.pReader->pfnRead(pModPe->Core.pReader, pbCur, cbRead, off);
2150 if (RT_FAILURE(rc))
2151 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_READ_ERROR_HASH, "Hash read error at %#x: %Rrc (cbRead=%#zx)",
2152 off, rc, cbRead);
2153
2154 if (off < SpecialPlaces.offEndSpecial)
2155 {
2156 if (off < SpecialPlaces.offCksum)
2157 {
2158 /* Hash everything up to the checksum. */
2159 uint32_t cbChunk = RT_MIN(SpecialPlaces.offCksum - off, cbRead);
2160 rtLdrPE_HashUpdate(pHashCtx, enmDigest, pbCur, cbChunk);
2161 pbCur += cbChunk;
2162 cbRead -= cbChunk;
2163 off += cbChunk;
2164 }
2165
2166 if (off < SpecialPlaces.offCksum + SpecialPlaces.cbCksum && off >= SpecialPlaces.offCksum)
2167 {
2168 /* Skip the checksum */
2169 uint32_t cbChunk = RT_MIN(SpecialPlaces.offCksum + SpecialPlaces.cbCksum - off, cbRead);
2170 pbCur += cbChunk;
2171 cbRead -= cbChunk;
2172 off += cbChunk;
2173 }
2174
2175 if (off < SpecialPlaces.offSecDir && off >= SpecialPlaces.offCksum + SpecialPlaces.cbCksum)
2176 {
2177 /* Hash everything between the checksum and the data dir entry. */
2178 uint32_t cbChunk = RT_MIN(SpecialPlaces.offSecDir - off, cbRead);
2179 rtLdrPE_HashUpdate(pHashCtx, enmDigest, pbCur, cbChunk);
2180 pbCur += cbChunk;
2181 cbRead -= cbChunk;
2182 off += cbChunk;
2183 }
2184
2185 if (off < SpecialPlaces.offSecDir + SpecialPlaces.cbSecDir && off >= SpecialPlaces.offSecDir)
2186 {
2187 /* Skip the security data directory entry. */
2188 uint32_t cbChunk = RT_MIN(SpecialPlaces.offSecDir + SpecialPlaces.cbSecDir - off, cbRead);
2189 pbCur += cbChunk;
2190 cbRead -= cbChunk;
2191 off += cbChunk;
2192 }
2193 }
2194
2195 rtLdrPE_HashUpdate(pHashCtx, enmDigest, pbCur, cbRead);
2196
2197 /* Advance */
2198 off += cbRead;
2199 }
2200
2201 /*
2202 * If there isn't a signature, experiments with signtool indicates that we
2203 * have to zero padd the file size until it's a multiple of 8. (This is
2204 * most likely to give 64-bit values in the certificate a natural alignment
2205 * when memory mapped.)
2206 */
2207 if ( pModPe->SecurityDir.Size != SpecialPlaces.cbToHash
2208 && SpecialPlaces.cbToHash != RT_ALIGN_32(SpecialPlaces.cbToHash, WIN_CERTIFICATE_ALIGNMENT))
2209 {
2210 static const uint8_t s_abZeros[WIN_CERTIFICATE_ALIGNMENT] = { 0,0,0,0, 0,0,0,0 };
2211 rtLdrPE_HashUpdate(pHashCtx, enmDigest, s_abZeros,
2212 RT_ALIGN_32(SpecialPlaces.cbToHash, WIN_CERTIFICATE_ALIGNMENT) - SpecialPlaces.cbToHash);
2213 }
2214
2215 /*
2216 * Done. Finalize the hashes.
2217 */
2218 rtLdrPE_HashFinalize(pHashCtx, enmDigest, pHashRes);
2219 return VINF_SUCCESS;
2220}
2221
2222#ifndef IPRT_WITHOUT_LDR_VERIFY
2223
2224/**
2225 * Verifies image preconditions not checked by the open validation code.
2226 *
2227 * @returns IPRT status code.
2228 * @param pModPe The PE module.
2229 * @param pErrInfo Optional error info buffer.
2230 */
2231static int rtldrPE_VerifySignatureImagePrecoditions(PRTLDRMODPE pModPe, PRTERRINFO pErrInfo)
2232{
2233 /*
2234 * Validate the sections. While doing so, track the amount of section raw
2235 * section data in the file so we can use this to validate the signature
2236 * table location later.
2237 */
2238 uint32_t offNext = pModPe->cbHeaders; /* same */
2239 for (uint32_t i = 0; i < pModPe->cSections; i++)
2240 if (pModPe->paSections[i].SizeOfRawData > 0)
2241 {
2242 uint64_t offEnd = (uint64_t)pModPe->paSections[i].PointerToRawData + pModPe->paSections[i].SizeOfRawData;
2243 if (offEnd > offNext)
2244 {
2245 if (offEnd >= _2G)
2246 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_SECTION_RAW_DATA_VALUES,
2247 "Section %#u specifies file data after 2GB: PointerToRawData=%#x SizeOfRawData=%#x",
2248 i, pModPe->paSections[i].PointerToRawData, pModPe->paSections[i].SizeOfRawData);
2249 offNext = (uint32_t)offEnd;
2250 }
2251 }
2252 uint32_t offEndOfSectionData = offNext;
2253
2254 /*
2255 * Validate the signature.
2256 */
2257 if (!pModPe->SecurityDir.Size)
2258 return RTErrInfoSet(pErrInfo, VERR_LDRVI_NOT_SIGNED, "Not signed.");
2259
2260 uint32_t const offSignature = pModPe->SecurityDir.VirtualAddress;
2261 uint32_t const cbSignature = pModPe->SecurityDir.Size;
2262 if ( cbSignature <= sizeof(WIN_CERTIFICATE)
2263 || cbSignature >= RTLDRMODPE_MAX_SECURITY_DIR_SIZE
2264 || offSignature >= _2G)
2265 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_INVALID_SECURITY_DIR_ENTRY,
2266 "Invalid security data dir entry: cb=%#x off=%#x", cbSignature, offSignature);
2267
2268 if (offSignature < offEndOfSectionData)
2269 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_INVALID_SECURITY_DIR_ENTRY,
2270 "Invalid security data dir entry offset: %#x offEndOfSectionData=%#x",
2271 offSignature, offEndOfSectionData);
2272
2273 if (RT_ALIGN_32(offSignature, WIN_CERTIFICATE_ALIGNMENT) != offSignature)
2274 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_INVALID_SECURITY_DIR_ENTRY,
2275 "Misaligned security dir entry offset: %#x (alignment=%#x)",
2276 offSignature, WIN_CERTIFICATE_ALIGNMENT);
2277
2278
2279 return VINF_SUCCESS;
2280}
2281
2282
2283/**
2284 * Reads and checks the raw signature data.
2285 *
2286 * @returns IPRT status code.
2287 * @param pModPe The PE module.
2288 * @param ppSignature Where to return the pointer to the parsed
2289 * signature data. Pass to
2290 * rtldrPE_VerifySignatureDestroy when done.
2291 * @param pErrInfo Optional error info buffer.
2292 */
2293static int rtldrPE_VerifySignatureRead(PRTLDRMODPE pModPe, PRTLDRPESIGNATURE *ppSignature, PRTERRINFO pErrInfo)
2294{
2295 *ppSignature = NULL;
2296 AssertReturn(pModPe->SecurityDir.Size > 0, VERR_INTERNAL_ERROR_2);
2297
2298 /*
2299 * Allocate memory for reading and parsing it.
2300 */
2301 if (pModPe->SecurityDir.Size >= RTLDRMODPE_MAX_SECURITY_DIR_SIZE)
2302 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_INVALID_SECURITY_DIR_ENTRY,
2303 "Signature directory is to large: %#x", pModPe->SecurityDir.Size);
2304
2305 PRTLDRPESIGNATURE pSignature = (PRTLDRPESIGNATURE)RTMemTmpAllocZ(sizeof(*pSignature) + 64 + pModPe->SecurityDir.Size);
2306 if (!pSignature)
2307 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_NO_MEMORY_SIGNATURE, "Failed to allocate %zu bytes",
2308 sizeof(*pSignature) + 64 + pModPe->SecurityDir.Size);
2309 pSignature->pRawData = RT_ALIGN_PT(pSignature + 1, 64, WIN_CERTIFICATE const *);
2310
2311
2312 /*
2313 * Read it.
2314 */
2315 int rc = pModPe->Core.pReader->pfnRead(pModPe->Core.pReader, (void *)pSignature->pRawData,
2316 pModPe->SecurityDir.Size, pModPe->SecurityDir.VirtualAddress);
2317 if (RT_SUCCESS(rc))
2318 {
2319 /*
2320 * Check the table we've read in.
2321 */
2322 uint32_t cbLeft = pModPe->SecurityDir.Size;
2323 WIN_CERTIFICATE const *pEntry = pSignature->pRawData;
2324 for (;;)
2325 {
2326 if ( cbLeft < sizeof(*pEntry)
2327 || pEntry->dwLength > cbLeft
2328 || pEntry->dwLength < sizeof(*pEntry))
2329 rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_HDR_LENGTH,
2330 "Bad WIN_CERTIFICATE length: %#x (max %#x, signature=%u)",
2331 pEntry->dwLength, cbLeft, 0);
2332 else if (pEntry->wRevision != WIN_CERT_REVISION_2_0)
2333 rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_HDR_REVISION,
2334 "Unsupported WIN_CERTIFICATE revision value: %#x (signature=%u)",
2335 pEntry->wRevision, 0);
2336 else if (pEntry->wCertificateType != WIN_CERT_TYPE_PKCS_SIGNED_DATA)
2337 rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_HDR_TYPE,
2338 "Unsupported WIN_CERTIFICATE certificate type: %#x (signature=%u)",
2339 pEntry->wCertificateType, 0);
2340 else
2341 {
2342 /* advance */
2343 uint32_t cbEntry = RT_ALIGN(pEntry->dwLength, WIN_CERTIFICATE_ALIGNMENT);
2344 if (cbEntry >= cbLeft)
2345 break;
2346 cbLeft -= cbEntry;
2347 pEntry = (WIN_CERTIFICATE *)((uintptr_t)pEntry + cbEntry);
2348
2349 /* For now, only one entry is supported. */
2350 rc = RTErrInfoSet(pErrInfo, VERR_LDRVI_BAD_CERT_MULTIPLE, "Multiple WIN_CERTIFICATE entries are not supported.");
2351 }
2352 break;
2353 }
2354 if (RT_SUCCESS(rc))
2355 {
2356 *ppSignature = pSignature;
2357 return VINF_SUCCESS;
2358 }
2359 }
2360 else
2361 rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_READ_ERROR_SIGNATURE, "Signature read error: %Rrc", rc);
2362 RTMemTmpFree(pSignature);
2363 return rc;
2364}
2365
2366
2367/**
2368 * Destroys the parsed signature.
2369 *
2370 * @param pModPe The PE module.
2371 * @param pSignature The signature data to destroy.
2372 */
2373static void rtldrPE_VerifySignatureDestroy(PRTLDRMODPE pModPe, PRTLDRPESIGNATURE pSignature)
2374{
2375 RTCrPkcs7ContentInfo_Delete(&pSignature->ContentInfo);
2376 RTMemTmpFree(pSignature);
2377}
2378
2379
2380/**
2381 * Decodes the raw signature.
2382 *
2383 * @returns IPRT status code.
2384 * @param pModPe The PE module.
2385 * @param pSignature The signature data.
2386 * @param pErrInfo Optional error info buffer.
2387 */
2388static int rtldrPE_VerifySignatureDecode(PRTLDRMODPE pModPe, PRTLDRPESIGNATURE pSignature, PRTERRINFO pErrInfo)
2389{
2390 WIN_CERTIFICATE const *pEntry = pSignature->pRawData;
2391 AssertReturn(pEntry->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA, VERR_INTERNAL_ERROR_2);
2392 AssertReturn(pEntry->wRevision == WIN_CERT_REVISION_2_0, VERR_INTERNAL_ERROR_2);
2393
2394 RTASN1CURSORPRIMARY PrimaryCursor;
2395 RTAsn1CursorInitPrimary(&PrimaryCursor,
2396 &pEntry->bCertificate[0],
2397 pEntry->dwLength - RT_OFFSETOF(WIN_CERTIFICATE, bCertificate),
2398 pErrInfo,
2399 &g_RTAsn1DefaultAllocator,
2400 0,
2401 "WinCert");
2402
2403 int rc = RTCrPkcs7ContentInfo_DecodeAsn1(&PrimaryCursor.Cursor, 0, &pSignature->ContentInfo, "CI");
2404 if (RT_SUCCESS(rc))
2405 {
2406 if (RTCrPkcs7ContentInfo_IsSignedData(&pSignature->ContentInfo))
2407 {
2408 pSignature->pSignedData = pSignature->ContentInfo.u.pSignedData;
2409
2410 /*
2411 * Decode the authenticode bits.
2412 */
2413 if (!strcmp(pSignature->pSignedData->ContentInfo.ContentType.szObjId, RTCRSPCINDIRECTDATACONTENT_OID))
2414 {
2415 pSignature->pIndData = pSignature->pSignedData->ContentInfo.u.pIndirectDataContent;
2416 Assert(pSignature->pIndData);
2417
2418 /*
2419 * Check that things add up.
2420 */
2421 if (RT_SUCCESS(rc))
2422 rc = RTCrPkcs7SignedData_CheckSanity(pSignature->pSignedData,
2423 RTCRPKCS7SIGNEDDATA_SANITY_F_AUTHENTICODE
2424 | RTCRPKCS7SIGNEDDATA_SANITY_F_ONLY_KNOWN_HASH
2425 | RTCRPKCS7SIGNEDDATA_SANITY_F_SIGNING_CERT_PRESENT,
2426 pErrInfo, "SD");
2427 if (RT_SUCCESS(rc))
2428 rc = RTCrSpcIndirectDataContent_CheckSanityEx(pSignature->pIndData,
2429 pSignature->pSignedData,
2430 RTCRSPCINDIRECTDATACONTENT_SANITY_F_ONLY_KNOWN_HASH,
2431 pErrInfo);
2432 if (RT_SUCCESS(rc))
2433 {
2434 PCRTCRX509ALGORITHMIDENTIFIER pDigestAlgorithm = &pSignature->pIndData->DigestInfo.DigestAlgorithm;
2435 pSignature->enmDigest = RTCrX509AlgorithmIdentifier_QueryDigestType(pDigestAlgorithm);
2436 AssertReturn(pSignature->enmDigest != RTDIGESTTYPE_INVALID, VERR_INTERNAL_ERROR_4); /* Checked above! */
2437 }
2438 }
2439 else
2440 rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_EXPECTED_INDIRECT_DATA_CONTENT_OID,
2441 "Unknown pSignedData.ContentInfo.ContentType.szObjId value: %s (expected %s)",
2442 pSignature->pSignedData->ContentInfo.ContentType.szObjId, RTCRSPCINDIRECTDATACONTENT_OID);
2443 }
2444 }
2445 return rc;
2446}
2447
2448
2449static int rtldrPE_VerifyAllPageHashes(PRTLDRMODPE pModPe, PCRTCRSPCSERIALIZEDOBJECTATTRIBUTE pAttrib, RTDIGESTTYPE enmDigest,
2450 void *pvScratch, size_t cbScratch, PRTERRINFO pErrInfo)
2451{
2452 AssertReturn(cbScratch >= _4K, VERR_INTERNAL_ERROR_3);
2453
2454 /*
2455 * Calculate the special places.
2456 */
2457 RTLDRPEHASHSPECIALS SpecialPlaces = { 0, 0, 0, 0, 0, 0 }; /* shut up gcc */
2458 int rc = rtldrPe_CalcSpecialHashPlaces(pModPe, &SpecialPlaces, pErrInfo);
2459 if (RT_FAILURE(rc))
2460 return rc;
2461
2462 uint32_t const cbHash = rtLdrPE_HashGetHashSize(enmDigest);
2463 uint32_t const cPages = pAttrib->u.pPageHashes->RawData.Asn1Core.cb / (cbHash + 4);
2464 if (cPages * (cbHash + 4) != pAttrib->u.pPageHashes->RawData.Asn1Core.cb)
2465 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_PAGE_HASH_TAB_SIZE_OVERFLOW,
2466 "Page hashes size issue: cb=%#x cbHash=%#x",
2467 pAttrib->u.pPageHashes->RawData.Asn1Core.cb, cbHash);
2468
2469 /*
2470 * Walk the table.
2471 */
2472 uint32_t const cbScratchReadMax = cbScratch & ~(uint32_t)(_4K - 1);
2473 uint32_t cbScratchRead = 0;
2474 uint32_t offScratchRead = 0;
2475
2476 uint32_t offPrev = 0;
2477#ifdef COMPLICATED_AND_WRONG
2478 uint32_t offSectEnd = pModPe->cbHeaders;
2479 uint32_t iSh = UINT32_MAX;
2480#endif
2481 uint8_t const *pbHashTab = pAttrib->u.pPageHashes->RawData.Asn1Core.uData.pu8;
2482 for (uint32_t iPage = 0; iPage < cPages - 1; iPage++)
2483 {
2484 /* Decode the page offset. */
2485 uint32_t const offPageInFile = RT_MAKE_U32_FROM_U8(pbHashTab[0], pbHashTab[1], pbHashTab[2], pbHashTab[3]);
2486 if (RT_UNLIKELY(offPageInFile >= SpecialPlaces.cbToHash))
2487 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_PAGE_HASH_TAB_TOO_LONG,
2488 "Page hash entry #%u is beyond the signature table start: %#x, %#x",
2489 iPage, offPageInFile, SpecialPlaces.cbToHash);
2490 if (RT_UNLIKELY(offPageInFile < offPrev))
2491 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_PAGE_HASH_TAB_NOT_STRICTLY_SORTED,
2492 "Page hash table is not strictly sorted: entry #%u @%#x, previous @%#x\n",
2493 iPage, offPageInFile, offPrev);
2494
2495#ifdef COMPLICATED_AND_WRONG
2496 /* Figure out how much to read and how much to zero. Need keep track
2497 of the on-disk section boundraries. */
2498 if (offPageInFile >= offSectEnd)
2499 {
2500 iSh++;
2501 if ( iSh < pModPe->cSections
2502 && offPageInFile - pModPe->paSections[iSh].PointerToRawData < pModPe->paSections[iSh].SizeOfRawData)
2503 offSectEnd = pModPe->paSections[iSh].PointerToRawData + pModPe->paSections[iSh].SizeOfRawData;
2504 else
2505 {
2506 iSh = 0;
2507 while ( iSh < pModPe->cSections
2508 && offPageInFile - pModPe->paSections[iSh].PointerToRawData >= pModPe->paSections[iSh].SizeOfRawData)
2509 iSh++;
2510 if (iSh < pModPe->cSections)
2511 offSectEnd = pModPe->paSections[iSh].PointerToRawData + pModPe->paSections[iSh].SizeOfRawData;
2512 else
2513 return RTErrInfoSetF(pErrInfo, VERR_PAGE_HASH_TAB_HASHES_NON_SECTION_DATA,
2514 "Page hash entry #%u isn't in any section: %#x", iPage, offPageInFile);
2515 }
2516 }
2517
2518#else
2519 /* Figure out how much to read and how much take as zero. Use the next
2520 page offset and the signature as upper boundraries. */
2521#endif
2522 uint32_t cbPageInFile = _4K;
2523#ifdef COMPLICATED_AND_WRONG
2524 if (offPageInFile + cbPageInFile > offSectEnd)
2525 cbPageInFile = offSectEnd - offPageInFile;
2526#else
2527 if (iPage + 1 < cPages)
2528 {
2529 uint32_t offNextPage = RT_MAKE_U32_FROM_U8(pbHashTab[0 + 4 + cbHash], pbHashTab[1 + 4 + cbHash],
2530 pbHashTab[2 + 4 + cbHash], pbHashTab[3 + 4 + cbHash]);
2531 if (offNextPage - offPageInFile < cbPageInFile)
2532 cbPageInFile = offNextPage - offPageInFile;
2533 }
2534#endif
2535
2536 if (offPageInFile + cbPageInFile > SpecialPlaces.cbToHash)
2537 cbPageInFile = SpecialPlaces.cbToHash - offPageInFile;
2538
2539 /* Did we get a cache hit? */
2540 uint8_t *pbCur = (uint8_t *)pvScratch;
2541 if ( offPageInFile + cbPageInFile <= offScratchRead + cbScratchRead
2542 && offPageInFile >= offScratchRead)
2543 pbCur += offPageInFile - offScratchRead;
2544 /* Missed, read more. */
2545 else
2546 {
2547 offScratchRead = offPageInFile;
2548#ifdef COMPLICATED_AND_WRONG
2549 cbScratchRead = offSectEnd - offPageInFile;
2550#else
2551 cbScratchRead = SpecialPlaces.cbToHash - offPageInFile;
2552#endif
2553 if (cbScratchRead > cbScratchReadMax)
2554 cbScratchRead = cbScratchReadMax;
2555 rc = pModPe->Core.pReader->pfnRead(pModPe->Core.pReader, pbCur, cbScratchRead, offScratchRead);
2556 if (RT_FAILURE(rc))
2557 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_READ_ERROR_HASH,
2558 "Page hash read error at %#x: %Rrc (cbScratchRead=%#zx)",
2559 offScratchRead, rc, cbScratchRead);
2560 }
2561
2562 /*
2563 * Hash it.
2564 */
2565 RTLDRPEHASHCTXUNION HashCtx;
2566 rc = rtLdrPE_HashInit(&HashCtx, enmDigest);
2567 AssertRCReturn(rc, rc);
2568
2569 /* Deal with special places. */
2570 uint32_t cbLeft = cbPageInFile;
2571 if (offPageInFile < SpecialPlaces.offEndSpecial)
2572 {
2573 uint32_t off = offPageInFile;
2574 if (off < SpecialPlaces.offCksum)
2575 {
2576 /* Hash everything up to the checksum. */
2577 uint32_t cbChunk = RT_MIN(SpecialPlaces.offCksum - off, cbLeft);
2578 rtLdrPE_HashUpdate(&HashCtx, enmDigest, pbCur, cbChunk);
2579 pbCur += cbChunk;
2580 cbLeft -= cbChunk;
2581 off += cbChunk;
2582 }
2583
2584 if (off < SpecialPlaces.offCksum + SpecialPlaces.cbCksum && off >= SpecialPlaces.offCksum)
2585 {
2586 /* Skip the checksum */
2587 uint32_t cbChunk = RT_MIN(SpecialPlaces.offCksum + SpecialPlaces.cbCksum - off, cbLeft);
2588 pbCur += cbChunk;
2589 cbLeft -= cbChunk;
2590 off += cbChunk;
2591 }
2592
2593 if (off < SpecialPlaces.offSecDir && off >= SpecialPlaces.offCksum + SpecialPlaces.cbCksum)
2594 {
2595 /* Hash everything between the checksum and the data dir entry. */
2596 uint32_t cbChunk = RT_MIN(SpecialPlaces.offSecDir - off, cbLeft);
2597 rtLdrPE_HashUpdate(&HashCtx, enmDigest, pbCur, cbChunk);
2598 pbCur += cbChunk;
2599 cbLeft -= cbChunk;
2600 off += cbChunk;
2601 }
2602
2603 if (off < SpecialPlaces.offSecDir + SpecialPlaces.cbSecDir && off >= SpecialPlaces.offSecDir)
2604 {
2605 /* Skip the security data directory entry. */
2606 uint32_t cbChunk = RT_MIN(SpecialPlaces.offSecDir + SpecialPlaces.cbSecDir - off, cbLeft);
2607 pbCur += cbChunk;
2608 cbLeft -= cbChunk;
2609 off += cbChunk;
2610 }
2611 }
2612
2613 rtLdrPE_HashUpdate(&HashCtx, enmDigest, pbCur, cbLeft);
2614 if (cbPageInFile < _4K)
2615 rtLdrPE_HashUpdate(&HashCtx, enmDigest, &g_abRTZero4K[cbPageInFile], _4K - cbPageInFile);
2616
2617 /*
2618 * Finish the hash calculation and compare the result.
2619 */
2620 RTLDRPEHASHRESUNION HashRes;
2621 rtLdrPE_HashFinalize(&HashCtx, enmDigest, &HashRes);
2622
2623 pbHashTab += 4;
2624 if (memcmp(pbHashTab, &HashRes, cbHash) != 0)
2625 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_PAGE_HASH_MISMATCH,
2626 "Page hash failed for page #%u, @%#x, %#x bytes: %.*Rhxs != %.*Rhxs",
2627 iPage, offPageInFile, cbPageInFile, (size_t)cbHash, pbHashTab, (size_t)cbHash, &HashRes);
2628 pbHashTab += cbHash;
2629 offPrev = offPageInFile;
2630 }
2631
2632 /*
2633 * Check that the last table entry has a hash value of zero.
2634 */
2635 if (!ASMMemIsZero(pbHashTab + 4, cbHash))
2636 return RTErrInfoSetF(pErrInfo, VERR_LDRVI_PAGE_HASH_TAB_TOO_LONG,
2637 "Maltform final page hash table entry: #%u %#010x %.*Rhxs",
2638 cPages - 1, RT_MAKE_U32_FROM_U8(pbHashTab[0], pbHashTab[1], pbHashTab[2], pbHashTab[3]),
2639 (size_t)cbHash, pbHashTab + 4);
2640 return VINF_SUCCESS;
2641}
2642
2643
2644/**
2645 * Validates the image hash, including page hashes if present.
2646 *
2647 * @returns IPRT status code.
2648 * @param pModPe The PE module.
2649 * @param pSignature The decoded signature data.
2650 * @param pErrInfo Optional error info buffer.
2651 */
2652static int rtldrPE_VerifySignatureValidateHash(PRTLDRMODPE pModPe, PRTLDRPESIGNATURE pSignature, PRTERRINFO pErrInfo)
2653{
2654 AssertReturn(pSignature->enmDigest > RTDIGESTTYPE_INVALID && pSignature->enmDigest < RTDIGESTTYPE_END, VERR_INTERNAL_ERROR_4);
2655 AssertPtrReturn(pSignature->pIndData, VERR_INTERNAL_ERROR_5);
2656 AssertReturn(RTASN1CORE_IS_PRESENT(&pSignature->pIndData->DigestInfo.Digest.Asn1Core), VERR_INTERNAL_ERROR_5);
2657 AssertPtrReturn(pSignature->pIndData->DigestInfo.Digest.Asn1Core.uData.pv, VERR_INTERNAL_ERROR_5);
2658
2659 uint32_t const cbHash = rtLdrPE_HashGetHashSize(pSignature->enmDigest);
2660 AssertReturn(pSignature->pIndData->DigestInfo.Digest.Asn1Core.cb == cbHash, VERR_INTERNAL_ERROR_5);
2661
2662 /*
2663 * Allocate a temporary memory buffer.
2664 * Note! The _4K that gets subtracted is to avoid that the 16-byte heap
2665 * block header in ring-0 (iprt) caused any unnecessary internal
2666 * heap fragmentation.
2667 */
2668#ifdef IN_RING0
2669 uint32_t cbScratch = _256K - _4K;
2670#else
2671 uint32_t cbScratch = _1M;
2672#endif
2673 void *pvScratch = RTMemTmpAlloc(cbScratch);
2674 if (!pvScratch)
2675 {
2676 cbScratch = _4K;
2677 pvScratch = RTMemTmpAlloc(cbScratch);
2678 if (!pvScratch)
2679 return RTErrInfoSet(pErrInfo, VERR_NO_TMP_MEMORY, "Failed to allocate 4KB of scratch space for hashing image.");
2680 }
2681
2682 /*
2683 * Calculate and compare the full image hash.
2684 */
2685 int rc = rtldrPE_HashImageCommon(pModPe, pvScratch, cbScratch, pSignature->enmDigest,
2686 &pSignature->HashCtx, &pSignature->HashRes, pErrInfo);
2687 if (RT_SUCCESS(rc))
2688 {
2689 if (!memcmp(&pSignature->HashRes, pSignature->pIndData->DigestInfo.Digest.Asn1Core.uData.pv, cbHash))
2690 {
2691 /*
2692 * Compare the page hashes if present.
2693 *
2694 * Seems the difference between V1 and V2 page hash attributes is
2695 * that v1 uses SHA-1 while v2 uses SHA-256. The data structures to
2696 * be identical otherwise. Initially we assumed the digest
2697 * algorithm was supposed to be RTCRSPCINDIRECTDATACONTENT::DigestInfo,
2698 * i.e. the same as for the whole image hash. The initial approach
2699 * worked just fine, but this makes more sense.
2700 *
2701 * (See also comments in osslsigncode.c (google it).)
2702 */
2703 PCRTCRSPCSERIALIZEDOBJECTATTRIBUTE pAttrib;
2704 pAttrib = RTCrSpcIndirectDataContent_GetPeImageObjAttrib(pSignature->pIndData,
2705 RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V2);
2706 if (pAttrib)
2707 rc = rtldrPE_VerifyAllPageHashes(pModPe, pAttrib, RTDIGESTTYPE_SHA256, pvScratch, cbScratch, pErrInfo);
2708 else
2709 {
2710 pAttrib = RTCrSpcIndirectDataContent_GetPeImageObjAttrib(pSignature->pIndData,
2711 RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V1);
2712 if (pAttrib)
2713 rc = rtldrPE_VerifyAllPageHashes(pModPe, pAttrib, RTDIGESTTYPE_SHA1, pvScratch, cbScratch, pErrInfo);
2714 }
2715 }
2716 else
2717 rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_IMAGE_HASH_MISMATCH,
2718 "Full image signature mismatch: %.*Rhxs, expected %.*Rhxs",
2719 cbHash, &pSignature->HashRes,
2720 cbHash, pSignature->pIndData->DigestInfo.Digest.Asn1Core.uData.pv);
2721 }
2722
2723 RTMemTmpFree(pvScratch);
2724 return rc;
2725}
2726
2727#endif /* !IPRT_WITHOUT_LDR_VERIFY */
2728
2729
2730/** @interface_method_impl{RTLDROPS,pfnVerifySignature} */
2731static DECLCALLBACK(int) rtldrPE_VerifySignature(PRTLDRMODINTERNAL pMod, PFNRTLDRVALIDATESIGNEDDATA pfnCallback, void *pvUser,
2732 PRTERRINFO pErrInfo)
2733{
2734#ifndef IPRT_WITHOUT_LDR_VERIFY
2735 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
2736
2737 int rc = rtldrPE_VerifySignatureImagePrecoditions(pModPe, pErrInfo);
2738 if (RT_SUCCESS(rc))
2739 {
2740 PRTLDRPESIGNATURE pSignature = NULL;
2741 rc = rtldrPE_VerifySignatureRead(pModPe, &pSignature, pErrInfo);
2742 if (RT_SUCCESS(rc))
2743 {
2744 rc = rtldrPE_VerifySignatureDecode(pModPe, pSignature, pErrInfo);
2745 if (RT_SUCCESS(rc))
2746 rc = rtldrPE_VerifySignatureValidateHash(pModPe, pSignature, pErrInfo);
2747 if (RT_SUCCESS(rc))
2748 {
2749 rc = pfnCallback(&pModPe->Core, RTLDRSIGNATURETYPE_PKCS7_SIGNED_DATA,
2750 &pSignature->ContentInfo, sizeof(pSignature->ContentInfo),
2751 pErrInfo, pvUser);
2752 }
2753 rtldrPE_VerifySignatureDestroy(pModPe, pSignature);
2754 }
2755 }
2756 return rc;
2757#else
2758 return VERR_NOT_SUPPORTED;
2759#endif
2760}
2761
2762
2763
2764/** @interface_method_impl{RTLDROPS,pfnHashImage} */
2765static DECLCALLBACK(int) rtldrPE_HashImage(PRTLDRMODINTERNAL pMod, RTDIGESTTYPE enmDigest, char *pszDigest, size_t cbDigest)
2766{
2767 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
2768
2769 /*
2770 * Allocate a temporary memory buffer.
2771 */
2772 uint32_t cbScratch = _16K;
2773 void *pvScratch = RTMemTmpAlloc(cbScratch);
2774 if (!pvScratch)
2775 {
2776 cbScratch = _4K;
2777 pvScratch = RTMemTmpAlloc(cbScratch);
2778 if (!pvScratch)
2779 return VERR_NO_TMP_MEMORY;
2780 }
2781
2782 /*
2783 * Do the hashing.
2784 */
2785 RTLDRPEHASHCTXUNION HashCtx;
2786 RTLDRPEHASHRESUNION HashRes;
2787 int rc = rtldrPE_HashImageCommon(pModPe, pvScratch, cbScratch, enmDigest, &HashCtx, &HashRes, NULL);
2788 if (RT_SUCCESS(rc))
2789 {
2790 /*
2791 * Format the digest into as human readable hash string.
2792 */
2793 switch (enmDigest)
2794 {
2795 case RTDIGESTTYPE_SHA512: rc = RTSha512ToString(HashRes.abSha512, pszDigest, cbDigest); break;
2796 case RTDIGESTTYPE_SHA256: rc = RTSha256ToString(HashRes.abSha256, pszDigest, cbDigest); break;
2797 case RTDIGESTTYPE_SHA1: rc = RTSha1ToString(HashRes.abSha1, pszDigest, cbDigest); break;
2798 case RTDIGESTTYPE_MD5: rc = RTMd5ToString(HashRes.abMd5, pszDigest, cbDigest); break;
2799 default: AssertFailedReturn(VERR_INTERNAL_ERROR_3);
2800 }
2801 }
2802 return rc;
2803}
2804
2805
2806/** @interface_method_impl{RTLDROPS,pfnDone} */
2807static DECLCALLBACK(int) rtldrPEDone(PRTLDRMODINTERNAL pMod)
2808{
2809 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
2810 if (pModPe->pvBits)
2811 {
2812 RTMemFree(pModPe->pvBits);
2813 pModPe->pvBits = NULL;
2814 }
2815 return VINF_SUCCESS;
2816}
2817
2818
2819/** @interface_method_impl{RTLDROPS,pfnClose} */
2820static DECLCALLBACK(int) rtldrPEClose(PRTLDRMODINTERNAL pMod)
2821{
2822 PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
2823 if (pModPe->paSections)
2824 {
2825 RTMemFree(pModPe->paSections);
2826 pModPe->paSections = NULL;
2827 }
2828 if (pModPe->pvBits)
2829 {
2830 RTMemFree(pModPe->pvBits);
2831 pModPe->pvBits = NULL;
2832 }
2833 return VINF_SUCCESS;
2834}
2835
2836
2837/**
2838 * Operations for a 32-bit PE module.
2839 */
2840static const RTLDROPSPE s_rtldrPE32Ops =
2841{
2842 {
2843 "pe32",
2844 rtldrPEClose,
2845 NULL,
2846 rtldrPEDone,
2847 rtldrPEEnumSymbols,
2848 /* ext */
2849 rtldrPEGetImageSize,
2850 rtldrPEGetBits,
2851 rtldrPERelocate,
2852 rtldrPEGetSymbolEx,
2853 rtldrPE_QueryForwarderInfo,
2854 rtldrPE_EnumDbgInfo,
2855 rtldrPE_EnumSegments,
2856 rtldrPE_LinkAddressToSegOffset,
2857 rtldrPE_LinkAddressToRva,
2858 rtldrPE_SegOffsetToRva,
2859 rtldrPE_RvaToSegOffset,
2860 NULL,
2861 rtldrPE_QueryProp,
2862 rtldrPE_VerifySignature,
2863 rtldrPE_HashImage,
2864 42
2865 },
2866 rtldrPEResolveImports32,
2867 42
2868};
2869
2870
2871/**
2872 * Operations for a 64-bit PE module.
2873 */
2874static const RTLDROPSPE s_rtldrPE64Ops =
2875{
2876 {
2877 "pe64",
2878 rtldrPEClose,
2879 NULL,
2880 rtldrPEDone,
2881 rtldrPEEnumSymbols,
2882 /* ext */
2883 rtldrPEGetImageSize,
2884 rtldrPEGetBits,
2885 rtldrPERelocate,
2886 rtldrPEGetSymbolEx,
2887 rtldrPE_QueryForwarderInfo,
2888 rtldrPE_EnumDbgInfo,
2889 rtldrPE_EnumSegments,
2890 rtldrPE_LinkAddressToSegOffset,
2891 rtldrPE_LinkAddressToRva,
2892 rtldrPE_SegOffsetToRva,
2893 rtldrPE_RvaToSegOffset,
2894 NULL,
2895 rtldrPE_QueryProp,
2896 rtldrPE_VerifySignature,
2897 rtldrPE_HashImage,
2898 42
2899 },
2900 rtldrPEResolveImports64,
2901 42
2902};
2903
2904
2905/**
2906 * Converts the optional header from 32 bit to 64 bit.
2907 * This is a rather simple task, if you start from the right end.
2908 *
2909 * @param pOptHdr On input this is a PIMAGE_OPTIONAL_HEADER32.
2910 * On output this will be a PIMAGE_OPTIONAL_HEADER64.
2911 */
2912static void rtldrPEConvert32BitOptionalHeaderTo64Bit(PIMAGE_OPTIONAL_HEADER64 pOptHdr)
2913{
2914 /*
2915 * volatile everywhere! Trying to prevent the compiler being a smarta$$ and reorder stuff.
2916 */
2917 IMAGE_OPTIONAL_HEADER32 volatile *pOptHdr32 = (IMAGE_OPTIONAL_HEADER32 volatile *)pOptHdr;
2918 IMAGE_OPTIONAL_HEADER64 volatile *pOptHdr64 = pOptHdr;
2919
2920 /* from LoaderFlags and out the difference is 4 * 32-bits. */
2921 Assert(RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, LoaderFlags) + 16 == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, LoaderFlags));
2922 Assert( RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]) + 16
2923 == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]));
2924 uint32_t volatile *pu32Dst = (uint32_t *)&pOptHdr64->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1;
2925 const uint32_t volatile *pu32Src = (uint32_t *)&pOptHdr32->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1;
2926 const uint32_t volatile *pu32SrcLast = (uint32_t *)&pOptHdr32->LoaderFlags;
2927 while (pu32Src >= pu32SrcLast)
2928 *pu32Dst-- = *pu32Src--;
2929
2930 /* the previous 4 fields are 32/64 and needs special attention. */
2931 pOptHdr64->SizeOfHeapCommit = pOptHdr32->SizeOfHeapCommit;
2932 pOptHdr64->SizeOfHeapReserve = pOptHdr32->SizeOfHeapReserve;
2933 pOptHdr64->SizeOfStackCommit = pOptHdr32->SizeOfStackCommit;
2934 uint32_t u32SizeOfStackReserve = pOptHdr32->SizeOfStackReserve;
2935 pOptHdr64->SizeOfStackReserve = u32SizeOfStackReserve;
2936
2937 /* The rest matches except for BaseOfData which has been merged into ImageBase in the 64-bit version..
2938 * Thus, ImageBase needs some special treatment. It will probably work fine assigning one to the
2939 * other since this is all declared volatile, but taking now chances, we'll use a temp variable.
2940 */
2941 Assert(RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, SizeOfStackReserve) == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, SizeOfStackReserve));
2942 Assert(RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, BaseOfData) == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, ImageBase));
2943 Assert(RT_OFFSETOF(IMAGE_OPTIONAL_HEADER32, SectionAlignment) == RT_OFFSETOF(IMAGE_OPTIONAL_HEADER64, SectionAlignment));
2944 uint32_t u32ImageBase = pOptHdr32->ImageBase;
2945 pOptHdr64->ImageBase = u32ImageBase;
2946}
2947
2948
2949/**
2950 * Converts the load config directory from 32 bit to 64 bit.
2951 * This is a rather simple task, if you start from the right end.
2952 *
2953 * @param pLoadCfg On input this is a PIMAGE_LOAD_CONFIG_DIRECTORY32.
2954 * On output this will be a PIMAGE_LOAD_CONFIG_DIRECTORY64.
2955 */
2956static void rtldrPEConvert32BitLoadConfigTo64Bit(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg)
2957{
2958 /*
2959 * volatile everywhere! Trying to prevent the compiler being a smarta$$ and reorder stuff.
2960 */
2961 IMAGE_LOAD_CONFIG_DIRECTORY32_V5 volatile *pLoadCfg32 = (IMAGE_LOAD_CONFIG_DIRECTORY32_V5 volatile *)pLoadCfg;
2962 IMAGE_LOAD_CONFIG_DIRECTORY64_V5 volatile *pLoadCfg64 = pLoadCfg;
2963
2964 pLoadCfg64->GuardAddressTakenIatEntryTable = pLoadCfg32->GuardAddressTakenIatEntryTable;
2965 pLoadCfg64->GuardAddressTakenIatEntryCount = pLoadCfg32->GuardAddressTakenIatEntryCount;
2966 pLoadCfg64->GuardLongJumpTargetTable = pLoadCfg32->GuardLongJumpTargetTable;
2967 pLoadCfg64->GuardLongJumpTargetCount = pLoadCfg32->GuardLongJumpTargetCount;
2968 pLoadCfg64->CodeIntegrity.Reserved = pLoadCfg32->CodeIntegrity.Reserved;
2969 pLoadCfg64->CodeIntegrity.CatalogOffset = pLoadCfg32->CodeIntegrity.CatalogOffset;
2970 pLoadCfg64->CodeIntegrity.Catalog = pLoadCfg32->CodeIntegrity.Catalog;
2971 pLoadCfg64->CodeIntegrity.Flags = pLoadCfg32->CodeIntegrity.Flags;
2972 pLoadCfg64->GuardFlags = pLoadCfg32->GuardFlags;
2973 pLoadCfg64->GuardCFFunctionCount = pLoadCfg32->GuardCFFunctionCount;
2974 pLoadCfg64->GuardCFFunctionTable = pLoadCfg32->GuardCFFunctionTable;
2975 pLoadCfg64->Reserved2 = pLoadCfg32->Reserved2;
2976 pLoadCfg64->GuardCFCCheckFunctionPointer = pLoadCfg32->GuardCFCCheckFunctionPointer;
2977 pLoadCfg64->SEHandlerCount = pLoadCfg32->SEHandlerCount;
2978 pLoadCfg64->SEHandlerTable = pLoadCfg32->SEHandlerTable;
2979 pLoadCfg64->SecurityCookie = pLoadCfg32->SecurityCookie;
2980 pLoadCfg64->EditList = pLoadCfg32->EditList;
2981 pLoadCfg64->Reserved1 = pLoadCfg32->Reserved1;
2982 pLoadCfg64->CSDVersion = pLoadCfg32->CSDVersion;
2983 pLoadCfg64->ProcessHeapFlags = pLoadCfg32->ProcessHeapFlags; /* switched place with ProcessAffinityMask, but we're more than 16 byte off by now so it doesn't matter. */
2984 pLoadCfg64->ProcessAffinityMask = pLoadCfg32->ProcessAffinityMask;
2985 pLoadCfg64->VirtualMemoryThreshold = pLoadCfg32->VirtualMemoryThreshold;
2986 pLoadCfg64->MaximumAllocationSize = pLoadCfg32->MaximumAllocationSize;
2987 pLoadCfg64->LockPrefixTable = pLoadCfg32->LockPrefixTable;
2988 pLoadCfg64->DeCommitTotalFreeThreshold = pLoadCfg32->DeCommitTotalFreeThreshold;
2989 uint32_t u32DeCommitFreeBlockThreshold = pLoadCfg32->DeCommitFreeBlockThreshold;
2990 pLoadCfg64->DeCommitFreeBlockThreshold = u32DeCommitFreeBlockThreshold;
2991 /* the rest is equal. */
2992 Assert( RT_OFFSETOF(IMAGE_LOAD_CONFIG_DIRECTORY32, DeCommitFreeBlockThreshold)
2993 == RT_OFFSETOF(IMAGE_LOAD_CONFIG_DIRECTORY64, DeCommitFreeBlockThreshold));
2994}
2995
2996
2997/**
2998 * Translate the PE/COFF machine name to a string.
2999 *
3000 * @returns Name string (read-only).
3001 * @param uMachine The PE/COFF machine.
3002 */
3003static const char *rtldrPEGetArchName(uint16_t uMachine)
3004{
3005 switch (uMachine)
3006 {
3007 case IMAGE_FILE_MACHINE_I386: return "X86_32";
3008 case IMAGE_FILE_MACHINE_AMD64: return "AMD64";
3009
3010 case IMAGE_FILE_MACHINE_UNKNOWN: return "UNKNOWN";
3011 case IMAGE_FILE_MACHINE_AM33: return "AM33";
3012 case IMAGE_FILE_MACHINE_ARM: return "ARM";
3013 case IMAGE_FILE_MACHINE_THUMB: return "THUMB";
3014 case IMAGE_FILE_MACHINE_ARMNT: return "ARMNT";
3015 case IMAGE_FILE_MACHINE_ARM64: return "ARM64";
3016 case IMAGE_FILE_MACHINE_EBC: return "EBC";
3017 case IMAGE_FILE_MACHINE_IA64: return "IA64";
3018 case IMAGE_FILE_MACHINE_M32R: return "M32R";
3019 case IMAGE_FILE_MACHINE_MIPS16: return "MIPS16";
3020 case IMAGE_FILE_MACHINE_MIPSFPU: return "MIPSFPU";
3021 case IMAGE_FILE_MACHINE_MIPSFPU16: return "MIPSFPU16";
3022 case IMAGE_FILE_MACHINE_WCEMIPSV2: return "WCEMIPSV2";
3023 case IMAGE_FILE_MACHINE_POWERPC: return "POWERPC";
3024 case IMAGE_FILE_MACHINE_POWERPCFP: return "POWERPCFP";
3025 case IMAGE_FILE_MACHINE_R4000: return "R4000";
3026 case IMAGE_FILE_MACHINE_SH3: return "SH3";
3027 case IMAGE_FILE_MACHINE_SH3DSP: return "SH3DSP";
3028 case IMAGE_FILE_MACHINE_SH4: return "SH4";
3029 case IMAGE_FILE_MACHINE_SH5: return "SH5";
3030 default: return "UnknownMachine";
3031 }
3032}
3033
3034
3035/**
3036 * Validates the file header.
3037 *
3038 * @returns iprt status code.
3039 * @param pFileHdr Pointer to the file header that needs validating.
3040 * @param fFlags Valid RTLDR_O_XXX combination.
3041 * @param pszLogName The log name to prefix the errors with.
3042 * @param penmArch Where to store the CPU architecture.
3043 */
3044static int rtldrPEValidateFileHeader(PIMAGE_FILE_HEADER pFileHdr, uint32_t fFlags, const char *pszLogName, PRTLDRARCH penmArch)
3045{
3046 size_t cbOptionalHeader;
3047 switch (pFileHdr->Machine)
3048 {
3049 case IMAGE_FILE_MACHINE_I386:
3050 cbOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER32);
3051 *penmArch = RTLDRARCH_X86_32;
3052 break;
3053 case IMAGE_FILE_MACHINE_AMD64:
3054 cbOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER64);
3055 *penmArch = RTLDRARCH_AMD64;
3056 break;
3057
3058 default:
3059 Log(("rtldrPEOpen: %s: Unsupported Machine=%#x\n",
3060 pszLogName, pFileHdr->Machine));
3061 *penmArch = RTLDRARCH_INVALID;
3062 return VERR_BAD_EXE_FORMAT;
3063 }
3064 if (pFileHdr->SizeOfOptionalHeader != cbOptionalHeader)
3065 {
3066 Log(("rtldrPEOpen: %s: SizeOfOptionalHeader=%#x expected %#x\n",
3067 pszLogName, pFileHdr->SizeOfOptionalHeader, cbOptionalHeader));
3068 return VERR_BAD_EXE_FORMAT;
3069 }
3070 /* This restriction needs to be implemented elsewhere. */
3071 if ( (pFileHdr->Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
3072 && !(fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION)))
3073 {
3074 Log(("rtldrPEOpen: %s: IMAGE_FILE_RELOCS_STRIPPED\n", pszLogName));
3075 return VERR_BAD_EXE_FORMAT;
3076 }
3077 if (pFileHdr->NumberOfSections > 42)
3078 {
3079 Log(("rtldrPEOpen: %s: NumberOfSections=%d - our limit is 42, please raise it if the binary makes sense.(!!!)\n",
3080 pszLogName, pFileHdr->NumberOfSections));
3081 return VERR_BAD_EXE_FORMAT;
3082 }
3083 if (pFileHdr->NumberOfSections < 1)
3084 {
3085 Log(("rtldrPEOpen: %s: NumberOfSections=%d - we can't have an image without sections (!!!)\n",
3086 pszLogName, pFileHdr->NumberOfSections));
3087 return VERR_BAD_EXE_FORMAT;
3088 }
3089 return VINF_SUCCESS;
3090}
3091
3092
3093/**
3094 * Validates the optional header (64/32-bit)
3095 *
3096 * @returns iprt status code.
3097 * @param pOptHdr Pointer to the optional header which needs validation.
3098 * @param pszLogName The log name to prefix the errors with.
3099 * @param offNtHdrs The offset of the NT headers from the start of the file.
3100 * @param pFileHdr Pointer to the file header (valid).
3101 * @param cbRawImage The raw image size.
3102 * @param fFlags Loader flags, RTLDR_O_XXX.
3103 */
3104static int rtldrPEValidateOptionalHeader(const IMAGE_OPTIONAL_HEADER64 *pOptHdr, const char *pszLogName, RTFOFF offNtHdrs,
3105 const IMAGE_FILE_HEADER *pFileHdr, RTFOFF cbRawImage, uint32_t fFlags)
3106{
3107 const uint16_t CorrectMagic = pFileHdr->SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
3108 ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC;
3109 if (pOptHdr->Magic != CorrectMagic)
3110 {
3111 Log(("rtldrPEOpen: %s: Magic=%#x - expected %#x!!!\n", pszLogName, pOptHdr->Magic, CorrectMagic));
3112 return VERR_BAD_EXE_FORMAT;
3113 }
3114 const uint32_t cbImage = pOptHdr->SizeOfImage;
3115 if (cbImage > _1G)
3116 {
3117 Log(("rtldrPEOpen: %s: SizeOfImage=%#x - Our limit is 1GB (%#x)!!!\n", pszLogName, cbImage, _1G));
3118 return VERR_BAD_EXE_FORMAT;
3119 }
3120 const uint32_t cbMinImageSize = pFileHdr->SizeOfOptionalHeader + sizeof(*pFileHdr) + 4 + (uint32_t)offNtHdrs;
3121 if (cbImage < cbMinImageSize)
3122 {
3123 Log(("rtldrPEOpen: %s: SizeOfImage=%#x to small, minimum %#x!!!\n", pszLogName, cbImage, cbMinImageSize));
3124 return VERR_BAD_EXE_FORMAT;
3125 }
3126 if (pOptHdr->AddressOfEntryPoint >= cbImage)
3127 {
3128 Log(("rtldrPEOpen: %s: AddressOfEntryPoint=%#x - beyond image size (%#x)!!!\n",
3129 pszLogName, pOptHdr->AddressOfEntryPoint, cbImage));
3130 return VERR_BAD_EXE_FORMAT;
3131 }
3132 if (pOptHdr->BaseOfCode >= cbImage)
3133 {
3134 Log(("rtldrPEOpen: %s: BaseOfCode=%#x - beyond image size (%#x)!!!\n",
3135 pszLogName, pOptHdr->BaseOfCode, cbImage));
3136 return VERR_BAD_EXE_FORMAT;
3137 }
3138#if 0/* only in 32-bit header */
3139 if (pOptHdr->BaseOfData >= cbImage)
3140 {
3141 Log(("rtldrPEOpen: %s: BaseOfData=%#x - beyond image size (%#x)!!!\n",
3142 pszLogName, pOptHdr->BaseOfData, cbImage));
3143 return VERR_BAD_EXE_FORMAT;
3144 }
3145#endif
3146 if (pOptHdr->SizeOfHeaders >= cbImage)
3147 {
3148 Log(("rtldrPEOpen: %s: SizeOfHeaders=%#x - beyond image size (%#x)!!!\n",
3149 pszLogName, pOptHdr->SizeOfHeaders, cbImage));
3150 return VERR_BAD_EXE_FORMAT;
3151 }
3152 /* don't know how to do the checksum, so ignore it. */
3153 if (pOptHdr->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN)
3154 {
3155 Log(("rtldrPEOpen: %s: Subsystem=%#x (unknown)!!!\n", pszLogName, pOptHdr->Subsystem));
3156 return VERR_BAD_EXE_FORMAT;
3157 }
3158 if (pOptHdr->SizeOfHeaders < cbMinImageSize + pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER))
3159 {
3160 Log(("rtldrPEOpen: %s: SizeOfHeaders=%#x - cbMinImageSize %#x + sections %#x = %#llx!!!\n",
3161 pszLogName, pOptHdr->SizeOfHeaders,
3162 cbMinImageSize, pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER),
3163 cbMinImageSize + pFileHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER)));
3164 return VERR_BAD_EXE_FORMAT;
3165 }
3166 if (pOptHdr->SizeOfStackReserve < pOptHdr->SizeOfStackCommit)
3167 {
3168 Log(("rtldrPEOpen: %s: SizeOfStackReserve %#x < SizeOfStackCommit %#x!!!\n",
3169 pszLogName, pOptHdr->SizeOfStackReserve, pOptHdr->SizeOfStackCommit));
3170 return VERR_BAD_EXE_FORMAT;
3171 }
3172 if (pOptHdr->SizeOfHeapReserve < pOptHdr->SizeOfHeapCommit)
3173 {
3174 Log(("rtldrPEOpen: %s: SizeOfStackReserve %#x < SizeOfStackCommit %#x!!!\n",
3175 pszLogName, pOptHdr->SizeOfStackReserve, pOptHdr->SizeOfStackCommit));
3176 return VERR_BAD_EXE_FORMAT;
3177 }
3178
3179 /* DataDirectory */
3180 if (pOptHdr->NumberOfRvaAndSizes != RT_ELEMENTS(pOptHdr->DataDirectory))
3181 {
3182 Log(("rtldrPEOpen: %s: NumberOfRvaAndSizes=%d!!!\n", pszLogName, pOptHdr->NumberOfRvaAndSizes));
3183 return VERR_BAD_EXE_FORMAT;
3184 }
3185 for (unsigned i = 0; i < RT_ELEMENTS(pOptHdr->DataDirectory); i++)
3186 {
3187 IMAGE_DATA_DIRECTORY const *pDir = &pOptHdr->DataDirectory[i];
3188 if (!pDir->Size)
3189 continue;
3190 size_t cb = cbImage;
3191 switch (i)
3192 {
3193 case IMAGE_DIRECTORY_ENTRY_EXPORT: // 0
3194 case IMAGE_DIRECTORY_ENTRY_IMPORT: // 1
3195 case IMAGE_DIRECTORY_ENTRY_RESOURCE: // 2
3196 case IMAGE_DIRECTORY_ENTRY_EXCEPTION: // 3
3197 case IMAGE_DIRECTORY_ENTRY_BASERELOC: // 5
3198 case IMAGE_DIRECTORY_ENTRY_DEBUG: // 6
3199 case IMAGE_DIRECTORY_ENTRY_COPYRIGHT: // 7
3200 case IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT: // 11
3201 case IMAGE_DIRECTORY_ENTRY_IAT: // 12 /* Import Address Table */
3202 break;
3203 case IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG: // 10 - need to check for lock prefixes.
3204 /* Delay inspection after section table is validated. */
3205 break;
3206
3207 case IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT: // 13
3208 if (fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION))
3209 break;
3210 Log(("rtldrPEOpen: %s: dir no. %d (DELAY_IMPORT) VirtualAddress=%#x Size=%#x is not supported!!!\n",
3211 pszLogName, i, pDir->VirtualAddress, pDir->Size));
3212 return VERR_LDRPE_DELAY_IMPORT;
3213
3214 case IMAGE_DIRECTORY_ENTRY_SECURITY: // 4
3215 /* The VirtualAddress is a PointerToRawData. */
3216 cb = (size_t)cbRawImage; Assert((RTFOFF)cb == cbRawImage);
3217 Log(("rtldrPEOpen: %s: dir no. %d (SECURITY) VirtualAddress=%#x Size=%#x is not supported!!!\n",
3218 pszLogName, i, pDir->VirtualAddress, pDir->Size));
3219 if (pDir->Size < sizeof(WIN_CERTIFICATE))
3220 {
3221 Log(("rtldrPEOpen: %s: Security directory #%u is too small: %#x bytes\n", pszLogName, i, pDir->Size));
3222 return VERR_LDRPE_CERT_MALFORMED;
3223 }
3224 if (pDir->Size >= RTLDRMODPE_MAX_SECURITY_DIR_SIZE)
3225 {
3226 Log(("rtldrPEOpen: %s: Security directory #%u is too large: %#x bytes\n", pszLogName, i, pDir->Size));
3227 return VERR_LDRPE_CERT_MALFORMED;
3228 }
3229 if (pDir->VirtualAddress & 7)
3230 {
3231 Log(("rtldrPEOpen: %s: Security directory #%u is misaligned: %#x\n", pszLogName, i, pDir->VirtualAddress));
3232 return VERR_LDRPE_CERT_MALFORMED;
3233 }
3234 /* When using the in-memory reader with a debugger, we may get
3235 into trouble here since we might not have access to the whole
3236 physical file. So skip the tests below. Makes VBoxGuest.sys
3237 load and check out just fine, for instance. */
3238 if (fFlags & RTLDR_O_FOR_DEBUG)
3239 continue;
3240 break;
3241
3242 case IMAGE_DIRECTORY_ENTRY_GLOBALPTR: // 8 /* (MIPS GP) */
3243 Log(("rtldrPEOpen: %s: dir no. %d (GLOBALPTR) VirtualAddress=%#x Size=%#x is not supported!!!\n",
3244 pszLogName, i, pDir->VirtualAddress, pDir->Size));
3245 return VERR_LDRPE_GLOBALPTR;
3246
3247 case IMAGE_DIRECTORY_ENTRY_TLS: // 9
3248 if (fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION))
3249 break;
3250 Log(("rtldrPEOpen: %s: dir no. %d (TLS) VirtualAddress=%#x Size=%#x is not supported!!!\n",
3251 pszLogName, i, pDir->VirtualAddress, pDir->Size));
3252 return VERR_LDRPE_TLS;
3253
3254 case IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR:// 14
3255 if (fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION))
3256 break;
3257 Log(("rtldrPEOpen: %s: dir no. %d (COM_DESCRIPTOR) VirtualAddress=%#x Size=%#x is not supported!!!\n",
3258 pszLogName, i, pDir->VirtualAddress, pDir->Size));
3259 return VERR_LDRPE_COM_DESCRIPTOR;
3260
3261 default:
3262 Log(("rtldrPEOpen: %s: dir no. %d VirtualAddress=%#x Size=%#x is not supported!!!\n",
3263 pszLogName, i, pDir->VirtualAddress, pDir->Size));
3264 return VERR_BAD_EXE_FORMAT;
3265 }
3266 if (pDir->VirtualAddress >= cb)
3267 {
3268 Log(("rtldrPEOpen: %s: dir no. %d VirtualAddress=%#x is invalid (limit %#x)!!!\n",
3269 pszLogName, i, pDir->VirtualAddress, cb));
3270 return VERR_BAD_EXE_FORMAT;
3271 }
3272 if (pDir->Size > cb - pDir->VirtualAddress)
3273 {
3274 Log(("rtldrPEOpen: %s: dir no. %d Size=%#x is invalid (rva=%#x, limit=%#x)!!!\n",
3275 pszLogName, i, pDir->Size, pDir->VirtualAddress, cb));
3276 return VERR_BAD_EXE_FORMAT;
3277 }
3278 }
3279 return VINF_SUCCESS;
3280}
3281
3282
3283/**
3284 * Validates the section headers.
3285 *
3286 * @returns iprt status code.
3287 * @param paSections Pointer to the array of sections that is to be validated.
3288 * @param cSections Number of sections in that array.
3289 * @param pszLogName The log name to prefix the errors with.
3290 * @param pOptHdr Pointer to the optional header (valid).
3291 * @param cbRawImage The raw image size.
3292 * @param fFlags Loader flags, RTLDR_O_XXX.
3293 * @param fNoCode Verify that the image contains no code.
3294 */
3295static int rtldrPEValidateSectionHeaders(const IMAGE_SECTION_HEADER *paSections, unsigned cSections, const char *pszLogName,
3296 const IMAGE_OPTIONAL_HEADER64 *pOptHdr, RTFOFF cbRawImage, uint32_t fFlags, bool fNoCode)
3297{
3298 const uint32_t cbImage = pOptHdr->SizeOfImage;
3299 const IMAGE_SECTION_HEADER *pSH = &paSections[0];
3300 uint32_t uRvaPrev = pOptHdr->SizeOfHeaders;
3301 Log3(("RTLdrPE: Section Headers:\n"));
3302 for (unsigned cSHdrsLeft = cSections; cSHdrsLeft > 0; cSHdrsLeft--, pSH++)
3303 {
3304 const unsigned iSH = (unsigned)(pSH - &paSections[0]); NOREF(iSH);
3305 Log3(("RTLdrPE: #%d '%-8.8s' Characteristics: %08RX32\n"
3306 "RTLdrPE: VirtAddr: %08RX32 VirtSize: %08RX32\n"
3307 "RTLdrPE: FileOff: %08RX32 FileSize: %08RX32\n"
3308 "RTLdrPE: RelocOff: %08RX32 #Relocs: %08RX32\n"
3309 "RTLdrPE: LineOff: %08RX32 #Lines: %08RX32\n",
3310 iSH, pSH->Name, pSH->Characteristics,
3311 pSH->VirtualAddress, pSH->Misc.VirtualSize,
3312 pSH->PointerToRawData, pSH->SizeOfRawData,
3313 pSH->PointerToRelocations, pSH->NumberOfRelocations,
3314 pSH->PointerToLinenumbers, pSH->NumberOfLinenumbers));
3315
3316 AssertCompile(IMAGE_SCN_MEM_16BIT == IMAGE_SCN_MEM_PURGEABLE);
3317 if ( ( pSH->Characteristics & (IMAGE_SCN_MEM_PURGEABLE | IMAGE_SCN_MEM_PRELOAD | IMAGE_SCN_MEM_FARDATA) )
3318 && !(fFlags & RTLDR_O_FOR_DEBUG)) /* purgable/16-bit seen on w2ksp0 hal.dll, ignore the bunch. */
3319 {
3320 Log(("rtldrPEOpen: %s: Unsupported section flag(s) %#x section #%d '%.*s'!!!\n",
3321 pszLogName, pSH->Characteristics, iSH, sizeof(pSH->Name), pSH->Name));
3322 return VERR_BAD_EXE_FORMAT;
3323 }
3324
3325 if ( pSH->Misc.VirtualSize
3326 && !(pSH->Characteristics & IMAGE_SCN_TYPE_NOLOAD)) /* binutils uses this for '.stab' even if it's reserved/obsoleted by MS. */
3327 {
3328 if (pSH->VirtualAddress < uRvaPrev)
3329 {
3330 Log(("rtldrPEOpen: %s: Overlaps previous section or sections aren't in ascending order, VirtualAddress=%#x uRvaPrev=%#x - section #%d '%.*s'!!!\n",
3331 pszLogName, pSH->VirtualAddress, uRvaPrev, iSH, sizeof(pSH->Name), pSH->Name));
3332 return VERR_BAD_EXE_FORMAT;
3333 }
3334 if (pSH->VirtualAddress > cbImage)
3335 {
3336 Log(("rtldrPEOpen: %s: VirtualAddress=%#x - beyond image size (%#x) - section #%d '%.*s'!!!\n",
3337 pszLogName, pSH->VirtualAddress, cbImage, iSH, sizeof(pSH->Name), pSH->Name));
3338 return VERR_BAD_EXE_FORMAT;
3339 }
3340
3341 if (pSH->VirtualAddress & (pOptHdr->SectionAlignment - 1)) //ASSUMES power of 2 alignment.
3342 {
3343 Log(("rtldrPEOpen: %s: VirtualAddress=%#x misaligned (%#x) - section #%d '%.*s'!!!\n",
3344 pszLogName, pSH->VirtualAddress, pOptHdr->SectionAlignment, iSH, sizeof(pSH->Name), pSH->Name));
3345 return VERR_BAD_EXE_FORMAT;
3346 }
3347
3348#ifdef PE_FILE_OFFSET_EQUALS_RVA
3349 /* Our loader code assume rva matches the file offset. */
3350 if ( pSH->SizeOfRawData
3351 && pSH->PointerToRawData != pSH->VirtualAddress)
3352 {
3353 Log(("rtldrPEOpen: %s: ASSUMPTION FAILED: file offset %#x != RVA %#x - section #%d '%.*s'!!!\n",
3354 pszLogName, pSH->PointerToRawData, pSH->VirtualAddress, iSH, sizeof(pSH->Name), pSH->Name));
3355 return VERR_BAD_EXE_FORMAT;
3356 }
3357#endif
3358 }
3359
3360 ///@todo only if SizeOfRawData > 0 ?
3361 if ( pSH->PointerToRawData > cbRawImage /// @todo pSH->PointerToRawData >= cbRawImage ?
3362 || pSH->SizeOfRawData > cbRawImage
3363 || pSH->PointerToRawData + pSH->SizeOfRawData > cbRawImage)
3364 {
3365 Log(("rtldrPEOpen: %s: PointerToRawData=%#x SizeOfRawData=%#x - beyond end of file (%#x) - section #%d '%.*s'!!!\n",
3366 pszLogName, pSH->PointerToRawData, pSH->SizeOfRawData, cbRawImage,
3367 iSH, sizeof(pSH->Name), pSH->Name));
3368 return VERR_BAD_EXE_FORMAT;
3369 }
3370
3371 if (pSH->PointerToRawData & (pOptHdr->FileAlignment - 1)) //ASSUMES power of 2 alignment.
3372 {
3373 Log(("rtldrPEOpen: %s: PointerToRawData=%#x misaligned (%#x) - section #%d '%.*s'!!!\n",
3374 pszLogName, pSH->PointerToRawData, pOptHdr->FileAlignment, iSH, sizeof(pSH->Name), pSH->Name));
3375 return VERR_BAD_EXE_FORMAT;
3376 }
3377
3378 /* ignore the relocations and linenumbers. */
3379
3380 uRvaPrev = pSH->VirtualAddress + pSH->Misc.VirtualSize;
3381 }
3382
3383 /*
3384 * Do a separate run if we need to validate the no-code claim from the
3385 * optional header.
3386 */
3387 if (fNoCode)
3388 {
3389 pSH = &paSections[0];
3390 for (unsigned cSHdrsLeft = cSections; cSHdrsLeft > 0; cSHdrsLeft--, pSH++)
3391 if (pSH->Characteristics & (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE))
3392 return VERR_LDR_ARCH_MISMATCH;
3393 }
3394
3395
3396 /** @todo r=bird: more sanity checks! */
3397 return VINF_SUCCESS;
3398}
3399
3400
3401/**
3402 * Reads image data by RVA using the section headers.
3403 *
3404 * @returns iprt status code.
3405 * @param pModPe The PE module instance.
3406 * @param pvBuf Where to store the bits.
3407 * @param cb Number of bytes to tread.
3408 * @param RVA Where to read from.
3409 */
3410static int rtldrPEReadRVA(PRTLDRMODPE pModPe, void *pvBuf, uint32_t cb, uint32_t RVA)
3411{
3412 const IMAGE_SECTION_HEADER *pSH = pModPe->paSections;
3413 PRTLDRREADER pReader = pModPe->Core.pReader;
3414 uint32_t cbRead;
3415 int rc;
3416
3417 /*
3418 * Is it the headers, i.e. prior to the first section.
3419 */
3420 if (RVA < pModPe->cbHeaders)
3421 {
3422 cbRead = RT_MIN(pModPe->cbHeaders - RVA, cb);
3423 rc = pReader->pfnRead(pReader, pvBuf, cbRead, RVA);
3424 if ( cbRead == cb
3425 || RT_FAILURE(rc))
3426 return rc;
3427 cb -= cbRead;
3428 RVA += cbRead;
3429 pvBuf = (uint8_t *)pvBuf + cbRead;
3430 }
3431
3432 /* In the zero space between headers and the first section? */
3433 if (RVA < pSH->VirtualAddress)
3434 {
3435 cbRead = RT_MIN(pSH->VirtualAddress - RVA, cb);
3436 memset(pvBuf, 0, cbRead);
3437 if (cbRead == cb)
3438 return VINF_SUCCESS;
3439 cb -= cbRead;
3440 RVA += cbRead;
3441 pvBuf = (uint8_t *)pvBuf + cbRead;
3442 }
3443
3444 /*
3445 * Iterate the sections.
3446 */
3447 for (unsigned cLeft = pModPe->cSections;
3448 cLeft > 0;
3449 cLeft--, pSH++)
3450 {
3451 uint32_t off = RVA - pSH->VirtualAddress;
3452 if (off < pSH->Misc.VirtualSize)
3453 {
3454 cbRead = RT_MIN(pSH->Misc.VirtualSize - off, cb);
3455 rc = pReader->pfnRead(pReader, pvBuf, cbRead, pSH->PointerToRawData + off);
3456 if ( cbRead == cb
3457 || RT_FAILURE(rc))
3458 return rc;
3459 cb -= cbRead;
3460 RVA += cbRead;
3461 pvBuf = (uint8_t *)pvBuf + cbRead;
3462 }
3463 uint32_t RVANext = cLeft ? pSH[1].VirtualAddress : pModPe->cbImage;
3464 if (RVA < RVANext)
3465 {
3466 cbRead = RT_MIN(RVANext - RVA, cb);
3467 memset(pvBuf, 0, cbRead);
3468 if (cbRead == cb)
3469 return VINF_SUCCESS;
3470 cb -= cbRead;
3471 RVA += cbRead;
3472 pvBuf = (uint8_t *)pvBuf + cbRead;
3473 }
3474 }
3475
3476 AssertFailed();
3477 return VERR_INTERNAL_ERROR;
3478}
3479
3480
3481/**
3482 * Validates the data of some selected data directories entries and remember
3483 * important bits for later.
3484 *
3485 * This requires a valid section table and thus has to wait till after we've
3486 * read and validated it.
3487 *
3488 * @returns iprt status code.
3489 * @param pModPe The PE module instance.
3490 * @param pOptHdr Pointer to the optional header (valid).
3491 * @param fFlags Loader flags, RTLDR_O_XXX.
3492 * @param pErrInfo Where to return extended error information. Optional.
3493 */
3494static int rtldrPEValidateDirectoriesAndRememberStuff(PRTLDRMODPE pModPe, const IMAGE_OPTIONAL_HEADER64 *pOptHdr, uint32_t fFlags,
3495 PRTERRINFO pErrInfo)
3496{
3497 const char *pszLogName = pModPe->Core.pReader->pfnLogName(pModPe->Core.pReader); NOREF(pszLogName);
3498 union /* combine stuff we're reading to help reduce stack usage. */
3499 {
3500 IMAGE_LOAD_CONFIG_DIRECTORY64 Cfg64;
3501 uint8_t abZeros[sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64_V5) * 4];
3502 } u;
3503
3504 /*
3505 * The load config entry may include lock prefix tables and whatnot which we don't implement.
3506 * It does also include a lot of stuff which we can ignore, so we'll have to inspect the
3507 * actual data before we can make up our mind about it all.
3508 */
3509 IMAGE_DATA_DIRECTORY Dir = pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG];
3510 if (Dir.Size)
3511 {
3512 const size_t cbExpectV5 = !pModPe->f64Bit
3513 ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32_V5)
3514 : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64_V5);
3515 const size_t cbExpectV4 = !pModPe->f64Bit
3516 ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32_V4)
3517 : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64_V4);
3518 const size_t cbExpectV3 = !pModPe->f64Bit
3519 ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32_V3)
3520 : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64_V3);
3521 const size_t cbExpectV2 = !pModPe->f64Bit
3522 ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32_V2)
3523 : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64_V2);
3524 const size_t cbExpectV1 = !pModPe->f64Bit
3525 ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32_V1)
3526 : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64_V2) /*No V1*/;
3527
3528 bool fNewerStructureHack = false;
3529 if ( Dir.Size != cbExpectV5
3530 && Dir.Size != cbExpectV4
3531 && Dir.Size != cbExpectV3
3532 && Dir.Size != cbExpectV2
3533 && Dir.Size != cbExpectV1)
3534 {
3535 fNewerStructureHack = Dir.Size > cbExpectV5 /* These structure changes are slowly getting to us! More futher down. */
3536 && Dir.Size <= sizeof(u);
3537 Log(("rtldrPEOpen: %s: load cfg dir: unexpected dir size of %u bytes, expected %zu, %zu, %zu, %zu, or %zu.%s\n",
3538 pszLogName, Dir.Size, cbExpectV5, cbExpectV4, cbExpectV3, cbExpectV2, cbExpectV1,
3539 fNewerStructureHack ? " Will try ignore extra bytes if all zero." : ""));
3540 if (!fNewerStructureHack)
3541 return RTErrInfoSetF(pErrInfo, VERR_LDRPE_LOAD_CONFIG_SIZE,
3542 "Unexpected load config dir size of %u bytes; supported sized: %zu, %zu, %zu, %zu, or %zu",
3543 Dir.Size, cbExpectV5, cbExpectV4, cbExpectV3, cbExpectV2, cbExpectV1);
3544 }
3545
3546 /*
3547 * Read, check new stuff and convert to 64-bit.
3548 *
3549 * If we accepted a newer structure, we check whether the new bits are
3550 * all zero. This PRAYING/ASSUMING that the nothing new weird stuff is
3551 * activated by a zero value and that it'll mostly be unused in areas
3552 * we care about (which has been the case till now).
3553 */
3554 RT_ZERO(u.Cfg64);
3555 int rc = rtldrPEReadRVA(pModPe, &u.Cfg64, Dir.Size, Dir.VirtualAddress);
3556 if (RT_FAILURE(rc))
3557 return rc;
3558 if ( fNewerStructureHack
3559 && !ASMMemIsZero(&u.abZeros[cbExpectV5], Dir.Size - cbExpectV5))
3560 {
3561 Log(("rtldrPEOpen: %s: load cfg dir: Unexpected bytes are non-zero (%u bytes of which %u expected to be zero): %.*Rhxs\n",
3562 pszLogName, Dir.Size, Dir.Size - cbExpectV5, Dir.Size - cbExpectV5, &u.abZeros[cbExpectV5]));
3563 return RTErrInfoSetF(pErrInfo, VERR_LDRPE_LOAD_CONFIG_SIZE,
3564 "Grown load config (%u to %u bytes) includes non-zero bytes: %.*Rhxs",
3565 cbExpectV5, Dir.Size, Dir.Size - cbExpectV5, &u.abZeros[cbExpectV5]);
3566 }
3567 rtldrPEConvert32BitLoadConfigTo64Bit(&u.Cfg64);
3568
3569 if (u.Cfg64.Size != Dir.Size)
3570 {
3571 /* Kludge #1: ntdll.dll from XP seen with Dir.Size=0x40 and Cfg64.Size=0x00. */
3572 if (Dir.Size == 0x40 && u.Cfg64.Size == 0x00 && !pModPe->f64Bit)
3573 {
3574 Log(("rtldrPEOpen: %s: load cfg dir: Header (%d) and directory (%d) size mismatch, applying the XP kludge.\n",
3575 pszLogName, u.Cfg64.Size, Dir.Size));
3576 u.Cfg64.Size = Dir.Size;
3577 }
3578 /* Kludge #2: This happens a lot. Structure changes, but the linker doesn't get
3579 updated and stores some old size in the directory. Use the header size. */
3580 else if ( u.Cfg64.Size == cbExpectV5
3581 || u.Cfg64.Size == cbExpectV4
3582 || u.Cfg64.Size == cbExpectV3
3583 || u.Cfg64.Size == cbExpectV2
3584 || u.Cfg64.Size == cbExpectV1
3585 || (fNewerStructureHack = (u.Cfg64.Size > cbExpectV5 && u.Cfg64.Size <= sizeof(u))) )
3586 {
3587 Log(("rtldrPEOpen: %s: load cfg dir: Header (%d) and directory (%d) size mismatch, applying the old linker kludge.\n",
3588 pszLogName, u.Cfg64.Size, Dir.Size));
3589
3590 Dir.Size = u.Cfg64.Size;
3591 uint32_t const uOrgDir = Dir.Size;
3592 RT_ZERO(u.Cfg64);
3593 rc = rtldrPEReadRVA(pModPe, &u.Cfg64, Dir.Size, Dir.VirtualAddress);
3594 if (RT_FAILURE(rc))
3595 return rc;
3596 if ( fNewerStructureHack
3597 && !ASMMemIsZero(&u.abZeros[cbExpectV5], Dir.Size - cbExpectV5))
3598 {
3599 Log(("rtldrPEOpen: %s: load cfg dir: Unknown bytes are non-zero (%u bytes of which %u expected to be zero): %.*Rhxs\n",
3600 pszLogName, Dir.Size, Dir.Size - cbExpectV5, Dir.Size - cbExpectV5, &u.abZeros[cbExpectV5]));
3601 return RTErrInfoSetF(pErrInfo, VERR_LDRPE_LOAD_CONFIG_SIZE,
3602 "Grown load config (%u to %u bytes, dir %u) includes non-zero bytes: %.*Rhxs",
3603 cbExpectV5, Dir.Size, uOrgDir, Dir.Size - cbExpectV5, &u.abZeros[cbExpectV5]);
3604 }
3605 rtldrPEConvert32BitLoadConfigTo64Bit(&u.Cfg64);
3606 AssertReturn(u.Cfg64.Size == Dir.Size,
3607 RTErrInfoSetF(pErrInfo, VERR_LDRPE_LOAD_CONFIG_SIZE, "Data changed while reading! (%d vs %d)\n",
3608 u.Cfg64.Size, Dir.Size));
3609 }
3610 else
3611 {
3612 Log(("rtldrPEOpen: %s: load cfg hdr: unexpected hdr size of %u bytes (dir %u), expected %zu, %zu, %zu, %zu, or %zu.\n",
3613 pszLogName, u.Cfg64.Size, Dir.Size, cbExpectV5, cbExpectV4, cbExpectV3, cbExpectV2, cbExpectV1));
3614 return RTErrInfoSetF(pErrInfo, VERR_LDRPE_LOAD_CONFIG_SIZE,
3615 "Unexpected load config header size of %u bytes (dir %u); supported sized: %zu, %zu, %zu, %zu, or %zu",
3616 u.Cfg64.Size, Dir.Size, cbExpectV5, cbExpectV4, cbExpectV3, cbExpectV2, cbExpectV1);
3617 }
3618 }
3619 if (u.Cfg64.LockPrefixTable && !(fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION)))
3620 {
3621 Log(("rtldrPEOpen: %s: load cfg dir: lock prefix table at %RX64. We don't support lock prefix tables!\n",
3622 pszLogName, u.Cfg64.LockPrefixTable));
3623 return RTErrInfoSetF(pErrInfo, VERR_LDRPE_LOCK_PREFIX_TABLE,
3624 "Lock prefix table not supported: %RX64", u.Cfg64.LockPrefixTable);
3625 }
3626#if 0/* this seems to be safe to ignore. */
3627 if ( u.Cfg64.SEHandlerTable
3628 || u.Cfg64.SEHandlerCount)
3629 {
3630 Log(("rtldrPEOpen: %s: load cfg dir: SEHandlerTable=%RX64 and SEHandlerCount=%RX64 are unsupported!\n",
3631 pszLogName, u.Cfg64.SEHandlerTable, u.Cfg64.SEHandlerCount));
3632 return VERR_BAD_EXE_FORMAT;
3633 }
3634#endif
3635 if (u.Cfg64.EditList && !(fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION)))
3636 {
3637 Log(("rtldrPEOpen: %s: load cfg dir: EditList=%RX64 is unsupported!\n",
3638 pszLogName, u.Cfg64.EditList));
3639 return RTErrInfoSetF(pErrInfo, VERR_BAD_EXE_FORMAT, "Load config EditList=%RX64 is not supported", u.Cfg64.EditList);
3640 }
3641 /** @todo GuardCFC? Possibly related to:
3642 * http://research.microsoft.com/pubs/69217/ccs05-cfi.pdf
3643 * Not trusting something designed by bakas who don't know how to modify a
3644 * structure without messing up its natural alignment. */
3645 if ( ( u.Cfg64.GuardCFCCheckFunctionPointer
3646 || u.Cfg64.Reserved2
3647 || u.Cfg64.GuardCFFunctionTable
3648 || u.Cfg64.GuardCFFunctionCount
3649 || u.Cfg64.GuardFlags
3650 || u.Cfg64.GuardAddressTakenIatEntryTable
3651 || u.Cfg64.GuardAddressTakenIatEntryCount
3652 || u.Cfg64.GuardLongJumpTargetTable
3653 || u.Cfg64.GuardLongJumpTargetCount)
3654 && !(fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION)) )
3655 {
3656 Log(("rtldrPEOpen: %s: load cfg dir: Guard stuff: %RX64,%RX64,%RX64,%RX64,%RX32,%RX64,%RX64,%RX64,%RX64!\n",
3657 pszLogName, u.Cfg64.GuardCFCCheckFunctionPointer, u.Cfg64.Reserved2,
3658 u.Cfg64.GuardCFFunctionTable, u.Cfg64.GuardCFFunctionCount, u.Cfg64.GuardFlags,
3659 u.Cfg64.GuardAddressTakenIatEntryTable, u.Cfg64.GuardAddressTakenIatEntryCount,
3660 u.Cfg64.GuardLongJumpTargetTable, u.Cfg64.GuardLongJumpTargetCount ));
3661 return RTErrInfoSetF(pErrInfo, VERR_LDRPE_GUARD_CF_STUFF,
3662 "Guard bits in load config: %RX64,%RX64,%RX64,%RX64,%RX32,%RX64,%RX64,%RX64,%RX64!",
3663 u.Cfg64.GuardCFCCheckFunctionPointer, u.Cfg64.Reserved2,
3664 u.Cfg64.GuardCFFunctionTable, u.Cfg64.GuardCFFunctionCount, u.Cfg64.GuardFlags,
3665 u.Cfg64.GuardAddressTakenIatEntryTable, u.Cfg64.GuardAddressTakenIatEntryCount,
3666 u.Cfg64.GuardLongJumpTargetTable, u.Cfg64.GuardLongJumpTargetCount);
3667 }
3668 }
3669
3670 /*
3671 * If the image is signed and we're not doing this for debug purposes,
3672 * take a look at the signature.
3673 */
3674 Dir = pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
3675 if (Dir.Size)
3676 {
3677 PWIN_CERTIFICATE pFirst = (PWIN_CERTIFICATE)RTMemTmpAlloc(Dir.Size);
3678 if (!pFirst)
3679 return VERR_NO_TMP_MEMORY;
3680 int rc = pModPe->Core.pReader->pfnRead(pModPe->Core.pReader, pFirst, Dir.Size, Dir.VirtualAddress);
3681 if (RT_SUCCESS(rc))
3682 {
3683 uint32_t off = 0;
3684 do
3685 {
3686 PWIN_CERTIFICATE pCur = (PWIN_CERTIFICATE)((uint8_t *)pFirst + off);
3687
3688 /* validate the members. */
3689 if ( pCur->dwLength < sizeof(WIN_CERTIFICATE)
3690 || pCur->dwLength + off > Dir.Size)
3691 {
3692 Log(("rtldrPEOpen: %s: cert at %#x/%#x: dwLength=%#x\n", pszLogName, off, Dir.Size, pCur->dwLength));
3693 rc = RTErrInfoSetF(pErrInfo, VERR_LDRPE_CERT_MALFORMED,
3694 "Cert at %#x LB %#x: Bad header length value: %#x", off, Dir.Size, pCur->dwLength);
3695 break;
3696 }
3697 if ( pCur->wRevision != WIN_CERT_REVISION_2_0
3698 && pCur->wRevision != WIN_CERT_REVISION_1_0)
3699 {
3700 Log(("rtldrPEOpen: %s: cert at %#x/%#x: wRevision=%#x\n", pszLogName, off, Dir.Size, pCur->wRevision));
3701 if (pCur->wRevision >= WIN_CERT_REVISION_1_0)
3702 rc = RTErrInfoSetF(pErrInfo, VERR_LDRPE_CERT_UNSUPPORTED,
3703 "Cert at %#x LB %#x: Unsupported revision: %#x", off, Dir.Size, pCur->wRevision);
3704 else
3705 rc = RTErrInfoSetF(pErrInfo, VERR_LDRPE_CERT_MALFORMED,
3706 "Cert at %#x LB %#x: Malformed revision: %#x", off, Dir.Size, pCur->wRevision);
3707 break;
3708 }
3709 if ( pCur->wCertificateType != WIN_CERT_TYPE_PKCS_SIGNED_DATA
3710 && pCur->wCertificateType != WIN_CERT_TYPE_X509
3711 /*&& pCur->wCertificateType != WIN_CERT_TYPE_RESERVED_1*/
3712 /*&& pCur->wCertificateType != WIN_CERT_TYPE_TS_STACK_SIGNED*/
3713 && pCur->wCertificateType != WIN_CERT_TYPE_EFI_PKCS115
3714 && pCur->wCertificateType != WIN_CERT_TYPE_EFI_GUID
3715 )
3716 {
3717 Log(("rtldrPEOpen: %s: cert at %#x/%#x: wCertificateType=%#x\n", pszLogName, off, Dir.Size, pCur->wCertificateType));
3718 if (pCur->wCertificateType)
3719 rc = RTErrInfoSetF(pErrInfo, VERR_LDRPE_CERT_UNSUPPORTED,
3720 "Cert at %#x LB %#x: Unsupported certificate type: %#x",
3721 off, Dir.Size, pCur->wCertificateType);
3722 else
3723 rc = RTErrInfoSetF(pErrInfo, VERR_LDRPE_CERT_MALFORMED,
3724 "Cert at %#x LB %#x: Malformed certificate type: %#x",
3725 off, Dir.Size, pCur->wCertificateType);
3726 break;
3727 }
3728
3729 /* Remember the first signed data certificate. */
3730 if ( pCur->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA
3731 && pModPe->offPkcs7SignedData == 0)
3732 {
3733 pModPe->offPkcs7SignedData = Dir.VirtualAddress
3734 + (uint32_t)((uintptr_t)&pCur->bCertificate[0] - (uintptr_t)pFirst);
3735 pModPe->cbPkcs7SignedData = pCur->dwLength - RT_OFFSETOF(WIN_CERTIFICATE, bCertificate);
3736 }
3737
3738 /* next */
3739 off += RT_ALIGN(pCur->dwLength, WIN_CERTIFICATE_ALIGNMENT);
3740 } while (off < Dir.Size);
3741 }
3742 RTMemTmpFree(pFirst);
3743 if (RT_FAILURE(rc) && !(fFlags & RTLDR_O_FOR_DEBUG))
3744 return rc;
3745 }
3746
3747 return VINF_SUCCESS;
3748}
3749
3750
3751/**
3752 * Open a PE image.
3753 *
3754 * @returns iprt status code.
3755 * @param pReader The loader reader instance which will provide the raw image bits.
3756 * @param fFlags Loader flags, RTLDR_O_XXX.
3757 * @param enmArch Architecture specifier.
3758 * @param offNtHdrs The offset of the NT headers (where you find "PE\0\0").
3759 * @param phLdrMod Where to store the handle.
3760 * @param pErrInfo Where to return extended error information. Optional.
3761 */
3762int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF offNtHdrs,
3763 PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo)
3764{
3765 /*
3766 * Read and validate the file header.
3767 */
3768 IMAGE_FILE_HEADER FileHdr;
3769 int rc = pReader->pfnRead(pReader, &FileHdr, sizeof(FileHdr), offNtHdrs + 4);
3770 if (RT_FAILURE(rc))
3771 return rc;
3772 RTLDRARCH enmArchImage;
3773 const char *pszLogName = pReader->pfnLogName(pReader);
3774 rc = rtldrPEValidateFileHeader(&FileHdr, fFlags, pszLogName, &enmArchImage);
3775 if (RT_FAILURE(rc))
3776 return rc;
3777
3778 /*
3779 * Match the CPU architecture.
3780 */
3781 bool fArchNoCodeCheckPending = false;
3782 if ( enmArch != enmArchImage
3783 && ( enmArch != RTLDRARCH_WHATEVER
3784 && !(fFlags & RTLDR_O_WHATEVER_ARCH)) )
3785 {
3786 if (!(fFlags & RTLDR_O_IGNORE_ARCH_IF_NO_CODE))
3787 return RTErrInfoSetF(pErrInfo, VERR_LDR_ARCH_MISMATCH, "Image is for '%s', only accepting images for '%s'.",
3788 rtldrPEGetArchName(FileHdr.Machine), rtLdrArchName(enmArch));
3789 fArchNoCodeCheckPending = true;
3790 }
3791
3792 /*
3793 * Read and validate the "optional" header. Convert 32->64 if necessary.
3794 */
3795 IMAGE_OPTIONAL_HEADER64 OptHdr;
3796 rc = pReader->pfnRead(pReader, &OptHdr, FileHdr.SizeOfOptionalHeader, offNtHdrs + 4 + sizeof(IMAGE_FILE_HEADER));
3797 if (RT_FAILURE(rc))
3798 return rc;
3799 if (FileHdr.SizeOfOptionalHeader != sizeof(OptHdr))
3800 rtldrPEConvert32BitOptionalHeaderTo64Bit(&OptHdr);
3801 rc = rtldrPEValidateOptionalHeader(&OptHdr, pszLogName, offNtHdrs, &FileHdr, pReader->pfnSize(pReader), fFlags);
3802 if (RT_FAILURE(rc))
3803 return rc;
3804 if (fArchNoCodeCheckPending && OptHdr.SizeOfCode != 0)
3805 return RTErrInfoSetF(pErrInfo, VERR_LDR_ARCH_MISMATCH,
3806 "Image is for '%s' and contains code (%#x), only accepting images for '%s' with code.",
3807 rtldrPEGetArchName(FileHdr.Machine), OptHdr.SizeOfCode, rtLdrArchName(enmArch));
3808
3809 /*
3810 * Read and validate section headers.
3811 */
3812 const size_t cbSections = sizeof(IMAGE_SECTION_HEADER) * FileHdr.NumberOfSections;
3813 PIMAGE_SECTION_HEADER paSections = (PIMAGE_SECTION_HEADER)RTMemAlloc(cbSections);
3814 if (!paSections)
3815 return VERR_NO_MEMORY;
3816 rc = pReader->pfnRead(pReader, paSections, cbSections,
3817 offNtHdrs + 4 + sizeof(IMAGE_FILE_HEADER) + FileHdr.SizeOfOptionalHeader);
3818 if (RT_SUCCESS(rc))
3819 {
3820 rc = rtldrPEValidateSectionHeaders(paSections, FileHdr.NumberOfSections, pszLogName,
3821 &OptHdr, pReader->pfnSize(pReader), fFlags, fArchNoCodeCheckPending);
3822 if (RT_SUCCESS(rc))
3823 {
3824 /*
3825 * Allocate and initialize the PE module structure.
3826 */
3827 PRTLDRMODPE pModPe = (PRTLDRMODPE)RTMemAllocZ(sizeof(*pModPe));
3828 if (pModPe)
3829 {
3830 pModPe->Core.u32Magic = RTLDRMOD_MAGIC;
3831 pModPe->Core.eState = LDR_STATE_OPENED;
3832 if (FileHdr.SizeOfOptionalHeader == sizeof(OptHdr))
3833 pModPe->Core.pOps = &s_rtldrPE64Ops.Core;
3834 else
3835 pModPe->Core.pOps = &s_rtldrPE32Ops.Core;
3836 pModPe->Core.pReader = pReader;
3837 pModPe->Core.enmFormat= RTLDRFMT_PE;
3838 pModPe->Core.enmType = FileHdr.Characteristics & IMAGE_FILE_DLL
3839 ? FileHdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED
3840 ? RTLDRTYPE_EXECUTABLE_FIXED
3841 : RTLDRTYPE_EXECUTABLE_RELOCATABLE
3842 : FileHdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED
3843 ? RTLDRTYPE_SHARED_LIBRARY_FIXED
3844 : RTLDRTYPE_SHARED_LIBRARY_RELOCATABLE;
3845 pModPe->Core.enmEndian= RTLDRENDIAN_LITTLE;
3846 pModPe->Core.enmArch = FileHdr.Machine == IMAGE_FILE_MACHINE_I386
3847 ? RTLDRARCH_X86_32
3848 : FileHdr.Machine == IMAGE_FILE_MACHINE_AMD64
3849 ? RTLDRARCH_AMD64
3850 : RTLDRARCH_WHATEVER;
3851 pModPe->pvBits = NULL;
3852 pModPe->offNtHdrs = offNtHdrs;
3853 pModPe->offEndOfHdrs = offNtHdrs + 4 + sizeof(IMAGE_FILE_HEADER) + FileHdr.SizeOfOptionalHeader + cbSections;
3854 pModPe->u16Machine = FileHdr.Machine;
3855 pModPe->fFile = FileHdr.Characteristics;
3856 pModPe->cSections = FileHdr.NumberOfSections;
3857 pModPe->paSections = paSections;
3858 pModPe->uEntryPointRVA= OptHdr.AddressOfEntryPoint;
3859 pModPe->uImageBase = (RTUINTPTR)OptHdr.ImageBase;
3860 pModPe->cbImage = OptHdr.SizeOfImage;
3861 pModPe->cbHeaders = OptHdr.SizeOfHeaders;
3862 pModPe->uTimestamp = FileHdr.TimeDateStamp;
3863 pModPe->cImports = UINT32_MAX;
3864 pModPe->f64Bit = FileHdr.SizeOfOptionalHeader == sizeof(OptHdr);
3865 pModPe->ImportDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
3866 pModPe->RelocDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
3867 pModPe->ExportDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
3868 pModPe->DebugDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
3869 pModPe->SecurityDir = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
3870 pModPe->fDllCharacteristics = OptHdr.DllCharacteristics;
3871
3872 /*
3873 * Perform validation of some selected data directories which requires
3874 * inspection of the actual data. This also saves some certificate
3875 * information.
3876 */
3877 rc = rtldrPEValidateDirectoriesAndRememberStuff(pModPe, &OptHdr, fFlags, pErrInfo);
3878 if (RT_SUCCESS(rc))
3879 {
3880 *phLdrMod = &pModPe->Core;
3881 return VINF_SUCCESS;
3882 }
3883 RTMemFree(pModPe);
3884 }
3885 else
3886 rc = VERR_NO_MEMORY;
3887 }
3888 }
3889 RTMemFree(paSections);
3890 return rc;
3891}
3892
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