source: trunk/kLdr/kLdrModPE.c@ 3232

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

off_t -> KLDRFOFF.

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