source: trunk/kLdr/kLdrModPE.c@ 2947

Last change on this file since 2947 was 2947, checked in by bird, 19 years ago

Initialized pvMapping and corrected an assertion on it.

  • Property svn:keywords set to Id
File size: 70.4 KB
RevLine 
[2878]1/* $Id: kLdrModPE.c 2947 2007-01-14 08:42:53Z bird $ */
[2854]2/** @file
3 *
4 * kLdr - The Module Interpreter for the Portable Executable (PE) Format.
5 *
6 * Copyright (c) 2006 knut st. osmundsen <bird-kbuild-src@anduin.net>
7 *
8 *
9 * This file is part of kLdr.
10 *
11 * kLdr is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * kLdr is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kLdr; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <kLdr.h>
32#include "kLdrHlp.h"
33#include "kLdrInternal.h"
34#include "kLdrModPE.h"
35
[2856]36
[2854]37/*******************************************************************************
38* Defined Constants And Macros *
39*******************************************************************************/
40/** @def KLDRMODPE_STRICT
41 * Define KLDRMODPE_STRICT to enabled strict checks in KLDRMODPE. */
[2877]42#define KLDRMODPE_STRICT 1
[2854]43
44/** @def KLDRMODPE_ASSERT
45 * Assert that an expression is true when KLDR_STRICT is defined.
46 */
47#ifdef KLDRMODPE_STRICT
48# define KLDRMODPE_ASSERT(expr) kldrHlpAssert(expr)
49#else
50# define KLDRMODPE_ASSERT(expr) do {} while (0)
51#endif
52
53/** @def KLDRMODPE_RVA2TYPE
54 * Converts a RVA to a pointer of the specified type.
55 * @param pvBits The bits (image base).
56 * @param uRVA The image relative virtual address.
57 * @param type The type to cast to.
58 */
59#define KLDRMODPE_RVA2TYPE(pvBits, uRVA, type) \
[2883]60 ( (type) ((uintptr_t)(pvBits) + (uintptr_t)(uRVA)) )
[2854]61
[2857]62/** @def KLDRMODPE_VALID_RVA
63 * Checks that the specified RVA value is non-zero and within the bounds of the image.
64 * @returns true/false.
65 * @param pModPE The PE module interpreter instance.
66 * @param uRVA The RVA to validate.
67 */
68#define KLDRMODPE_VALID_RVA(pModPE, uRVA) \
69 ( (uRVA) && (uRVA) < (pModPE)->Hdrs.OptionalHeader.SizeOfImage )
[2854]70
71
[2857]72
[2854]73/*******************************************************************************
74* Structures and Typedefs *
75*******************************************************************************/
76/**
77 * Instance data for the PE module interpreter.
78 */
79typedef struct KLDRMODPE
80{
81 /** Pointer to the module. (Follows the section table.) */
82 PKLDRMOD pMod;
83 /** Pointer to the RDR mapping of the raw file bits. NULL if not mapped. */
84 const void *pvBits;
[2856]85 /** Pointer to the user mapping. */
86 const void *pvMapping;
[2854]87 /** Reserved flags. */
[2856]88 uint32_t f32Reserved;
[2854]89 /** The number of imported modules.
90 * If ~(uint32_t)0 this hasn't been determined yet. */
91 uint32_t cImportModules;
92 /** The offset of the NT headers. */
93 off_t offHdrs;
94 /** Copy of the NT headers. */
95 IMAGE_NT_HEADERS64 Hdrs;
96 /** The section header table . */
97 IMAGE_SECTION_HEADER aShdrs[1];
98} KLDRMODPE, *PKLDRMODPE;
99
100
101/*******************************************************************************
102* Internal Functions *
103*******************************************************************************/
[2855]104static int32_t kldrModPENumberOfImports(PKLDRMOD pMod, const void *pvBits);
[2857]105static int kldrModPERelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
106 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
[2854]107
[2857]108static int kldrModPEDoCreate(PKLDRRDR pRdr, off_t offNewHdr, PKLDRMODPE *ppMod);
[2899]109/*static void kldrModPEDoLoadConfigConversion(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg); */
[2857]110static int kLdrModPEDoOptionalHeaderValidation(PKLDRMODPE pModPE);
111static int kLdrModPEDoSectionHeadersValidation(PKLDRMODPE pModPE);
112static void kldrModPEDoOptionalHeaderConversion(PIMAGE_OPTIONAL_HEADER64 pOptionalHeader);
113static int kldrModPEDoForwarderQuery(PKLDRMODPE pModPE, const void *pvBits, const char *pszForwarder,
114 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind);
115static int kldrModPEDoFixups(PKLDRMODPE pModPE, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress);
116static int kldrModPEDoImports32Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc,
117 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
118static int kldrModPEDoImports64Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc,
119 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
120static int kldrModPEDoImports(PKLDRMODPE pModPE, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
121static int kldrModPEDoCallDLL(PKLDRMODPE pModPE, unsigned uOp, uintptr_t uHandle);
122static int kldrModPEDoCallTLS(PKLDRMODPE pModPE, unsigned uOp, uintptr_t uHandle);
123static int32_t kldrModPEDoCall(uintptr_t uEntrypoint, uintptr_t uHandle, uint32_t uOp, void *pvReserved);
[2854]124
[2857]125
[2854]126/**
127 * Create a loader module instance interpreting the executable image found
128 * in the specified file provider instance.
129 *
130 * @returns 0 on success and *ppMod pointing to a module instance.
131 * On failure, a non-zero OS specific error code is returned.
132 * @param pOps Pointer to the registered method table.
133 * @param pRdr The file provider instance to use.
134 * @param offNewHdr The offset of the new header in MZ files. -1 if not found.
135 * @param ppMod Where to store the module instance pointer.
136 */
137static int kldrModPECreate(PCKLDRMODOPS pOps, PKLDRRDR pRdr, off_t offNewHdr, PPKLDRMOD ppMod)
138{
139 PKLDRMODPE pModPE;
140 int rc;
141
142 /*
143 * Create the instance data and do a minimal header validation.
144 */
[2857]145 rc = kldrModPEDoCreate(pRdr, offNewHdr, &pModPE);
[2854]146 if (!rc)
147 {
148 pModPE->pMod->pOps = pOps;
149 pModPE->pMod->u32Magic = KLDRMOD_MAGIC;
150 *ppMod = pModPE->pMod;
151 return 0;
152 }
153 kldrHlpFree(pModPE);
154 return rc;
155}
156
157
158/**
159 * Separate function for reading creating the PE module instance to
160 * simplify cleanup on failure.
161 */
[2857]162static int kldrModPEDoCreate(PKLDRRDR pRdr, off_t offNewHdr, PKLDRMODPE *ppModPE)
[2854]163{
164 struct
165 {
166 uint32_t Signature;
167 IMAGE_FILE_HEADER FileHdr;
168 } s;
169 PKLDRMODPE pModPE;
170 PKLDRMOD pMod;
171 size_t cb;
172 size_t cchFilename;
173 off_t off;
174 uint32_t i;
175 int rc;
176 *ppModPE = NULL;
177
178 /*
179 * Read the signature and file header.
180 */
181 rc = kLdrRdrRead(pRdr, &s, sizeof(s), offNewHdr > 0 ? offNewHdr : 0);
182 if (rc)
183 return rc;
184 if (s.Signature != IMAGE_NT_SIGNATURE)
185 return KLDR_ERR_UNKNOWN_FORMAT;
186
187 /* sanity checks. */
[2883]188 if ( s.FileHdr.NumberOfSections > 4096
[2854]189 || ( s.FileHdr.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER32)
190 && s.FileHdr.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER64))
[2859]191 || !(s.FileHdr.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)
[2854]192 )
193 return KLDR_ERR_PE_BAD_FILE_HEADER;
194 if ( s.FileHdr.Machine != IMAGE_FILE_MACHINE_I386
195 && s.FileHdr.Machine != IMAGE_FILE_MACHINE_AMD64
196 )
197 return KLDR_ERR_PE_UNSUPPORTED_MACHINE;
198
199 /*
200 * Calc the instance size, allocate and initialize it.
201 */
202 cchFilename = kLdrHlpStrLen(kLdrRdrName(pRdr));
[2858]203 cb = KLDR_ALIGN_Z(KLDR_OFFSETOF(KLDRMODPE, aShdrs[s.FileHdr.NumberOfSections]), 16)
204 + KLDR_OFFSETOF(KLDRMOD, aSegments[s.FileHdr.NumberOfSections + 1])
[2854]205 + cchFilename + 1;
206 pModPE = (PKLDRMODPE)kldrHlpAlloc(cb);
207 if (!pModPE)
208 return KLDR_ERR_NO_MEMORY;
[2858]209 *ppModPE = pModPE;
[2854]210
211 /* KLDRMOD */
[2858]212 pMod = (PKLDRMOD)((uint8_t *)pModPE + KLDR_ALIGN_Z(KLDR_OFFSETOF(KLDRMODPE, aShdrs[s.FileHdr.NumberOfSections]), 16));
[2854]213 pMod->pvData = pModPE;
214 pMod->pRdr = pRdr;
215 pMod->pOps = NULL; /* set upon success. */
216 pMod->cSegments = s.FileHdr.NumberOfSections + 1;
217 pMod->cchFilename = cchFilename;
218 pMod->pszFilename = (char *)&pMod->aSegments[pMod->cSegments];
219 kLdrHlpMemCopy((char *)pMod->pszFilename, kLdrRdrName(pRdr), cchFilename + 1);
220 pMod->pszName = kldrHlpGetFilename(pMod->pszFilename);
221 pMod->cchName = cchFilename - (pMod->pszName - pMod->pszFilename);
222 switch (s.FileHdr.Machine)
223 {
224 case IMAGE_FILE_MACHINE_I386:
225 pMod->enmCpu = KLDRCPU_I386;
226 pMod->enmArch = KLDRARCH_X86_32;
227 pMod->enmEndian = KLDRENDIAN_LITTLE;
228 break;
229
230 case IMAGE_FILE_MACHINE_AMD64:
231 pMod->enmCpu = KLDRCPU_K8;
232 pMod->enmArch = KLDRARCH_AMD64;
233 pMod->enmEndian = KLDRENDIAN_LITTLE;
234 break;
235 default:
236 kldrHlpAssert(0);
237 break;
238 }
239 pMod->enmFmt = KLDRFMT_PE;
[2859]240 if (s.FileHdr.Characteristics & IMAGE_FILE_DLL)
[2869]241 pMod->enmType = !(s.FileHdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
[2859]242 ? KLDRTYPE_SHARED_LIBRARY_RELOCATABLE
243 : KLDRTYPE_SHARED_LIBRARY_FIXED;
244 else
[2869]245 pMod->enmType = !(s.FileHdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
[2859]246 ? KLDRTYPE_EXECUTABLE_RELOCATABLE
247 : KLDRTYPE_EXECUTABLE_FIXED;
[2854]248 pMod->u32Magic = 0; /* set upon success. */
249
250 /* KLDRMODPE */
251 pModPE->pMod = pMod;
252 pModPE->pvBits = NULL;
[2947]253 pModPE->pvMapping = NULL;
[2856]254 pModPE->f32Reserved = 0;
[2854]255 pModPE->cImportModules = ~(uint32_t)0;
256 pModPE->offHdrs = offNewHdr >= 0 ? offNewHdr : 0;
257 pModPE->Hdrs.Signature = s.Signature;
258 pModPE->Hdrs.FileHeader = s.FileHdr;
259
260 /*
261 * Read the optional header and the section table.
262 */
263 off = pModPE->offHdrs + sizeof(pModPE->Hdrs.Signature) + sizeof(pModPE->Hdrs.FileHeader);
264 rc = kLdrRdrRead(pRdr, &pModPE->Hdrs.OptionalHeader, pModPE->Hdrs.FileHeader.SizeOfOptionalHeader, off);
265 if (rc)
266 return rc;
267 if (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader != sizeof(pModPE->Hdrs.OptionalHeader))
[2857]268 kldrModPEDoOptionalHeaderConversion(&pModPE->Hdrs.OptionalHeader);
[2854]269 off += pModPE->Hdrs.FileHeader.SizeOfOptionalHeader;
270 rc = kLdrRdrRead(pRdr, &pModPE->aShdrs[0], sizeof(IMAGE_SECTION_HEADER) * pModPE->Hdrs.FileHeader.NumberOfSections, off);
271 if (rc)
272 return rc;
273
274 /*
275 * Validate the two.
276 */
[2857]277 rc = kLdrModPEDoOptionalHeaderValidation(pModPE);
[2854]278 if (rc)
279 return rc;
280 for (i = 0; i < pModPE->Hdrs.FileHeader.NumberOfSections; i++)
281 {
[2857]282 rc = kLdrModPEDoSectionHeadersValidation(pModPE);
[2854]283 if (rc)
284 return rc;
285 }
286
287 /*
288 * Setup the KLDRMOD segment array.
289 */
290 /* The implied headers section. */
291 pMod->aSegments[0].pvUser = NULL;
292 pMod->aSegments[0].pchName = "TheHeaders";
293 pMod->aSegments[0].cchName = sizeof("TheHeaders") - 1;
[2859]294 pMod->aSegments[0].enmProt = KLDRPROT_READONLY;
[2854]295 pMod->aSegments[0].cb = pModPE->Hdrs.OptionalHeader.SizeOfHeaders;
[2859]296 pMod->aSegments[0].Alignment = pModPE->Hdrs.OptionalHeader.SectionAlignment;
[2854]297 pMod->aSegments[0].LinkAddress = pModPE->Hdrs.OptionalHeader.ImageBase;
[2859]298 pMod->aSegments[0].offFile = 0;
299 pMod->aSegments[0].cbFile = pModPE->Hdrs.OptionalHeader.SizeOfHeaders;
300 pMod->aSegments[0].RVA = 0;
301 if (pMod->cSegments > 1)
302 pMod->aSegments[0].cbMapped = pModPE->aShdrs[0].VirtualAddress;
303 else
304 pMod->aSegments[0].cbMapped = pModPE->Hdrs.OptionalHeader.SizeOfHeaders;
305 pMod->aSegments[0].MapAddress = 0;
[2854]306
307 /* The section headers. */
308 for (i = 0; i < pModPE->Hdrs.FileHeader.NumberOfSections; i++)
309 {
[2883]310 const char *pch;
[2859]311
312 /* unused */
[2854]313 pMod->aSegments[i + 1].pvUser = NULL;
[2859]314 pMod->aSegments[i + 1].MapAddress = 0;
315
316 /* name */
[2883]317 pMod->aSegments[i + 1].pchName = pch = (const char *)&pModPE->aShdrs[i].Name[0];
[2854]318 cb = IMAGE_SIZEOF_SHORT_NAME;
319 while ( cb > 0
320 && (pch[cb - 1] == ' ' || pch[cb - 1] == '\0'))
321 cb--;
322 pMod->aSegments[i + 1].cchName = cb;
[2859]323
324 /* size and addresses */
[2854]325 if (!(pModPE->aShdrs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
326 {
[2859]327 pMod->aSegments[i + 1].cb = pModPE->aShdrs[i].Misc.VirtualSize;
328 pMod->aSegments[i + 1].LinkAddress = pModPE->aShdrs[i].VirtualAddress
329 + pModPE->Hdrs.OptionalHeader.ImageBase;
330 pMod->aSegments[i + 1].RVA = pModPE->aShdrs[i].VirtualAddress;
331 pMod->aSegments[i + 1].cbMapped = pModPE->aShdrs[i].Misc.VirtualSize;
332 if (i + 2 < pMod->cSegments)
333 pMod->aSegments[i + 1].cbMapped= pModPE->aShdrs[i + 1].VirtualAddress
334 - pModPE->aShdrs[i].VirtualAddress;
[2854]335 }
336 else
337 {
[2859]338 pMod->aSegments[i + 1].cb = 0;
339 pMod->aSegments[i + 1].cbMapped = 0;
[2854]340 pMod->aSegments[i + 1].LinkAddress = NIL_KLDRADDR;
[2859]341 pMod->aSegments[i + 1].RVA = 0;
[2854]342 }
[2859]343
344 /* file location */
345 pMod->aSegments[i + 1].offFile = pModPE->aShdrs[i].PointerToRawData;
346 pMod->aSegments[i + 1].cbFile = pModPE->aShdrs[i].SizeOfRawData;
347 if ( pMod->aSegments[i + 1].cbMapped > 0 /* if mapped */
348 && (KLDRSIZE)pMod->aSegments[i + 1].cbFile > pMod->aSegments[i + 1].cbMapped)
349 pMod->aSegments[i + 1].cbFile = pMod->aSegments[i + 1].cbMapped;
350
351 /* protection */
[2854]352 switch ( pModPE->aShdrs[i].Characteristics
353 & (IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE))
354 {
355 case 0:
356 case IMAGE_SCN_MEM_SHARED:
357 pMod->aSegments[i + 1].enmProt = KLDRPROT_NOACCESS;
358 break;
359 case IMAGE_SCN_MEM_READ:
360 case IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED:
361 pMod->aSegments[i + 1].enmProt = KLDRPROT_READONLY;
362 break;
363 case IMAGE_SCN_MEM_WRITE:
364 case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ:
365 pMod->aSegments[i + 1].enmProt = KLDRPROT_WRITECOPY;
366 break;
367 case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED:
368 case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ:
369 pMod->aSegments[i + 1].enmProt = KLDRPROT_READWRITE;
370 break;
371 case IMAGE_SCN_MEM_EXECUTE:
372 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_SHARED:
373 pMod->aSegments[i + 1].enmProt = KLDRPROT_EXECUTE;
374 break;
375 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ:
376 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED:
377 pMod->aSegments[i + 1].enmProt = KLDRPROT_EXECUTE_READ;
378 break;
379 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE:
380 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ:
381 pMod->aSegments[i + 1].enmProt = KLDRPROT_EXECUTE_WRITECOPY;
382 break;
383 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED:
384 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ:
385 pMod->aSegments[i + 1].enmProt = KLDRPROT_EXECUTE_READWRITE;
386 break;
387 }
[2859]388
389 /* alignment. */
[2854]390 switch (pModPE->aShdrs[i].Characteristics & IMAGE_SCN_ALIGN_MASK)
391 {
[2859]392 case 0: /* hope this is right... */
393 pMod->aSegments[i + 1].Alignment = pModPE->Hdrs.OptionalHeader.SectionAlignment;
394 break;
[2854]395 case IMAGE_SCN_ALIGN_1BYTES: pMod->aSegments[i + 1].Alignment = 1; break;
396 case IMAGE_SCN_ALIGN_2BYTES: pMod->aSegments[i + 1].Alignment = 2; break;
397 case IMAGE_SCN_ALIGN_4BYTES: pMod->aSegments[i + 1].Alignment = 4; break;
398 case IMAGE_SCN_ALIGN_8BYTES: pMod->aSegments[i + 1].Alignment = 8; break;
399 case IMAGE_SCN_ALIGN_16BYTES: pMod->aSegments[i + 1].Alignment = 16; break;
400 case IMAGE_SCN_ALIGN_32BYTES: pMod->aSegments[i + 1].Alignment = 32; break;
401 case IMAGE_SCN_ALIGN_64BYTES: pMod->aSegments[i + 1].Alignment = 64; break;
402 case IMAGE_SCN_ALIGN_128BYTES: pMod->aSegments[i + 1].Alignment = 128; break;
403 case IMAGE_SCN_ALIGN_256BYTES: pMod->aSegments[i + 1].Alignment = 256; break;
404 case IMAGE_SCN_ALIGN_512BYTES: pMod->aSegments[i + 1].Alignment = 512; break;
405 case IMAGE_SCN_ALIGN_1024BYTES: pMod->aSegments[i + 1].Alignment = 1024; break;
406 case IMAGE_SCN_ALIGN_2048BYTES: pMod->aSegments[i + 1].Alignment = 2048; break;
407 case IMAGE_SCN_ALIGN_4096BYTES: pMod->aSegments[i + 1].Alignment = 4096; break;
408 case IMAGE_SCN_ALIGN_8192BYTES: pMod->aSegments[i + 1].Alignment = 8192; break;
[2859]409 default: kldrHlpAssert(0); pMod->aSegments[i + 1].Alignment = 0; break;
[2854]410 }
411 }
412
413 /*
414 * We're done.
415 */
416 *ppModPE = pModPE;
417 return 0;
418}
419
420
421/**
422 * Converts a 32-bit optional header to a 64-bit one
423 *
424 * @param pOptHdr The optional header to convert.
425 */
[2857]426static void kldrModPEDoOptionalHeaderConversion(PIMAGE_OPTIONAL_HEADER64 pOptHdr)
[2854]427{
428 /* volatile everywhere! */
429 IMAGE_OPTIONAL_HEADER32 volatile *pOptHdr32 = (IMAGE_OPTIONAL_HEADER32 volatile *)pOptHdr;
430 IMAGE_OPTIONAL_HEADER64 volatile *pOptHdr64 = pOptHdr;
431 uint32_t volatile *pu32Dst;
432 uint32_t volatile *pu32Src;
433 uint32_t volatile *pu32SrcLast;
434 uint32_t u32;
435
436 /* From LoaderFlags and out the difference is 4 * 32-bits. */
437 pu32Dst = (uint32_t *)&pOptHdr64->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1;
438 pu32Src = (uint32_t *)&pOptHdr32->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1;
439 pu32SrcLast = (uint32_t *)&pOptHdr32->LoaderFlags;
440 while (pu32Src >= pu32SrcLast)
441 *pu32Dst-- = *pu32Src--;
442
443 /* The previous 4 fields are 32/64 and needs special attention. */
444 pOptHdr64->SizeOfHeapCommit = pOptHdr32->SizeOfHeapCommit;
445 pOptHdr64->SizeOfHeapReserve = pOptHdr32->SizeOfHeapReserve;
446 pOptHdr64->SizeOfStackCommit = pOptHdr32->SizeOfStackCommit;
447 u32 = pOptHdr32->SizeOfStackReserve;
448 pOptHdr64->SizeOfStackReserve = u32;
449
450 /*
451 * The rest matches except for BaseOfData which has been merged into ImageBase in the 64-bit version.
452 * Thus, ImageBase needs some special treatement. It will probably work fine assigning one to the
453 * other since this is all declared volatile, but taking now chances, we'll use a temp variable.
454 */
455 u32 = pOptHdr32->ImageBase;
456 pOptHdr64->ImageBase = u32;
457}
458
459
[2899]460#if 0
[2854]461/**
462 * Converts a 32-bit load config directory to a 64 bit one.
463 *
464 * @param pOptHdr The load config to convert.
465 */
[2857]466static void kldrModPEDoLoadConfigConversion(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg)
[2854]467{
468 /* volatile everywhere! */
469 IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *pLoadCfg32 = (IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *)pLoadCfg;
470 IMAGE_LOAD_CONFIG_DIRECTORY64 volatile *pLoadCfg64 = pLoadCfg;
471 uint32_t u32;
472
473 pLoadCfg64->SEHandlerCount = pLoadCfg32->SEHandlerCount;
474 pLoadCfg64->SEHandlerTable = pLoadCfg32->SEHandlerTable;
475 pLoadCfg64->SecurityCookie = pLoadCfg32->SecurityCookie;
476 pLoadCfg64->EditList = pLoadCfg32->EditList;
477 pLoadCfg64->Reserved1 = pLoadCfg32->Reserved1;
478 pLoadCfg64->CSDVersion = pLoadCfg32->CSDVersion;
479 /* (ProcessHeapFlags switched place with ProcessAffinityMask, but we're
480 * more than 16 byte off by now so it doesn't matter.) */
481 pLoadCfg64->ProcessHeapFlags = pLoadCfg32->ProcessHeapFlags;
482 pLoadCfg64->ProcessAffinityMask = pLoadCfg32->ProcessAffinityMask;
483 pLoadCfg64->VirtualMemoryThreshold = pLoadCfg32->VirtualMemoryThreshold;
484 pLoadCfg64->MaximumAllocationSize = pLoadCfg32->MaximumAllocationSize;
485 pLoadCfg64->LockPrefixTable = pLoadCfg32->LockPrefixTable;
486 pLoadCfg64->DeCommitTotalFreeThreshold = pLoadCfg32->DeCommitTotalFreeThreshold;
487 u32 = pLoadCfg32->DeCommitFreeBlockThreshold;
488 pLoadCfg64->DeCommitFreeBlockThreshold = u32;
489 /* the remainder matches. */
490}
[2899]491#endif
[2854]492
493
[2857]494/**
495 * Internal worker which validates the section headers.
496 */
497static int kLdrModPEDoOptionalHeaderValidation(PKLDRMODPE pModPE)
498{
499 const unsigned fIs32Bit = pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32);
500
501 /* the magic */
502 if ( pModPE->Hdrs.OptionalHeader.Magic
503 != (fIs32Bit ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC))
504 return KLDR_ERR_PE_BAD_OPTIONAL_HEADER;
505
506 /** @todo validate more */
507 return 0;
508}
509
510
511/**
512 * Internal worker which validates the section headers.
513 */
514static int kLdrModPEDoSectionHeadersValidation(PKLDRMODPE pModPE)
515{
516 /** @todo validate shdrs */
517 return 0;
518}
519
520
[2854]521/** @copydoc KLDRMODOPS::pfnDestroy */
522static int kldrModPEDestroy(PKLDRMOD pMod)
523{
524 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
525 int rc = 0;
[2947]526 KLDRMODPE_ASSERT(!pModPE->pvMapping);
[2854]527
528 if (pMod->pRdr)
529 {
530 rc = kLdrRdrClose(pMod->pRdr);
531 pMod->pRdr = NULL;
532 }
533 pMod->u32Magic = 0;
534 pMod->pOps = NULL;
535 kldrHlpFree(pModPE);
536 return rc;
537}
538
539
540/**
[2856]541 * Performs the mapping of the image.
542 *
543 * This can be used to do the internal mapping as well as the
544 * user requested mapping. fForReal indicates which is desired.
545 *
546 * @returns 0 on success, non-zero OS or kLdr status code on failure.
547 * @param pModPE The interpreter module instance
548 * @param fForReal If set, do the user mapping. if clear, do the internal mapping.
549 */
550static int kldrModPEDoMap(PKLDRMODPE pModPE, unsigned fForReal)
551{
[2860]552 PKLDRMOD pMod = pModPE->pMod;
553 unsigned fFixed;
554 void *pvBase;
555 int rc;
556 uint32_t i;
557
558 /*
[2861]559 * Map it.
[2860]560 */
561 /* fixed image? */
562 fFixed = fForReal
563 && ( pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
564 || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED);
565 if (!fFixed)
566 pvBase = NULL;
567 else
568 {
569 pvBase = (void *)(uintptr_t)pMod->aSegments[0].LinkAddress;
570 if ((uintptr_t)pvBase != pMod->aSegments[0].LinkAddress)
571 return KLDR_ERR_ADDRESS_OVERFLOW;
572 }
573
574 /* try do the prepare */
[2861]575 rc = kLdrRdrMap(pMod->pRdr, &pvBase, pMod->cSegments, pMod->aSegments, fFixed);
[2860]576 if (rc)
577 return rc;
578
579 /*
[2861]580 * Update the segments with their map addresses.
[2860]581 */
[2861]582 if (fForReal)
[2860]583 {
[2861]584 for (i = 0; i < pMod->cSegments; i++)
[2860]585 {
[2861]586 if (pMod->aSegments[i].RVA != NIL_KLDRADDR)
587 pMod->aSegments[i].MapAddress = (uintptr_t)pvBase + (uintptr_t)pMod->aSegments[i].RVA;
[2860]588 }
[2861]589 pModPE->pvMapping = pvBase;
[2860]590 }
591 else
[2861]592 pModPE->pvBits = pvBase;
593 return 0;
[2856]594}
595
596
597/**
598 * Unmaps a image mapping.
599 *
600 * This can be used to do the internal mapping as well as the
601 * user requested mapping. fForReal indicates which is desired.
602 *
603 * @returns 0 on success, non-zero OS or kLdr status code on failure.
604 * @param pModPE The interpreter module instance
[2857]605 * @param pvMapping The mapping to unmap.
[2856]606 */
[2857]607static int kldrModPEDoUnmap(PKLDRMODPE pModPE, const void *pvMapping)
[2856]608{
[2860]609 PKLDRMOD pMod = pModPE->pMod;
[2861]610 int rc;
[2860]611 uint32_t i;
612
613 /*
[2861]614 * Try unmap the image.
[2860]615 */
[2861]616 rc = kLdrRdrUnmap(pMod->pRdr, (void *)pvMapping, pMod->cSegments, pMod->aSegments);
617 if (rc)
618 return rc;
[2860]619
620 /*
[2861]621 * Update the segments to reflect that they aren't mapped any longer.
[2860]622 */
[2861]623 if (pModPE->pvMapping == pvMapping)
[2860]624 {
[2861]625 pModPE->pvMapping = NULL;
626 for (i = 0; i < pMod->cSegments; i++)
627 pMod->aSegments[i].MapAddress = 0;
[2860]628 }
[2861]629 if (pModPE->pvBits == pvMapping)
630 pModPE->pvBits = NULL;
[2860]631
[2861]632 return 0;
[2856]633}
634
635
636/**
[2854]637 * Gets usable bits and the right base address.
638 *
639 * @returns 0 on success.
640 * @returns A non-zero status code if the BaseAddress isn't right or some problem is encountered
641 * featch in a temp mapping the bits.
642 * @param pModPE The interpreter module instance
643 * @param ppvBits The bits address, IN & OUT.
644 * @param pBaseAddress The base address, IN & OUT. Optional.
645 */
646static int kldrModPEBitsAndBaseAddress(PKLDRMODPE pModPE, const void **ppvBits, PKLDRADDR pBaseAddress)
647{
648 int rc = 0;
649
650 /*
651 * Correct the base address.
652 *
653 * We don't use the base address for interpreting the bits in this
654 * interpreter, which makes things relativly simple.
655 */
656 if (pBaseAddress)
657 {
658 if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP)
659 *pBaseAddress = pModPE->pMod->aSegments[0].MapAddress;
660 else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK)
661 *pBaseAddress = pModPE->Hdrs.OptionalHeader.ImageBase;
662 }
663
664 /*
665 * Get bits.
666 */
[2859]667 if (ppvBits && !*ppvBits)
[2854]668 {
[2856]669 if (pModPE->pvMapping)
670 *ppvBits = pModPE->pvMapping;
[2854]671 else if (pModPE->pvBits)
672 *ppvBits = pModPE->pvBits;
673 else
674 {
[2861]675 /* create an internal mapping. */
676 rc = kldrModPEDoMap(pModPE, 0 /* not for real */);
677 if (rc)
678 return rc;
679 KLDRMODPE_ASSERT(pModPE->pvBits);
680 *ppvBits = pModPE->pvBits;
[2854]681 }
682 }
683
684 return 0;
685}
686
687
688/** @copydoc kLdrModQuerySymbol */
[2859]689static int kldrModPEQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, uint32_t iSymbol,
[2893]690 const char *pchSymbol, size_t cchSymbol, const char *pszVersion,
[2891]691 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind)
692
[2854]693{
694 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
695 const uint32_t *paExportRVAs;
696 const IMAGE_EXPORT_DIRECTORY *pExpDir;
697 uint32_t iExpOrd;
698 uint32_t uRVA;
699 int rc;
700
701 /*
702 * Make sure we've got mapped bits and resolve any base address aliases.
703 */
704 rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, &BaseAddress);
705 if (rc)
706 return rc;
707 if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size
708 < sizeof(IMAGE_EXPORT_DIRECTORY))
709 return KLDR_ERR_SYMBOL_NOT_FOUND;
[2891]710 if (pszVersion && *pszVersion)
711 return KLDR_ERR_SYMBOL_NOT_FOUND;
[2854]712
713 pExpDir = KLDRMODPE_RVA2TYPE(pvBits,
714 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,
715 PIMAGE_EXPORT_DIRECTORY);
[2891]716 if (!pchSymbol)
[2854]717 {
718 /*
719 * Simple, calculate the unbased ordinal and bounds check it.
720 */
[2859]721 iExpOrd = iSymbol - pExpDir->Base;
[2854]722 if (iExpOrd >= KLDR_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions))
723 return KLDR_ERR_SYMBOL_NOT_FOUND;
724 }
725 else
726 {
727 /*
728 * Do a binary search for the name.
729 * (The name table is sorted in ascending ordered by the linker.)
730 */
731 const uint32_t *paRVANames = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, const uint32_t *);
732 const uint16_t *paOrdinals = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, const uint16_t *);
733 int32_t iStart = 1; /* one based binary searching is simpler. */
734 int32_t iEnd = pExpDir->NumberOfNames;
735
736 for (;;)
737 {
738 int32_t i;
739 int diff;
740 const char *pszName;
741
742 /* done? */
743 if (iStart > iEnd)
744 {
745#ifdef KLDRMODPE_STRICT /* Make sure the linker and we both did our job right. */
[2877]746 for (i = 0; i < (int32_t)pExpDir->NumberOfNames; i++)
[2854]747
748 {
749 pszName = KLDRMODPE_RVA2TYPE(pvBits, paRVANames[i], const char *);
[2891]750 KLDRMODPE_ASSERT(kLdrHlpStrNComp(pszName, pchSymbol, cchSymbol) || pszName[cchSymbol]);
[2854]751 KLDRMODPE_ASSERT(i == 0 || kLdrHlpStrComp(pszName, KLDRMODPE_RVA2TYPE(pvBits, paRVANames[i - 1], const char *)));
752 }
753#endif
754 return KLDR_ERR_SYMBOL_NOT_FOUND;
755 }
756
757 i = (iEnd - iStart) / 2 + iStart;
758 pszName = KLDRMODPE_RVA2TYPE(pvBits, paRVANames[i - 1], const char *);
[2891]759 diff = kLdrHlpStrNComp(pszName, pchSymbol, cchSymbol);
760 if (!diff)
761 diff = pszName[cchSymbol] - 0;
[2854]762 if (diff < 0)
763 iStart = i + 1; /* The symbol must be after the current name. */
764 else if (diff)
765 iEnd = i - 1; /* The symbol must be before the current name. */
766 else
767 {
768 iExpOrd = paOrdinals[i - 1]; /* match! */
769 break;
770 }
771 }
772 }
773
774 /*
775 * Lookup the address in the 'symbol' table.
776 */
777 paExportRVAs = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfFunctions, const uint32_t *);
778 uRVA = paExportRVAs[iExpOrd];
779 if ( uRVA - pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
780 < pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
[2857]781 return kldrModPEDoForwarderQuery(pModPE, pvBits, KLDRMODPE_RVA2TYPE(pvBits, uRVA, const char *),
782 pfnGetForwarder, pvUser, puValue, pfKind);
[2854]783
784 /*
785 * Set the return value.
786 */
787 if (puValue)
788 *puValue = BaseAddress + uRVA;
789 if (pfKind)
790 *pfKind = (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
791 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT)
792 | KLDRSYMKIND_NO_TYPE;
793 return 0;
794}
795
796
797/**
798 * Deal with a forwarder entry.
799 *
800 * We do this seprately from kldrModPEQuerySymbol because the code is clumsy (as is all PE code
801 * thanks to the descriptive field names), and because it uses quite a bit more stack and we're
802 * trying to avoid allocating stack unless we have to.
803 *
804 * @returns See kLdrModQuerySymbol.
805 * @param pModPE The PE module interpreter instance.
806 * @param pvBits Where to read the image from.
807 * @param pszForwarder The forwarder entry name.
808 * @param pfnGetForwarder The callback for resolving forwarder symbols. (optional)
809 * @param pvUser The user argument for the callback.
810 * @param puValue Where to put the value. (optional)
811 * @param pfKind Where to put the symbol kind. (optional)
812 */
[2857]813static int kldrModPEDoForwarderQuery(PKLDRMODPE pModPE, const void *pvBits, const char *pszForwarder,
814 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind)
[2854]815{
816 const IMAGE_IMPORT_DESCRIPTOR *paImpDir;
817 uint32_t iImpModule;
818 uint32_t cchImpModule;
819 const char *pszSymbol;
[2859]820 uint32_t iSymbol;
[2854]821 int rc;
822
823 if (!pfnGetForwarder)
824 return KLDR_ERR_FORWARDER_SYMBOL;
825
826 /*
827 * Separate the name into a module name and a symbol name or ordinal.
828 *
829 * The module name ends at the first dot ('.').
830 * After the dot follows either a symbol name or a hash ('#') + ordinal.
831 */
832 pszSymbol = pszForwarder;
833 while (*pszSymbol != '.')
834 pszSymbol++;
835 if (!*pszSymbol)
836 return KLDR_ERR_PE_BAD_FORWARDER;
837 cchImpModule = pszSymbol - pszForwarder;
838
839 pszSymbol++; /* skip the dot */
840 if (!*pszSymbol)
841 return KLDR_ERR_PE_BAD_FORWARDER;
842 if (*pszSymbol == '#')
843 {
844 unsigned uBase;
845 pszSymbol++; /* skip the hash */
846
847 /* base detection */
848 uBase = 10;
849 if (pszSymbol[0] == '0' && (pszSymbol[1] == 'x' || pszSymbol[1] == 'X'))
850 {
851 uBase = 16;
852 pszSymbol += 2;
853 }
854
855 /* ascii to integer */
[2859]856 iSymbol = 0;
[2854]857 for (;;)
858 {
859 /* convert char to digit. */
860 unsigned uDigit = *pszSymbol++;
861 if (uDigit >= '0' && uDigit <= '9')
862 uDigit -= '0';
863 else if (uDigit >= 'a' && uDigit <= 'z')
864 uDigit -= 'a' + 10;
865 else if (uDigit >= 'A' && uDigit <= 'Z')
866 uDigit -= 'A' + 10;
867 else if (!uDigit)
868 break;
869 else
870 return KLDR_ERR_PE_BAD_FORWARDER;
871 if (uDigit >= uBase)
872 return KLDR_ERR_PE_BAD_FORWARDER;
873
874 /* insert the digit */
[2859]875 iSymbol *= uBase;
876 iSymbol += uDigit;
[2854]877 }
878
879 pszSymbol = NULL; /* no symbol name. */
880 }
881 else
[2859]882 iSymbol = NIL_KLDRMOD_SYM_ORDINAL; /* no ordinal number. */
[2854]883
884
885 /*
886 * Find the import module name.
887 *
888 * We ASSUME the linker will make sure there is an import
889 * entry for the module... not sure if this is right though.
890 */
[2855]891 if ( !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
892 || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
893 return KLDR_ERR_PE_FORWARDER_IMPORT_NOT_FOUND;
[2854]894 paImpDir = KLDRMODPE_RVA2TYPE(pvBits,
895 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
896 const IMAGE_IMPORT_DESCRIPTOR *);
[2855]897
898 kldrModPENumberOfImports(pModPE->pMod, pvBits);
899 for (iImpModule = 0; iImpModule < pModPE->cImportModules; iImpModule++)
[2854]900 {
[2855]901 const char *pszName = KLDRMODPE_RVA2TYPE(pvBits, paImpDir[iImpModule].Name, const char *);
902 size_t cchName = kLdrHlpStrLen(pszName);
[2854]903 if ( ( cchName == cchImpModule
904 || ( cchName > cchImpModule
905 && pszName[cchImpModule] == '.'
906 && (pszName[cchImpModule + 1] == 'd' || pszName[cchImpModule + 1] == 'D')
907 && (pszName[cchImpModule + 2] == 'l' || pszName[cchImpModule + 2] == 'L')
908 && (pszName[cchImpModule + 3] == 'l' || pszName[cchImpModule + 3] == 'L'))
909 )
910 && kLdrHlpMemIComp(pszName, pszForwarder, cchImpModule)
911 )
[2855]912 {
913 /*
914 * Now the rest is up to the callback (almost).
915 */
[2893]916 rc = pfnGetForwarder(pModPE->pMod, iImpModule, iSymbol, pszSymbol,
[2891]917 pszSymbol ? kLdrHlpStrLen(pszSymbol) : 0, NULL, puValue, pfKind, pvUser);
[2855]918 if (!rc && pfKind)
919 *pfKind |= KLDRSYMKIND_FORWARDER;
920 return rc;
921 }
[2854]922 }
[2855]923 return KLDR_ERR_PE_FORWARDER_IMPORT_NOT_FOUND;
[2854]924}
925
926
927/** @copydoc kLdrModEnumSymbols */
[2858]928static int kldrModPEEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
929 uint32_t fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
[2854]930{
931 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
932 const uint32_t *paFunctions;
933 const IMAGE_EXPORT_DIRECTORY *pExpDir;
934 const uint32_t *paRVANames;
935 const uint16_t *paOrdinals;
936 uint32_t iFunction;
937 uint32_t cFunctions;
938 uint32_t cNames;
939 int rc;
940
941 /*
942 * Make sure we've got mapped bits and resolve any base address aliases.
943 */
944 rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, &BaseAddress);
945 if (rc)
946 return rc;
947
948 if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size
949 < sizeof(IMAGE_EXPORT_DIRECTORY))
[2859]950 return 0; /* no exports to enumerate, return success. */
951
[2854]952 pExpDir = KLDRMODPE_RVA2TYPE(pvBits,
953 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,
954 PIMAGE_EXPORT_DIRECTORY);
955
956 /*
957 * Enumerate the ordinal exports.
958 */
959 paRVANames = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, const uint32_t *);
960 paOrdinals = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, const uint16_t *);
961 paFunctions = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfFunctions, const uint32_t *);
962 cFunctions = pExpDir->NumberOfFunctions;
963 cNames = pExpDir->NumberOfNames;
964 for (iFunction = 0; iFunction < cFunctions; iFunction++)
965 {
966 unsigned fFoundName;
967 uint32_t iName;
968 const uint32_t uRVA = paFunctions[iFunction];
969 const KLDRADDR uValue = BaseAddress + uRVA;
970 uint32_t fKind = (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
971 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT)
972 | KLDRSYMKIND_NO_TYPE;
973 if ( uRVA - pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
974 < pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
975 fKind |= KLDRSYMKIND_FORWARDER;
976
977 /*
978 * Any symbol names?
979 */
980 fFoundName = 0;
981 for (iName = 0; iName < cNames; iName++)
982 {
[2891]983 const char *pszName;
[2859]984 if (paOrdinals[iName] != iFunction)
[2854]985 continue;
986 fFoundName = 1;
[2891]987 pszName = KLDRMODPE_RVA2TYPE(pvBits, paRVANames[iName], const char *);
988 rc = pfnCallback(pMod, iFunction + pExpDir->Base, pszName, kLdrHlpStrLen(pszName), NULL,
[2854]989 uValue, fKind, pvUser);
990 if (rc)
991 return rc;
992 }
993
994 /*
995 * If no names, call once with the ordinal only.
996 */
997 if (!fFoundName)
998 {
[2891]999 rc = pfnCallback(pMod, iFunction + pExpDir->Base, NULL, 0, NULL, uValue, fKind, pvUser);
[2854]1000 if (rc)
1001 return rc;
1002 }
1003 }
1004
1005 return 0;
1006}
1007
1008
1009/** @copydoc kLdrModGetImport */
[2858]1010static int kldrModPEGetImport(PKLDRMOD pMod, const void *pvBits, uint32_t iImport, char *pszName, size_t cchName)
[2855]1011{
1012 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1013 const IMAGE_IMPORT_DESCRIPTOR *pImpDesc;
1014 const char *pszImportName;
1015 size_t cchImportName;
1016 int rc;
1017
1018 /*
1019 * Make sure we've got mapped bits and resolve any base address aliases.
1020 */
1021 rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, NULL);
1022 if (rc)
1023 return rc;
1024
1025 /*
1026 * Simple bounds check.
1027 */
1028 if (iImport >= (uint32_t)kldrModPENumberOfImports(pMod, pvBits))
1029 return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
1030
1031 /*
1032 * Get the name.
1033 */
1034 pImpDesc = KLDRMODPE_RVA2TYPE(pvBits,
1035 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress
1036 + sizeof(IMAGE_IMPORT_DESCRIPTOR) * iImport,
1037 const IMAGE_IMPORT_DESCRIPTOR *);
1038 pszImportName = KLDRMODPE_RVA2TYPE(pvBits, pImpDesc->Name, const char *);
[2883]1039 cchImportName = kLdrHlpStrLen(pszImportName);
[2855]1040 if (cchImportName < cchName)
1041 {
1042 kLdrHlpMemCopy(pszName, pszImportName, cchImportName + 1);
1043 rc = 0;
1044 }
1045 else
1046 {
1047 kLdrHlpMemCopy(pszName, pszImportName, cchName);
1048 if (cchName)
1049 pszName[cchName - 1] = '\0';
1050 rc = KLDR_ERR_BUFFER_OVERFLOW;
1051 }
1052
1053 return rc;
1054}
1055
1056
[2854]1057/** @copydoc kLdrModNumberOfImports */
[2855]1058static int32_t kldrModPENumberOfImports(PKLDRMOD pMod, const void *pvBits)
1059{
1060 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1061 if (pModPE->cImportModules == ~(uint32_t)0)
1062 {
1063 /*
1064 * We'll have to walk the import descriptors to figure out their number.
[2856]1065 * First, make sure we've got mapped bits.
[2855]1066 */
1067 if (kldrModPEBitsAndBaseAddress(pModPE, &pvBits, NULL))
1068 return -1;
1069 pModPE->cImportModules = 0;
1070 if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
1071 && pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
1072 {
1073 const IMAGE_IMPORT_DESCRIPTOR *pImpDesc;
1074
1075 pImpDesc = KLDRMODPE_RVA2TYPE(pvBits,
1076 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
1077 const IMAGE_IMPORT_DESCRIPTOR *);
1078 while (pImpDesc->Name && pImpDesc->FirstThunk)
1079 {
[2859]1080 pModPE->cImportModules++;
[2855]1081 pImpDesc++;
1082 }
1083 }
1084 }
1085 return pModPE->cImportModules;
1086}
1087
1088
[2854]1089/** @copydoc kLdrModGetStackInfo */
[2855]1090static int kldrModPEGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
1091{
1092 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1093
1094 pStackInfo->Address = NIL_KLDRADDR;
1095 pStackInfo->LinkAddress = NIL_KLDRADDR;
1096 pStackInfo->cbStack = pStackInfo->cbStackThread = pModPE->Hdrs.OptionalHeader.SizeOfStackReserve;
1097
1098 return 0;
1099}
1100
1101
[2854]1102/** @copydoc kLdrModQueryMainEntrypoint */
[2855]1103static int kldrModPEQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
1104{
1105 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1106 int rc;
1107
[2856]1108 /*
1109 * Resolve base address alias if any.
1110 */
[2855]1111 rc = kldrModPEBitsAndBaseAddress(pModPE, NULL, &BaseAddress);
1112 if (rc)
1113 return rc;
1114
[2856]1115 /*
1116 * Convert the address from the header.
1117 */
[2855]1118 *pMainEPAddress = pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint
1119 ? BaseAddress + pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint
1120 : NIL_KLDRADDR;
1121 return 0;
1122}
1123
1124
[2854]1125/** @copydoc kLdrModEnumDbgInfo */
[2856]1126static int kldrModPEEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
1127{
1128 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1129 const IMAGE_DEBUG_DIRECTORY *pDbgDir;
1130 uint32_t iDbgInfo;
1131 uint32_t cb;
1132 int rc;
[2855]1133
[2856]1134 /*
1135 * Check that there is a debug directory first.
1136 */
1137 cb = pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
1138 if ( cb < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
1139 || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
1140 return 0;
1141
1142 /*
1143 * Make sure we've got mapped bits.
1144 */
1145 rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, NULL);
1146 if (rc)
1147 return rc;
1148
1149 /*
1150 * Enumerate the debug directory.
1151 */
1152 pDbgDir = KLDRMODPE_RVA2TYPE(pvBits,
1153 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress,
1154 const IMAGE_DEBUG_DIRECTORY *);
1155 for (iDbgInfo = 0;; iDbgInfo++, pDbgDir++, cb -= sizeof(IMAGE_DEBUG_DIRECTORY))
1156 {
1157 KLDRDBGINFOTYPE enmDbgInfoType;
1158
1159 /* convert the type. */
1160 switch (pDbgDir->Type)
1161 {
1162 case IMAGE_DEBUG_TYPE_UNKNOWN:
1163 case IMAGE_DEBUG_TYPE_FPO:
[2883]1164 case IMAGE_DEBUG_TYPE_COFF: /*stabs dialect??*/
[2856]1165 case IMAGE_DEBUG_TYPE_MISC:
1166 case IMAGE_DEBUG_TYPE_EXCEPTION:
1167 case IMAGE_DEBUG_TYPE_FIXUP:
1168 case IMAGE_DEBUG_TYPE_BORLAND:
1169 default:
1170 enmDbgInfoType = KLDRDBGINFOTYPE_UNKNOWN;
1171 break;
1172 case IMAGE_DEBUG_TYPE_CODEVIEW:
1173 enmDbgInfoType = KLDRDBGINFOTYPE_CODEVIEW;
1174 break;
1175 }
1176
1177 rc = pfnCallback(pMod, iDbgInfo,
1178 enmDbgInfoType, pDbgDir->MajorVersion, pDbgDir->MinorVersion,
1179 pDbgDir->PointerToRawData ? pDbgDir->PointerToRawData : -1,
1180 pDbgDir->AddressOfRawData ? pDbgDir->AddressOfRawData : NIL_KLDRADDR,
1181 pDbgDir->SizeOfData,
1182 NULL,
1183 pvUser);
1184 if (rc)
1185 break;
1186
1187 /* next */
1188 if (cb <= sizeof(IMAGE_DEBUG_DIRECTORY))
1189 break;
1190 }
1191
1192 return rc;
1193}
1194
1195
[2854]1196/** @copydoc kLdrModHasDbgInfo */
[2856]1197static int kldrModPEHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
1198{
1199 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1200
1201 /*
1202 * Base this entirely on the presence of a debug directory.
1203 */
1204 if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size
1205 < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
1206 || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
1207 return KLDR_ERR_NO_DEBUG_INFO;
1208 return 0;
1209}
1210
1211
[2854]1212/** @copydoc kLdrModMap */
[2856]1213static int kldrModPEMap(PKLDRMOD pMod)
1214{
1215 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1216 int rc;
1217
1218 /*
1219 * Already mapped?
1220 */
1221 if (pModPE->pvMapping)
1222 return KLDR_ERR_ALREADY_MAPPED;
1223
1224 /*
1225 * We've got a common worker which does this.
1226 */
1227 rc = kldrModPEDoMap(pModPE, 1 /* the real thing */);
1228 if (rc)
1229 return rc;
1230 KLDRMODPE_ASSERT(pModPE->pvMapping);
1231 return 0;
1232}
1233
1234
[2854]1235/** @copydoc kLdrModUnmap */
[2856]1236static int kldrModPEUnmap(PKLDRMOD pMod)
1237{
1238 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1239 int rc;
1240
1241 /*
1242 * Mapped?
1243 */
1244 if (!pModPE->pvMapping)
1245 return KLDR_ERR_NOT_MAPPED;
1246
1247 /*
1248 * We've got a common worker which does this.
1249 */
[2857]1250 rc = kldrModPEDoUnmap(pModPE, pModPE->pvMapping);
[2856]1251 if (rc)
1252 return rc;
1253 KLDRMODPE_ASSERT(pModPE->pvMapping);
1254 return 0;
1255
1256}
1257
1258
[2854]1259/** @copydoc kLdrModAllocTLS */
[2856]1260static int kldrModPEAllocTLS(PKLDRMOD pMod)
1261{
1262 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1263
1264 /*
1265 * Mapped?
1266 */
1267 if (!pModPE->pvMapping)
1268 return KLDR_ERR_NOT_MAPPED;
1269
1270 /*
1271 * If no TLS directory then there is nothing to do.
1272 */
1273 if ( !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size
1274 || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress)
1275 return 0;
1276 /** @todo implement TLS. */
1277 return -1;
1278}
1279
1280
[2854]1281/** @copydoc kLdrModFreeTLS */
[2856]1282static void kldrModPEFreeTLS(PKLDRMOD pMod)
1283{
1284 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1285
1286 /*
1287 * Mapped?
1288 */
1289 if (!pModPE->pvMapping)
1290 return;
1291
1292 /*
1293 * If no TLS directory then there is nothing to do.
1294 */
1295 if ( !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size
1296 || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress)
1297 return;
1298 /** @todo implement TLS. */
1299 return;
1300}
1301
1302
[2854]1303/** @copydoc kLdrModReload */
[2856]1304static int kldrModPEReload(PKLDRMOD pMod)
1305{
[2861]1306 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
[2856]1307
1308 /*
1309 * Mapped?
1310 */
1311 if (!pModPE->pvMapping)
1312 return KLDR_ERR_NOT_MAPPED;
1313
[2861]1314 /* the file provider does it all */
1315 return kLdrRdrRefresh(pMod->pRdr, (void *)pModPE->pvMapping, pMod->cSegments, pMod->aSegments);
[2856]1316}
1317
1318
[2854]1319/** @copydoc kLdrModFixupMapping */
[2856]1320static int kldrModPEFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1321{
1322 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1323 int rc, rc2;
1324
1325 /*
1326 * Mapped?
1327 */
1328 if (!pModPE->pvMapping)
1329 return KLDR_ERR_NOT_MAPPED;
1330
1331 /*
1332 * Before doing anything we'll have to make all pages writable.
1333 */
[2861]1334 rc = kLdrRdrProtect(pMod->pRdr, (void *)pModPE->pvMapping, pMod->cSegments, pMod->aSegments, 1 /* unprotect */);
[2856]1335 if (rc)
1336 return rc;
1337
1338 /*
[2857]1339 * Apply base relocations.
[2856]1340 */
[2857]1341 rc = kldrModPEDoFixups(pModPE, (void *)pModPE->pvMapping, (uintptr_t)pModPE->pvMapping,
1342 pModPE->Hdrs.OptionalHeader.ImageBase);
[2856]1343
1344 /*
1345 * Resolve imports.
1346 */
1347 if (!rc)
1348 rc = kldrModPEDoImports(pModPE, (void *)pModPE->pvMapping, pfnGetImport, pvUser);
1349
1350 /*
1351 * Restore protection.
1352 */
[2861]1353 rc2 = kLdrRdrProtect(pMod->pRdr, (void *)pModPE->pvMapping, pMod->cSegments, pMod->aSegments, 0 /* protect */);
[2856]1354 if (!rc && rc2)
1355 rc = rc2;
1356 return rc;
1357}
1358
1359
[2857]1360/**
1361 * Applies base relocations to a (unprotected) image mapping.
1362 *
1363 * @returns 0 on success, non-zero kLdr status code on failure.
1364 * @param pModPE The PE module interpreter instance.
1365 * @param pvMapping The mapping to fixup.
1366 * @param NewBaseAddress The address to fixup the mapping to.
1367 * @param OldBaseAddress The address the mapping is currently fixed up to.
1368 */
1369static int kldrModPEDoFixups(PKLDRMODPE pModPE, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress)
1370{
1371 const KLDRADDR Delta = NewBaseAddress - OldBaseAddress;
1372 uint32_t cbLeft = pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
1373 const IMAGE_BASE_RELOCATION *pBR, *pFirstBR;
1374
1375 /*
1376 * Don't don anything if the delta is 0 or there aren't any relocations.
1377 */
1378 if ( !Delta
1379 || !cbLeft
1380 || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
1381 return 0;
1382
1383 /*
1384 * Process the fixups block by block.
1385 * (These blocks appears to be 4KB on all archs despite the native page size.)
1386 */
1387 pBR = pFirstBR = KLDRMODPE_RVA2TYPE(pvMapping,
1388 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
1389 const IMAGE_BASE_RELOCATION *);
1390 while ( cbLeft > sizeof(IMAGE_BASE_RELOCATION)
1391 && pBR->SizeOfBlock >= sizeof(IMAGE_BASE_RELOCATION) /* paranoia */)
1392 {
1393 union
1394 {
1395 uint8_t *pu8;
1396 uint16_t *pu16;
1397 uint32_t *pu32;
1398 uint64_t *pu64;
1399 } uChunk,
1400 u;
1401 const uint16_t *poffFixup = (const uint16_t *)(pBR + 1);
1402 const uint32_t cbBlock = KLDR_MIN(cbLeft, pBR->SizeOfBlock) - sizeof(IMAGE_BASE_RELOCATION); /* more caution... */
1403 uint32_t cFixups = cbBlock / sizeof(poffFixup[0]);
1404 uChunk.pu8 = KLDRMODPE_RVA2TYPE(pvMapping, pBR->VirtualAddress, uint8_t *);
1405
1406 /*
1407 * Loop thru the fixups in this chunk.
1408 */
1409 while (cFixups > 0)
1410 {
1411 u.pu8 = uChunk.pu8 + (*poffFixup & 0xfff);
1412 switch (*poffFixup >> 12) /* ordered by value. */
1413 {
1414 /* 0 - Alignment placeholder. */
1415 case IMAGE_REL_BASED_ABSOLUTE:
1416 break;
1417
1418 /* 1 - 16-bit, add 2nd 16-bit part of the delta. (rare) */
1419 case IMAGE_REL_BASED_HIGH:
1420 *u.pu16 += (uint16_t)(Delta >> 16);
1421 break;
1422
1423 /* 2 - 16-bit, add 1st 16-bit part of the delta. (rare) */
1424 case IMAGE_REL_BASED_LOW:
1425 *u.pu16 += (uint16_t)Delta;
1426 break;
1427
1428 /* 3 - 32-bit, add delta. (frequent in 32-bit images) */
1429 case IMAGE_REL_BASED_HIGHLOW:
1430 *u.pu32 += (uint32_t)Delta;
1431 break;
1432
1433 /* 4 - 16-bit, add 2nd 16-bit of the delta, sign adjust for the lower 16-bit. one arg. (rare) */
1434 case IMAGE_REL_BASED_HIGHADJ:
1435 {
1436 int32_t i32;
1437 if (cFixups <= 1)
1438 return KLDR_ERR_PE_BAD_FIXUP;
1439
1440 i32 = (uint32_t)*u.pu16 << 16;
1441 i32 |= *++poffFixup; cFixups--; /* the addend argument */
1442 i32 += (uint32_t)Delta;
1443 i32 += 0x8000;
1444 *u.pu16 = (uint16_t)(i32 >> 16);
1445 break;
1446 }
1447
1448 /* 5 - 32-bit MIPS JMPADDR, no implemented. */
1449 case IMAGE_REL_BASED_MIPS_JMPADDR:
[2883]1450 *u.pu32 = (*u.pu32 & 0xc0000000)
[2857]1451 | ((uint32_t)((*u.pu32 << 2) + (uint32_t)Delta) >> 2);
1452 break;
1453
1454 /* 6 - Intra section? Reserved value in later specs. Not implemented. */
1455 case IMAGE_REL_BASED_SECTION:
1456 KLDRMODPE_ASSERT(!"SECTION");
1457 return KLDR_ERR_PE_BAD_FIXUP;
1458
1459 /* 7 - Relative intra section? Reserved value in later specs. Not implemented. */
1460 case IMAGE_REL_BASED_REL32:
1461 KLDRMODPE_ASSERT(!"SECTION");
1462 return KLDR_ERR_PE_BAD_FIXUP;
1463
1464 /* 8 - reserved according to binutils... */
1465 case 8:
1466 KLDRMODPE_ASSERT(!"RESERVERED8");
1467 return KLDR_ERR_PE_BAD_FIXUP;
1468
1469 /* 9 - IA64_IMM64 (/ MIPS_JMPADDR16), no specs nor need to support the platform yet.
1470 * Bet this requires more code than all the other fixups put together in good IA64 spirit :-) */
1471 case IMAGE_REL_BASED_IA64_IMM64:
1472 KLDRMODPE_ASSERT(!"IA64_IMM64 / MIPS_JMPADDR16");
1473 return KLDR_ERR_PE_BAD_FIXUP;
1474
1475 /* 10 - 64-bit, add delta. (frequently in 64-bit images) */
1476 case IMAGE_REL_BASED_DIR64:
1477 *u.pu64 += (uint64_t)Delta;
1478 break;
1479
1480 /* 11 - 16-bit, add 3rd 16-bit of the delta, sign adjust for the lower 32-bit. two args. (rare) */
1481 case IMAGE_REL_BASED_HIGH3ADJ:
1482 {
1483 int64_t i64;
1484 if (cFixups <= 2)
1485 return KLDR_ERR_PE_BAD_FIXUP;
1486
1487 i64 = (uint64_t)*u.pu16 << 32
1488 | ((uint32_t)poffFixup[2] << 16)
1489 | poffFixup[1];
1490 i64 += Delta;
1491 i64 += 0x80008000UL;
1492 *u.pu16 = (uint16_t)(i64 >> 32);
1493 /* skip the addends arguments */
1494 poffFixup += 2;
1495 cFixups -= 2;
1496 break;
1497 }
1498
1499 /* the rest are yet to be defined.*/
1500 default:
1501 return KLDR_ERR_PE_BAD_FIXUP;
1502 }
1503
1504 /*
1505 * Next relocation.
1506 */
1507 poffFixup++;
1508 cFixups--;
1509 }
1510
1511
1512 /*
1513 * Next block.
1514 */
1515 cbLeft -= pBR->SizeOfBlock;
1516 pBR = (PIMAGE_BASE_RELOCATION)((uintptr_t)pBR + pBR->SizeOfBlock);
1517 }
1518
1519 return 0;
1520}
1521
1522
1523
1524/**
1525 * Resolves imports.
1526 *
1527 * @returns 0 on success, non-zero kLdr status code on failure.
1528 * @param pModPE The PE module interpreter instance.
1529 * @param pvMapping The mapping which imports should be resolved.
1530 * @param pfnGetImport The callback for resolving an imported symbol.
1531 * @param pvUser User argument to the callback.
1532 */
1533static int kldrModPEDoImports(PKLDRMODPE pModPE, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1534{
1535 const IMAGE_IMPORT_DESCRIPTOR *pImpDesc;
1536
1537 /*
1538 * If no imports, there is nothing to do.
1539 */
1540 kldrModPENumberOfImports(pModPE->pMod, pvMapping);
1541 if (!pModPE->cImportModules)
1542 return 0;
1543
1544 pImpDesc = KLDRMODPE_RVA2TYPE(pvMapping,
1545 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
1546 const IMAGE_IMPORT_DESCRIPTOR *);
1547 if (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
1548 return kldrModPEDoImports32Bit(pModPE, pvMapping, pImpDesc, pfnGetImport, pvUser);
1549 return kldrModPEDoImports64Bit(pModPE, pvMapping, pImpDesc, pfnGetImport, pvUser);
1550}
1551
1552
1553/**
1554 * Resolves imports, 32-bit image.
1555 *
1556 * @returns 0 on success, non-zero kLdr status code on failure.
1557 * @param pModPE The PE module interpreter instance.
1558 * @param pvMapping The mapping which imports should be resolved.
1559 * @param pImpDesc Pointer to the first import descriptor.
1560 * @param pfnGetImport The callback for resolving an imported symbol.
1561 * @param pvUser User argument to the callback.
1562 */
1563static int kldrModPEDoImports32Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc,
1564 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1565{
1566 PKLDRMOD pMod = pModPE->pMod;
1567 uint32_t iImp;
1568
1569 /*
1570 * Iterate the import descriptors.
1571 */
1572 for (iImp = 0; iImp < pModPE->cImportModules; iImp++, pImpDesc++)
1573 {
1574 PIMAGE_THUNK_DATA32 pFirstThunk = KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, PIMAGE_THUNK_DATA32);
1575 const IMAGE_THUNK_DATA32 *pThunk = pImpDesc->u.OriginalFirstThunk
1576 ? KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->u.OriginalFirstThunk, const IMAGE_THUNK_DATA32 *)
1577 : KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, const IMAGE_THUNK_DATA32 *);
1578
1579 /* Iterate the thunks. */
1580 while (pThunk->u1.Ordinal != 0)
1581 {
1582 KLDRADDR Value;
1583 uint32_t fKind;
1584 int rc;
1585
1586 /* Ordinal or name import? */
1587 if (IMAGE_SNAP_BY_ORDINAL32(pThunk->u1.Ordinal))
[2891]1588 rc = pfnGetImport(pMod, iImp, IMAGE_ORDINAL32(pThunk->u1.Ordinal), NULL, 0, NULL, &Value, &fKind, pvUser);
[2857]1589 else if (KLDRMODPE_VALID_RVA(pModPE, pThunk->u1.Ordinal))
[2869]1590 {
1591 const IMAGE_IMPORT_BY_NAME *pName = KLDRMODPE_RVA2TYPE(pvMapping, pThunk->u1.Ordinal, const IMAGE_IMPORT_BY_NAME *);
[2893]1592 rc = pfnGetImport(pMod, iImp, NIL_KLDRMOD_SYM_ORDINAL, (const char *)pName->Name,
[2891]1593 kLdrHlpStrLen((const char *)pName->Name), NULL, &Value, &fKind, pvUser);
[2869]1594 }
[2857]1595 else
1596 {
1597 KLDRMODPE_ASSERT(!"bad 32-bit import");
1598 return KLDR_ERR_PE_BAD_IMPORT;
1599 }
1600
1601 /* Apply it. */
1602 pFirstThunk->u1.Function = (uint32_t)Value;
1603 if (pFirstThunk->u1.Function != Value)
1604 {
1605 KLDRMODPE_ASSERT(!"overflow");
1606 return KLDR_ERR_ADDRESS_OVERFLOW;
1607 }
1608
1609 /* next */
1610 pThunk++;
1611 pFirstThunk++;
1612 }
1613 }
1614
1615 return 0;
1616}
1617
1618
1619/**
1620 * Resolves imports, 64-bit image.
1621 *
1622 * @returns 0 on success, non-zero kLdr status code on failure.
1623 * @param pModPE The PE module interpreter instance.
1624 * @param pvMapping The mapping which imports should be resolved.
1625 * @param pImpDesc Pointer to the first import descriptor.
1626 * @param pfnGetImport The callback for resolving an imported symbol.
1627 * @param pvUser User argument to the callback.
1628 */
1629static int kldrModPEDoImports64Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc,
1630 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1631{
1632 PKLDRMOD pMod = pModPE->pMod;
1633 uint32_t iImp;
1634
1635 /*
1636 * Iterate the import descriptors.
1637 */
1638 for (iImp = 0; iImp < pModPE->cImportModules; iImp++, pImpDesc++)
1639 {
1640 PIMAGE_THUNK_DATA64 pFirstThunk = KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, PIMAGE_THUNK_DATA64);
1641 const IMAGE_THUNK_DATA64 *pThunk = pImpDesc->u.OriginalFirstThunk
1642 ? KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->u.OriginalFirstThunk, const IMAGE_THUNK_DATA64 *)
1643 : KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, const IMAGE_THUNK_DATA64 *);
1644
1645 /* Iterate the thunks. */
1646 while (pThunk->u1.Ordinal != 0)
1647 {
1648 KLDRADDR Value;
1649 uint32_t fKind;
1650 int rc;
1651
1652 /* Ordinal or name import? */
1653 if (IMAGE_SNAP_BY_ORDINAL64(pThunk->u1.Ordinal))
[2891]1654 rc = pfnGetImport(pMod, iImp, (uint32_t)IMAGE_ORDINAL64(pThunk->u1.Ordinal), NULL, 0, NULL, &Value, &fKind, pvUser);
[2857]1655 else if (KLDRMODPE_VALID_RVA(pModPE, pThunk->u1.Ordinal))
[2891]1656 {
1657 const IMAGE_IMPORT_BY_NAME *pName = KLDRMODPE_RVA2TYPE(pvMapping, pThunk->u1.Ordinal, const IMAGE_IMPORT_BY_NAME *);
[2893]1658 rc = pfnGetImport(pMod, iImp, NIL_KLDRMOD_SYM_ORDINAL, (const char *)pName->Name,
[2891]1659 kLdrHlpStrLen((const char *)pName->Name), NULL, &Value, &fKind, pvUser);
1660 }
[2857]1661 else
1662 {
1663 KLDRMODPE_ASSERT(!"bad 64-bit import");
1664 return KLDR_ERR_PE_BAD_IMPORT;
1665 }
1666
1667 /* Apply it. */
1668 pFirstThunk->u1.Function = Value;
1669
1670 /* next */
1671 pThunk++;
1672 pFirstThunk++;
1673 }
1674 }
1675
1676 return 0;
1677}
1678
1679
1680
[2854]1681/** @copydoc kLdrModCallInit */
[2856]1682static int kldrModPECallInit(PKLDRMOD pMod, uintptr_t uHandle)
1683{
1684 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1685 int rc;
1686
1687 /*
1688 * Mapped?
1689 */
1690 if (!pModPE->pvMapping)
1691 return KLDR_ERR_NOT_MAPPED;
1692
1693 /*
1694 * Do TLS callbacks first and then call the init/term function if it's a DLL.
1695 */
1696 rc = kldrModPEDoCallTLS(pModPE, DLL_PROCESS_ATTACH, uHandle);
1697 if ( !rc
1698 && (pModPE->Hdrs.FileHeader.Characteristics & IMAGE_FILE_DLL))
1699 {
1700 rc = kldrModPEDoCallDLL(pModPE, DLL_PROCESS_ATTACH, uHandle);
1701 if (rc)
1702 kldrModPEDoCallTLS(pModPE, DLL_PROCESS_DETACH, uHandle);
1703 }
1704
1705 return rc;
1706}
1707
1708
[2857]1709/**
1710 * Call the DLL entrypoint.
1711 *
1712 * @returns 0 on success.
1713 * @returns KLDR_ERR_MODULE_INIT_FAILED or KLDR_ERR_THREAD_ATTACH_FAILED on failure.
1714 * @param pModPE The PE module interpreter instance.
1715 * @param uOp The operation (DLL_*).
1716 * @param uHandle The module handle to present.
1717 */
1718static int kldrModPEDoCallDLL(PKLDRMODPE pModPE, unsigned uOp, uintptr_t uHandle)
1719{
1720 int rc;
1721
1722 /*
1723 * If no entrypoint there isn't anything to be done.
1724 */
1725 if (!pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint)
1726 return 0;
1727
1728 /*
1729 * Invoke the entrypoint and convert the boolean result to a kLdr status code.
1730 */
1731 rc = kldrModPEDoCall((uintptr_t)pModPE->pvMapping + pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint,
1732 uHandle, uOp, NULL);
1733 if (rc)
1734 rc = 0;
1735 else if (uOp == DLL_PROCESS_ATTACH)
1736 rc = KLDR_ERR_MODULE_INIT_FAILED;
1737 else if (uOp == DLL_THREAD_ATTACH)
1738 rc = KLDR_ERR_THREAD_ATTACH_FAILED;
1739 else /* detach: ignore failures */
1740 rc = 0;
1741 return rc;
1742}
1743
1744
1745/**
1746 * Call the TLS entrypoints.
1747 *
1748 * @returns 0 on success.
1749 * @returns KLDR_ERR_THREAD_ATTACH_FAILED on failure.
1750 * @param pModPE The PE module interpreter instance.
1751 * @param uOp The operation (DLL_*).
1752 * @param uHandle The module handle to present.
1753 */
1754static int kldrModPEDoCallTLS(PKLDRMODPE pModPE, unsigned uOp, uintptr_t uHandle)
1755{
1756 /** @todo implement TLS support. */
1757 return 0;
1758}
1759
1760
1761/**
1762 * Do a 3 parameter callback.
1763 *
1764 * @returns 32-bit callback return.
1765 * @param uEntrypoint The address of the function to be called.
1766 * @param uHandle The first argument, the module handle.
1767 * @param uOp The second argumnet, the reason we're calling.
1768 * @param pvReserved The third argument, reserved argument. (figure this one out)
1769 */
1770static int32_t kldrModPEDoCall(uintptr_t uEntrypoint, uintptr_t uHandle, uint32_t uOp, void *pvReserved)
1771{
1772 int32_t rc;
1773
1774/** @todo try/except */
1775#if defined(__X86__) || defined(__i386__) || defined(_M_IX86)
1776 /*
1777 * Be very careful.
1778 * Not everyone will have got the calling convention right.
1779 */
1780# ifdef __GNUC__
1781 __asm__ __volatile__(
1782 "pushl %2\n\t"
1783 "pushl %1\n\t"
1784 "pushl %0\n\t"
1785 "lea 12(%%esp), %2\n\t"
1786 "call *%3\n\t"
1787 "movl %2, %%esp\n\t"
1788 : "=a" (rc)
1789 : "d" (uOp),
1790 "S" (0),
1791 "c" (uEntrypoint),
1792 "0" (uHandle));
1793# elif defined(_MSC_VER)
1794 __asm {
1795 mov eax, [uHandle]
1796 mov edx, [uOp]
1797 mov ecx, 0
1798 mov ebx, [uEntrypoint]
1799 push edi
1800 mov edi, esp
1801 push ecx
1802 push edx
1803 push eax
1804 call ebx
1805 mov esp, edi
1806 pop edi
1807 mov [rc], eax
1808 }
1809# else
1810# error "port me!"
1811# endif
1812
1813#elif defined(__AMD64__) || defined(__x86_64__) || defined(_M_IX86)
1814 /*
1815 * For now, let's just get the work done...
1816 */
1817 /** @todo Deal with GCC / MSC differences in some sensible way. */
1818 int (*pfn)(uintptr_t uHandle, uint32_t uOp, void *pvReserved);
1819 pfn = (int (*)(uintptr_t uHandle, uint32_t uOp, void *pvReserved))uEntrypoint;
1820 rc = pfn(uHandle, uOp, NULL);
1821
1822#else
1823# error "port me"
1824#endif
1825
1826 return rc;
1827}
1828
1829
[2854]1830/** @copydoc kLdrModCallTerm */
[2856]1831static int kldrModPECallTerm(PKLDRMOD pMod, uintptr_t uHandle)
1832{
1833 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1834
1835 /*
1836 * Mapped?
1837 */
1838 if (!pModPE->pvMapping)
1839 return KLDR_ERR_NOT_MAPPED;
1840
1841 /*
1842 * Do TLS callbacks first.
1843 */
1844 kldrModPEDoCallTLS(pModPE, DLL_PROCESS_DETACH, uHandle);
1845 if (pModPE->Hdrs.FileHeader.Characteristics & IMAGE_FILE_DLL)
1846 kldrModPEDoCallDLL(pModPE, DLL_PROCESS_DETACH, uHandle);
1847
1848 return 0;
1849}
1850
1851
[2854]1852/** @copydoc kLdrModCallThread */
[2856]1853static int kldrModPECallThread(PKLDRMOD pMod, uintptr_t uHandle, unsigned fAttachingOrDetaching)
1854{
1855 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1856 unsigned uOp = fAttachingOrDetaching ? DLL_THREAD_ATTACH : DLL_THREAD_DETACH;
1857 int rc;
1858
1859 /*
1860 * Do TLS callbacks first and then call the init/term function if it's a DLL.
1861 */
1862 rc = kldrModPEDoCallTLS(pModPE, uOp, uHandle);
1863 if (!fAttachingOrDetaching)
1864 rc = 0;
1865 if ( !rc
1866 && (pModPE->Hdrs.FileHeader.Characteristics & IMAGE_FILE_DLL))
1867 {
1868 rc = kldrModPEDoCallDLL(pModPE, uOp, uHandle);
1869 if (!fAttachingOrDetaching)
1870 rc = 0;
1871 if (rc)
1872 kldrModPEDoCallTLS(pModPE, uOp, uHandle);
1873 }
1874
1875 return rc;
1876}
1877
1878
[2854]1879/** @copydoc kLdrModSize */
[2856]1880static KLDRADDR kldrModPESize(PKLDRMOD pMod)
1881{
1882 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1883 return pModPE->Hdrs.OptionalHeader.SizeOfImage;
1884}
1885
1886
[2854]1887/** @copydoc kLdrModGetBits */
[2856]1888static int kldrModPEGetBits(PKLDRMOD pMod, void *pvBits, KLDRADDR BaseAddress, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1889{
1890 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1891 uint32_t i;
1892 int rc;
1893
1894 /*
[2857]1895 * Zero the entire buffer first to simplify things.
1896 */
1897 kLdrHlpMemSet(pvBits, 0, pModPE->Hdrs.OptionalHeader.SizeOfImage);
1898
1899 /*
[2856]1900 * Iterate the segments and read the data within them.
1901 */
1902 for (i = 0; i < pMod->cSegments; i++)
1903 {
[2857]1904 /* skip it? */
1905 if ( pMod->aSegments[i].cbFile == -1
1906 || pMod->aSegments[i].offFile == -1
1907 || pMod->aSegments[i].LinkAddress == NIL_KLDRADDR
1908 || !pMod->aSegments[i].Alignment)
1909 continue;
1910 rc = kLdrRdrRead(pMod->pRdr,
1911 (uint8_t *)pvBits + (pMod->aSegments[i].LinkAddress - pModPE->Hdrs.OptionalHeader.ImageBase),
1912 pMod->aSegments[i].cbFile,
1913 pMod->aSegments[i].offFile);
1914 if (rc)
1915 return rc;
[2856]1916 }
1917
1918 /*
1919 * Perform relocations.
1920 */
1921 return kldrModPERelocateBits(pMod, pvBits, BaseAddress, pModPE->Hdrs.OptionalHeader.ImageBase, pfnGetImport, pvUser);
1922
1923}
1924
1925
[2854]1926/** @copydoc kLdrModRelocateBits */
[2856]1927static int kldrModPERelocateBits(PKLDRMOD pMod, void *pvBits, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress,
1928 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1929{
1930 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1931 int rc;
[2854]1932
[2856]1933 /*
1934 * Call workers to do the jobs.
1935 */
1936 rc = kldrModPEDoFixups(pModPE, pvBits, NewBaseAddress, OldBaseAddress);
1937 if (!rc)
1938 rc = kldrModPEDoImports(pModPE, pvBits, pfnGetImport, pvUser);
1939
1940 return rc;
1941}
1942
[2858]1943
1944/**
1945 * The PE module interpreter method table.
1946 */
1947KLDRMODOPS g_kLdrModPEOps =
1948{
1949 "PE",
1950 NULL,
1951 kldrModPECreate,
1952 kldrModPEDestroy,
1953 kldrModPEQuerySymbol,
1954 kldrModPEEnumSymbols,
1955 kldrModPEGetImport,
1956 kldrModPENumberOfImports,
1957 NULL /* can execute one is optional */,
1958 kldrModPEGetStackInfo,
1959 kldrModPEQueryMainEntrypoint,
[2891]1960 NULL, /** @todo resources */
1961 NULL, /** @todo resources */
[2858]1962 kldrModPEEnumDbgInfo,
1963 kldrModPEHasDbgInfo,
1964 kldrModPEMap,
1965 kldrModPEUnmap,
1966 kldrModPEAllocTLS,
1967 kldrModPEFreeTLS,
1968 kldrModPEReload,
1969 kldrModPEFixupMapping,
1970 kldrModPECallInit,
1971 kldrModPECallTerm,
1972 kldrModPECallThread,
1973 kldrModPESize,
1974 kldrModPEGetBits,
1975 kldrModPERelocateBits,
[2891]1976 NULL, /** @todo mostly done */
[2858]1977 42 /* the end */
1978};
Note: See TracBrowser for help on using the repository browser.