source: trunk/kLdr/kLdrModPE.c@ 2899

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

Made it build (version + name length).

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