source: trunk/kLdr/kLdrModPE.c@ 2857

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

Only the mapping left now.

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