source: trunk/kLdr/kLdrModPE.c@ 2883

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

cleanup.

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