source: trunk/kLdr/kLdrModPE.c@ 2858

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

bugfixing - dinner break.

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