source: trunk/kLdr/kLdrModPE.c@ 2893

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

made it compile again.

  • Property svn:keywords set to Id
File size: 70.3 KB
Line 
1/* $Id: kLdrModPE.c 2893 2006-12-22 18:01:38Z bird $ */
2/** @file
3 *
4 * kLdr - The Module Interpreter for the Portable Executable (PE) Format.
5 *
6 * Copyright (c) 2006 knut st. osmundsen <bird-kbuild-src@anduin.net>
7 *
8 *
9 * This file is part of kLdr.
10 *
11 * kLdr is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * kLdr is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kLdr; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <kLdr.h>
32#include "kLdrHlp.h"
33#include "kLdrInternal.h"
34#include "kLdrModPE.h"
35
36
37/*******************************************************************************
38* Defined Constants And Macros *
39*******************************************************************************/
40/** @def KLDRMODPE_STRICT
41 * Define KLDRMODPE_STRICT to enabled strict checks in KLDRMODPE. */
42#define KLDRMODPE_STRICT 1
43
44/** @def KLDRMODPE_ASSERT
45 * Assert that an expression is true when KLDR_STRICT is defined.
46 */
47#ifdef KLDRMODPE_STRICT
48# define KLDRMODPE_ASSERT(expr) kldrHlpAssert(expr)
49#else
50# define KLDRMODPE_ASSERT(expr) do {} while (0)
51#endif
52
53/** @def KLDRMODPE_RVA2TYPE
54 * Converts a RVA to a pointer of the specified type.
55 * @param pvBits The bits (image base).
56 * @param uRVA The image relative virtual address.
57 * @param type The type to cast to.
58 */
59#define KLDRMODPE_RVA2TYPE(pvBits, uRVA, type) \
60 ( (type) ((uintptr_t)(pvBits) + (uintptr_t)(uRVA)) )
61
62/** @def KLDRMODPE_VALID_RVA
63 * Checks that the specified RVA value is non-zero and within the bounds of the image.
64 * @returns true/false.
65 * @param pModPE The PE module interpreter instance.
66 * @param uRVA The RVA to validate.
67 */
68#define KLDRMODPE_VALID_RVA(pModPE, uRVA) \
69 ( (uRVA) && (uRVA) < (pModPE)->Hdrs.OptionalHeader.SizeOfImage )
70
71
72
73/*******************************************************************************
74* Structures and Typedefs *
75*******************************************************************************/
76/**
77 * Instance data for the PE module interpreter.
78 */
79typedef struct KLDRMODPE
80{
81 /** Pointer to the module. (Follows the section table.) */
82 PKLDRMOD pMod;
83 /** Pointer to the RDR mapping of the raw file bits. NULL if not mapped. */
84 const void *pvBits;
85 /** Pointer to the user mapping. */
86 const void *pvMapping;
87 /** Reserved flags. */
88 uint32_t f32Reserved;
89 /** The number of imported modules.
90 * If ~(uint32_t)0 this hasn't been determined yet. */
91 uint32_t cImportModules;
92 /** The offset of the NT headers. */
93 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 kldrModPEDoFixups(PKLDRMODPE pModPE, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress);
116static int kldrModPEDoImports32Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc,
117 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
118static int kldrModPEDoImports64Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc,
119 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
120static int kldrModPEDoImports(PKLDRMODPE pModPE, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser);
121static int kldrModPEDoCallDLL(PKLDRMODPE pModPE, unsigned uOp, uintptr_t uHandle);
122static int kldrModPEDoCallTLS(PKLDRMODPE pModPE, unsigned uOp, uintptr_t uHandle);
123static int32_t kldrModPEDoCall(uintptr_t uEntrypoint, uintptr_t uHandle, uint32_t uOp, void *pvReserved);
124
125
126/**
127 * Create a loader module instance interpreting the executable image found
128 * in the specified file provider instance.
129 *
130 * @returns 0 on success and *ppMod pointing to a module instance.
131 * On failure, a non-zero OS specific error code is returned.
132 * @param pOps Pointer to the registered method table.
133 * @param pRdr The file provider instance to use.
134 * @param offNewHdr The offset of the new header in MZ files. -1 if not found.
135 * @param ppMod Where to store the module instance pointer.
136 */
137static int kldrModPECreate(PCKLDRMODOPS pOps, PKLDRRDR pRdr, off_t offNewHdr, PPKLDRMOD ppMod)
138{
139 PKLDRMODPE pModPE;
140 int rc;
141
142 /*
143 * Create the instance data and do a minimal header validation.
144 */
145 rc = kldrModPEDoCreate(pRdr, offNewHdr, &pModPE);
146 if (!rc)
147 {
148 pModPE->pMod->pOps = pOps;
149 pModPE->pMod->u32Magic = KLDRMOD_MAGIC;
150 *ppMod = pModPE->pMod;
151 return 0;
152 }
153 kldrHlpFree(pModPE);
154 return rc;
155}
156
157
158/**
159 * Separate function for reading creating the PE module instance to
160 * simplify cleanup on failure.
161 */
162static int kldrModPEDoCreate(PKLDRRDR pRdr, off_t offNewHdr, PKLDRMODPE *ppModPE)
163{
164 struct
165 {
166 uint32_t Signature;
167 IMAGE_FILE_HEADER FileHdr;
168 } s;
169 PKLDRMODPE pModPE;
170 PKLDRMOD pMod;
171 size_t cb;
172 size_t cchFilename;
173 off_t off;
174 uint32_t i;
175 int rc;
176 *ppModPE = NULL;
177
178 /*
179 * Read the signature and file header.
180 */
181 rc = kLdrRdrRead(pRdr, &s, sizeof(s), offNewHdr > 0 ? offNewHdr : 0);
182 if (rc)
183 return rc;
184 if (s.Signature != IMAGE_NT_SIGNATURE)
185 return KLDR_ERR_UNKNOWN_FORMAT;
186
187 /* sanity checks. */
188 if ( s.FileHdr.NumberOfSections > 4096
189 || ( s.FileHdr.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER32)
190 && s.FileHdr.SizeOfOptionalHeader != sizeof(IMAGE_OPTIONAL_HEADER64))
191 || !(s.FileHdr.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)
192 )
193 return KLDR_ERR_PE_BAD_FILE_HEADER;
194 if ( s.FileHdr.Machine != IMAGE_FILE_MACHINE_I386
195 && s.FileHdr.Machine != IMAGE_FILE_MACHINE_AMD64
196 )
197 return KLDR_ERR_PE_UNSUPPORTED_MACHINE;
198
199 /*
200 * Calc the instance size, allocate and initialize it.
201 */
202 cchFilename = kLdrHlpStrLen(kLdrRdrName(pRdr));
203 cb = KLDR_ALIGN_Z(KLDR_OFFSETOF(KLDRMODPE, aShdrs[s.FileHdr.NumberOfSections]), 16)
204 + KLDR_OFFSETOF(KLDRMOD, aSegments[s.FileHdr.NumberOfSections + 1])
205 + cchFilename + 1;
206 pModPE = (PKLDRMODPE)kldrHlpAlloc(cb);
207 if (!pModPE)
208 return KLDR_ERR_NO_MEMORY;
209 *ppModPE = pModPE;
210
211 /* KLDRMOD */
212 pMod = (PKLDRMOD)((uint8_t *)pModPE + KLDR_ALIGN_Z(KLDR_OFFSETOF(KLDRMODPE, aShdrs[s.FileHdr.NumberOfSections]), 16));
213 pMod->pvData = pModPE;
214 pMod->pRdr = pRdr;
215 pMod->pOps = NULL; /* set upon success. */
216 pMod->cSegments = s.FileHdr.NumberOfSections + 1;
217 pMod->cchFilename = cchFilename;
218 pMod->pszFilename = (char *)&pMod->aSegments[pMod->cSegments];
219 kLdrHlpMemCopy((char *)pMod->pszFilename, kLdrRdrName(pRdr), cchFilename + 1);
220 pMod->pszName = kldrHlpGetFilename(pMod->pszFilename);
221 pMod->cchName = cchFilename - (pMod->pszName - pMod->pszFilename);
222 switch (s.FileHdr.Machine)
223 {
224 case IMAGE_FILE_MACHINE_I386:
225 pMod->enmCpu = KLDRCPU_I386;
226 pMod->enmArch = KLDRARCH_X86_32;
227 pMod->enmEndian = KLDRENDIAN_LITTLE;
228 break;
229
230 case IMAGE_FILE_MACHINE_AMD64:
231 pMod->enmCpu = KLDRCPU_K8;
232 pMod->enmArch = KLDRARCH_AMD64;
233 pMod->enmEndian = KLDRENDIAN_LITTLE;
234 break;
235 default:
236 kldrHlpAssert(0);
237 break;
238 }
239 pMod->enmFmt = KLDRFMT_PE;
240 if (s.FileHdr.Characteristics & IMAGE_FILE_DLL)
241 pMod->enmType = !(s.FileHdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
242 ? KLDRTYPE_SHARED_LIBRARY_RELOCATABLE
243 : KLDRTYPE_SHARED_LIBRARY_FIXED;
244 else
245 pMod->enmType = !(s.FileHdr.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
246 ? KLDRTYPE_EXECUTABLE_RELOCATABLE
247 : KLDRTYPE_EXECUTABLE_FIXED;
248 pMod->u32Magic = 0; /* set upon success. */
249
250 /* KLDRMODPE */
251 pModPE->pMod = pMod;
252 pModPE->pvBits = NULL;
253 pModPE->f32Reserved = 0;
254 pModPE->cImportModules = ~(uint32_t)0;
255 pModPE->offHdrs = offNewHdr >= 0 ? offNewHdr : 0;
256 pModPE->Hdrs.Signature = s.Signature;
257 pModPE->Hdrs.FileHeader = s.FileHdr;
258
259 /*
260 * Read the optional header and the section table.
261 */
262 off = pModPE->offHdrs + sizeof(pModPE->Hdrs.Signature) + sizeof(pModPE->Hdrs.FileHeader);
263 rc = kLdrRdrRead(pRdr, &pModPE->Hdrs.OptionalHeader, pModPE->Hdrs.FileHeader.SizeOfOptionalHeader, off);
264 if (rc)
265 return rc;
266 if (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader != sizeof(pModPE->Hdrs.OptionalHeader))
267 kldrModPEDoOptionalHeaderConversion(&pModPE->Hdrs.OptionalHeader);
268 off += pModPE->Hdrs.FileHeader.SizeOfOptionalHeader;
269 rc = kLdrRdrRead(pRdr, &pModPE->aShdrs[0], sizeof(IMAGE_SECTION_HEADER) * pModPE->Hdrs.FileHeader.NumberOfSections, off);
270 if (rc)
271 return rc;
272
273 /*
274 * Validate the two.
275 */
276 rc = kLdrModPEDoOptionalHeaderValidation(pModPE);
277 if (rc)
278 return rc;
279 for (i = 0; i < pModPE->Hdrs.FileHeader.NumberOfSections; i++)
280 {
281 rc = kLdrModPEDoSectionHeadersValidation(pModPE);
282 if (rc)
283 return rc;
284 }
285
286 /*
287 * Setup the KLDRMOD segment array.
288 */
289 /* The implied headers section. */
290 pMod->aSegments[0].pvUser = NULL;
291 pMod->aSegments[0].pchName = "TheHeaders";
292 pMod->aSegments[0].cchName = sizeof("TheHeaders") - 1;
293 pMod->aSegments[0].enmProt = KLDRPROT_READONLY;
294 pMod->aSegments[0].cb = pModPE->Hdrs.OptionalHeader.SizeOfHeaders;
295 pMod->aSegments[0].Alignment = pModPE->Hdrs.OptionalHeader.SectionAlignment;
296 pMod->aSegments[0].LinkAddress = pModPE->Hdrs.OptionalHeader.ImageBase;
297 pMod->aSegments[0].offFile = 0;
298 pMod->aSegments[0].cbFile = pModPE->Hdrs.OptionalHeader.SizeOfHeaders;
299 pMod->aSegments[0].RVA = 0;
300 if (pMod->cSegments > 1)
301 pMod->aSegments[0].cbMapped = pModPE->aShdrs[0].VirtualAddress;
302 else
303 pMod->aSegments[0].cbMapped = pModPE->Hdrs.OptionalHeader.SizeOfHeaders;
304 pMod->aSegments[0].MapAddress = 0;
305
306 /* The section headers. */
307 for (i = 0; i < pModPE->Hdrs.FileHeader.NumberOfSections; i++)
308 {
309 const char *pch;
310
311 /* unused */
312 pMod->aSegments[i + 1].pvUser = NULL;
313 pMod->aSegments[i + 1].MapAddress = 0;
314
315 /* name */
316 pMod->aSegments[i + 1].pchName = pch = (const char *)&pModPE->aShdrs[i].Name[0];
317 cb = IMAGE_SIZEOF_SHORT_NAME;
318 while ( cb > 0
319 && (pch[cb - 1] == ' ' || pch[cb - 1] == '\0'))
320 cb--;
321 pMod->aSegments[i + 1].cchName = cb;
322
323 /* size and addresses */
324 if (!(pModPE->aShdrs[i].Characteristics & IMAGE_SCN_TYPE_NOLOAD))
325 {
326 pMod->aSegments[i + 1].cb = pModPE->aShdrs[i].Misc.VirtualSize;
327 pMod->aSegments[i + 1].LinkAddress = pModPE->aShdrs[i].VirtualAddress
328 + pModPE->Hdrs.OptionalHeader.ImageBase;
329 pMod->aSegments[i + 1].RVA = pModPE->aShdrs[i].VirtualAddress;
330 pMod->aSegments[i + 1].cbMapped = pModPE->aShdrs[i].Misc.VirtualSize;
331 if (i + 2 < pMod->cSegments)
332 pMod->aSegments[i + 1].cbMapped= pModPE->aShdrs[i + 1].VirtualAddress
333 - pModPE->aShdrs[i].VirtualAddress;
334 }
335 else
336 {
337 pMod->aSegments[i + 1].cb = 0;
338 pMod->aSegments[i + 1].cbMapped = 0;
339 pMod->aSegments[i + 1].LinkAddress = NIL_KLDRADDR;
340 pMod->aSegments[i + 1].RVA = 0;
341 }
342
343 /* file location */
344 pMod->aSegments[i + 1].offFile = pModPE->aShdrs[i].PointerToRawData;
345 pMod->aSegments[i + 1].cbFile = pModPE->aShdrs[i].SizeOfRawData;
346 if ( pMod->aSegments[i + 1].cbMapped > 0 /* if mapped */
347 && (KLDRSIZE)pMod->aSegments[i + 1].cbFile > pMod->aSegments[i + 1].cbMapped)
348 pMod->aSegments[i + 1].cbFile = pMod->aSegments[i + 1].cbMapped;
349
350 /* protection */
351 switch ( pModPE->aShdrs[i].Characteristics
352 & (IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE))
353 {
354 case 0:
355 case IMAGE_SCN_MEM_SHARED:
356 pMod->aSegments[i + 1].enmProt = KLDRPROT_NOACCESS;
357 break;
358 case IMAGE_SCN_MEM_READ:
359 case IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED:
360 pMod->aSegments[i + 1].enmProt = KLDRPROT_READONLY;
361 break;
362 case IMAGE_SCN_MEM_WRITE:
363 case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ:
364 pMod->aSegments[i + 1].enmProt = KLDRPROT_WRITECOPY;
365 break;
366 case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED:
367 case IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ:
368 pMod->aSegments[i + 1].enmProt = KLDRPROT_READWRITE;
369 break;
370 case IMAGE_SCN_MEM_EXECUTE:
371 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_SHARED:
372 pMod->aSegments[i + 1].enmProt = KLDRPROT_EXECUTE;
373 break;
374 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ:
375 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_SHARED:
376 pMod->aSegments[i + 1].enmProt = KLDRPROT_EXECUTE_READ;
377 break;
378 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE:
379 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ:
380 pMod->aSegments[i + 1].enmProt = KLDRPROT_EXECUTE_WRITECOPY;
381 break;
382 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED:
383 case IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ:
384 pMod->aSegments[i + 1].enmProt = KLDRPROT_EXECUTE_READWRITE;
385 break;
386 }
387
388 /* alignment. */
389 switch (pModPE->aShdrs[i].Characteristics & IMAGE_SCN_ALIGN_MASK)
390 {
391 case 0: /* hope this is right... */
392 pMod->aSegments[i + 1].Alignment = pModPE->Hdrs.OptionalHeader.SectionAlignment;
393 break;
394 case IMAGE_SCN_ALIGN_1BYTES: pMod->aSegments[i + 1].Alignment = 1; break;
395 case IMAGE_SCN_ALIGN_2BYTES: pMod->aSegments[i + 1].Alignment = 2; break;
396 case IMAGE_SCN_ALIGN_4BYTES: pMod->aSegments[i + 1].Alignment = 4; break;
397 case IMAGE_SCN_ALIGN_8BYTES: pMod->aSegments[i + 1].Alignment = 8; break;
398 case IMAGE_SCN_ALIGN_16BYTES: pMod->aSegments[i + 1].Alignment = 16; break;
399 case IMAGE_SCN_ALIGN_32BYTES: pMod->aSegments[i + 1].Alignment = 32; break;
400 case IMAGE_SCN_ALIGN_64BYTES: pMod->aSegments[i + 1].Alignment = 64; break;
401 case IMAGE_SCN_ALIGN_128BYTES: pMod->aSegments[i + 1].Alignment = 128; break;
402 case IMAGE_SCN_ALIGN_256BYTES: pMod->aSegments[i + 1].Alignment = 256; break;
403 case IMAGE_SCN_ALIGN_512BYTES: pMod->aSegments[i + 1].Alignment = 512; break;
404 case IMAGE_SCN_ALIGN_1024BYTES: pMod->aSegments[i + 1].Alignment = 1024; break;
405 case IMAGE_SCN_ALIGN_2048BYTES: pMod->aSegments[i + 1].Alignment = 2048; break;
406 case IMAGE_SCN_ALIGN_4096BYTES: pMod->aSegments[i + 1].Alignment = 4096; break;
407 case IMAGE_SCN_ALIGN_8192BYTES: pMod->aSegments[i + 1].Alignment = 8192; break;
408 default: kldrHlpAssert(0); pMod->aSegments[i + 1].Alignment = 0; break;
409 }
410 }
411
412 /*
413 * We're done.
414 */
415 *ppModPE = pModPE;
416 return 0;
417}
418
419
420/**
421 * Converts a 32-bit optional header to a 64-bit one
422 *
423 * @param pOptHdr The optional header to convert.
424 */
425static void kldrModPEDoOptionalHeaderConversion(PIMAGE_OPTIONAL_HEADER64 pOptHdr)
426{
427 /* volatile everywhere! */
428 IMAGE_OPTIONAL_HEADER32 volatile *pOptHdr32 = (IMAGE_OPTIONAL_HEADER32 volatile *)pOptHdr;
429 IMAGE_OPTIONAL_HEADER64 volatile *pOptHdr64 = pOptHdr;
430 uint32_t volatile *pu32Dst;
431 uint32_t volatile *pu32Src;
432 uint32_t volatile *pu32SrcLast;
433 uint32_t u32;
434
435 /* From LoaderFlags and out the difference is 4 * 32-bits. */
436 pu32Dst = (uint32_t *)&pOptHdr64->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1;
437 pu32Src = (uint32_t *)&pOptHdr32->DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] - 1;
438 pu32SrcLast = (uint32_t *)&pOptHdr32->LoaderFlags;
439 while (pu32Src >= pu32SrcLast)
440 *pu32Dst-- = *pu32Src--;
441
442 /* The previous 4 fields are 32/64 and needs special attention. */
443 pOptHdr64->SizeOfHeapCommit = pOptHdr32->SizeOfHeapCommit;
444 pOptHdr64->SizeOfHeapReserve = pOptHdr32->SizeOfHeapReserve;
445 pOptHdr64->SizeOfStackCommit = pOptHdr32->SizeOfStackCommit;
446 u32 = pOptHdr32->SizeOfStackReserve;
447 pOptHdr64->SizeOfStackReserve = u32;
448
449 /*
450 * The rest matches except for BaseOfData which has been merged into ImageBase in the 64-bit version.
451 * Thus, ImageBase needs some special treatement. It will probably work fine assigning one to the
452 * other since this is all declared volatile, but taking now chances, we'll use a temp variable.
453 */
454 u32 = pOptHdr32->ImageBase;
455 pOptHdr64->ImageBase = u32;
456}
457
458
459/**
460 * Converts a 32-bit load config directory to a 64 bit one.
461 *
462 * @param pOptHdr The load config to convert.
463 */
464static void kldrModPEDoLoadConfigConversion(PIMAGE_LOAD_CONFIG_DIRECTORY64 pLoadCfg)
465{
466 /* volatile everywhere! */
467 IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *pLoadCfg32 = (IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *)pLoadCfg;
468 IMAGE_LOAD_CONFIG_DIRECTORY64 volatile *pLoadCfg64 = pLoadCfg;
469 uint32_t u32;
470
471 pLoadCfg64->SEHandlerCount = pLoadCfg32->SEHandlerCount;
472 pLoadCfg64->SEHandlerTable = pLoadCfg32->SEHandlerTable;
473 pLoadCfg64->SecurityCookie = pLoadCfg32->SecurityCookie;
474 pLoadCfg64->EditList = pLoadCfg32->EditList;
475 pLoadCfg64->Reserved1 = pLoadCfg32->Reserved1;
476 pLoadCfg64->CSDVersion = pLoadCfg32->CSDVersion;
477 /* (ProcessHeapFlags switched place with ProcessAffinityMask, but we're
478 * more than 16 byte off by now so it doesn't matter.) */
479 pLoadCfg64->ProcessHeapFlags = pLoadCfg32->ProcessHeapFlags;
480 pLoadCfg64->ProcessAffinityMask = pLoadCfg32->ProcessAffinityMask;
481 pLoadCfg64->VirtualMemoryThreshold = pLoadCfg32->VirtualMemoryThreshold;
482 pLoadCfg64->MaximumAllocationSize = pLoadCfg32->MaximumAllocationSize;
483 pLoadCfg64->LockPrefixTable = pLoadCfg32->LockPrefixTable;
484 pLoadCfg64->DeCommitTotalFreeThreshold = pLoadCfg32->DeCommitTotalFreeThreshold;
485 u32 = pLoadCfg32->DeCommitFreeBlockThreshold;
486 pLoadCfg64->DeCommitFreeBlockThreshold = u32;
487 /* the remainder matches. */
488}
489
490
491/**
492 * Internal worker which validates the section headers.
493 */
494static int kLdrModPEDoOptionalHeaderValidation(PKLDRMODPE pModPE)
495{
496 const unsigned fIs32Bit = pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32);
497
498 /* the magic */
499 if ( pModPE->Hdrs.OptionalHeader.Magic
500 != (fIs32Bit ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC))
501 return KLDR_ERR_PE_BAD_OPTIONAL_HEADER;
502
503 /** @todo validate more */
504 return 0;
505}
506
507
508/**
509 * Internal worker which validates the section headers.
510 */
511static int kLdrModPEDoSectionHeadersValidation(PKLDRMODPE pModPE)
512{
513 /** @todo validate shdrs */
514 return 0;
515}
516
517
518/** @copydoc KLDRMODOPS::pfnDestroy */
519static int kldrModPEDestroy(PKLDRMOD pMod)
520{
521 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
522 int rc = 0;
523 KLDRMODPE_ASSERT(pModPE->pvMapping);
524
525 if (pMod->pRdr)
526 {
527 rc = kLdrRdrClose(pMod->pRdr);
528 pMod->pRdr = NULL;
529 }
530 pMod->u32Magic = 0;
531 pMod->pOps = NULL;
532 kldrHlpFree(pModPE);
533 return rc;
534}
535
536
537/**
538 * Performs the mapping of the image.
539 *
540 * This can be used to do the internal mapping as well as the
541 * user requested mapping. fForReal indicates which is desired.
542 *
543 * @returns 0 on success, non-zero OS or kLdr status code on failure.
544 * @param pModPE The interpreter module instance
545 * @param fForReal If set, do the user mapping. if clear, do the internal mapping.
546 */
547static int kldrModPEDoMap(PKLDRMODPE pModPE, unsigned fForReal)
548{
549 PKLDRMOD pMod = pModPE->pMod;
550 unsigned fFixed;
551 void *pvBase;
552 int rc;
553 uint32_t i;
554
555 /*
556 * Map it.
557 */
558 /* fixed image? */
559 fFixed = fForReal
560 && ( pMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
561 || pMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED);
562 if (!fFixed)
563 pvBase = NULL;
564 else
565 {
566 pvBase = (void *)(uintptr_t)pMod->aSegments[0].LinkAddress;
567 if ((uintptr_t)pvBase != pMod->aSegments[0].LinkAddress)
568 return KLDR_ERR_ADDRESS_OVERFLOW;
569 }
570
571 /* try do the prepare */
572 rc = kLdrRdrMap(pMod->pRdr, &pvBase, pMod->cSegments, pMod->aSegments, fFixed);
573 if (rc)
574 return rc;
575
576 /*
577 * Update the segments with their map addresses.
578 */
579 if (fForReal)
580 {
581 for (i = 0; i < pMod->cSegments; i++)
582 {
583 if (pMod->aSegments[i].RVA != NIL_KLDRADDR)
584 pMod->aSegments[i].MapAddress = (uintptr_t)pvBase + (uintptr_t)pMod->aSegments[i].RVA;
585 }
586 pModPE->pvMapping = pvBase;
587 }
588 else
589 pModPE->pvBits = pvBase;
590 return 0;
591}
592
593
594/**
595 * Unmaps a image mapping.
596 *
597 * This can be used to do the internal mapping as well as the
598 * user requested mapping. fForReal indicates which is desired.
599 *
600 * @returns 0 on success, non-zero OS or kLdr status code on failure.
601 * @param pModPE The interpreter module instance
602 * @param pvMapping The mapping to unmap.
603 */
604static int kldrModPEDoUnmap(PKLDRMODPE pModPE, const void *pvMapping)
605{
606 PKLDRMOD pMod = pModPE->pMod;
607 int rc;
608 uint32_t i;
609
610 /*
611 * Try unmap the image.
612 */
613 rc = kLdrRdrUnmap(pMod->pRdr, (void *)pvMapping, pMod->cSegments, pMod->aSegments);
614 if (rc)
615 return rc;
616
617 /*
618 * Update the segments to reflect that they aren't mapped any longer.
619 */
620 if (pModPE->pvMapping == pvMapping)
621 {
622 pModPE->pvMapping = NULL;
623 for (i = 0; i < pMod->cSegments; i++)
624 pMod->aSegments[i].MapAddress = 0;
625 }
626 if (pModPE->pvBits == pvMapping)
627 pModPE->pvBits = NULL;
628
629 return 0;
630}
631
632
633/**
634 * Gets usable bits and the right base address.
635 *
636 * @returns 0 on success.
637 * @returns A non-zero status code if the BaseAddress isn't right or some problem is encountered
638 * featch in a temp mapping the bits.
639 * @param pModPE The interpreter module instance
640 * @param ppvBits The bits address, IN & OUT.
641 * @param pBaseAddress The base address, IN & OUT. Optional.
642 */
643static int kldrModPEBitsAndBaseAddress(PKLDRMODPE pModPE, const void **ppvBits, PKLDRADDR pBaseAddress)
644{
645 int rc = 0;
646
647 /*
648 * Correct the base address.
649 *
650 * We don't use the base address for interpreting the bits in this
651 * interpreter, which makes things relativly simple.
652 */
653 if (pBaseAddress)
654 {
655 if (*pBaseAddress == KLDRMOD_BASEADDRESS_MAP)
656 *pBaseAddress = pModPE->pMod->aSegments[0].MapAddress;
657 else if (*pBaseAddress == KLDRMOD_BASEADDRESS_LINK)
658 *pBaseAddress = pModPE->Hdrs.OptionalHeader.ImageBase;
659 }
660
661 /*
662 * Get bits.
663 */
664 if (ppvBits && !*ppvBits)
665 {
666 if (pModPE->pvMapping)
667 *ppvBits = pModPE->pvMapping;
668 else if (pModPE->pvBits)
669 *ppvBits = pModPE->pvBits;
670 else
671 {
672 /* create an internal mapping. */
673 rc = kldrModPEDoMap(pModPE, 0 /* not for real */);
674 if (rc)
675 return rc;
676 KLDRMODPE_ASSERT(pModPE->pvBits);
677 *ppvBits = pModPE->pvBits;
678 }
679 }
680
681 return 0;
682}
683
684
685/** @copydoc kLdrModQuerySymbol */
686static int kldrModPEQuerySymbol(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, uint32_t iSymbol,
687 const char *pchSymbol, size_t cchSymbol, const char *pszVersion,
688 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind)
689
690{
691 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
692 const uint32_t *paExportRVAs;
693 const IMAGE_EXPORT_DIRECTORY *pExpDir;
694 uint32_t iExpOrd;
695 uint32_t uRVA;
696 int rc;
697
698 /*
699 * Make sure we've got mapped bits and resolve any base address aliases.
700 */
701 rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, &BaseAddress);
702 if (rc)
703 return rc;
704 if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size
705 < sizeof(IMAGE_EXPORT_DIRECTORY))
706 return KLDR_ERR_SYMBOL_NOT_FOUND;
707 if (pszVersion && *pszVersion)
708 return KLDR_ERR_SYMBOL_NOT_FOUND;
709
710 pExpDir = KLDRMODPE_RVA2TYPE(pvBits,
711 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,
712 PIMAGE_EXPORT_DIRECTORY);
713 if (!pchSymbol)
714 {
715 /*
716 * Simple, calculate the unbased ordinal and bounds check it.
717 */
718 iExpOrd = iSymbol - pExpDir->Base;
719 if (iExpOrd >= KLDR_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions))
720 return KLDR_ERR_SYMBOL_NOT_FOUND;
721 }
722 else
723 {
724 /*
725 * Do a binary search for the name.
726 * (The name table is sorted in ascending ordered by the linker.)
727 */
728 const uint32_t *paRVANames = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, const uint32_t *);
729 const uint16_t *paOrdinals = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, const uint16_t *);
730 int32_t iStart = 1; /* one based binary searching is simpler. */
731 int32_t iEnd = pExpDir->NumberOfNames;
732
733 for (;;)
734 {
735 int32_t i;
736 int diff;
737 const char *pszName;
738
739 /* done? */
740 if (iStart > iEnd)
741 {
742#ifdef KLDRMODPE_STRICT /* Make sure the linker and we both did our job right. */
743 for (i = 0; i < (int32_t)pExpDir->NumberOfNames; i++)
744
745 {
746 pszName = KLDRMODPE_RVA2TYPE(pvBits, paRVANames[i], const char *);
747 KLDRMODPE_ASSERT(kLdrHlpStrNComp(pszName, pchSymbol, cchSymbol) || pszName[cchSymbol]);
748 KLDRMODPE_ASSERT(i == 0 || kLdrHlpStrComp(pszName, KLDRMODPE_RVA2TYPE(pvBits, paRVANames[i - 1], const char *)));
749 }
750#endif
751 return KLDR_ERR_SYMBOL_NOT_FOUND;
752 }
753
754 i = (iEnd - iStart) / 2 + iStart;
755 pszName = KLDRMODPE_RVA2TYPE(pvBits, paRVANames[i - 1], const char *);
756 diff = kLdrHlpStrNComp(pszName, pchSymbol, cchSymbol);
757 if (!diff)
758 diff = pszName[cchSymbol] - 0;
759 if (diff < 0)
760 iStart = i + 1; /* The symbol must be after the current name. */
761 else if (diff)
762 iEnd = i - 1; /* The symbol must be before the current name. */
763 else
764 {
765 iExpOrd = paOrdinals[i - 1]; /* match! */
766 break;
767 }
768 }
769 }
770
771 /*
772 * Lookup the address in the 'symbol' table.
773 */
774 paExportRVAs = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfFunctions, const uint32_t *);
775 uRVA = paExportRVAs[iExpOrd];
776 if ( uRVA - pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
777 < pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
778 return kldrModPEDoForwarderQuery(pModPE, pvBits, KLDRMODPE_RVA2TYPE(pvBits, uRVA, const char *),
779 pfnGetForwarder, pvUser, puValue, pfKind);
780
781 /*
782 * Set the return value.
783 */
784 if (puValue)
785 *puValue = BaseAddress + uRVA;
786 if (pfKind)
787 *pfKind = (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
788 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT)
789 | KLDRSYMKIND_NO_TYPE;
790 return 0;
791}
792
793
794/**
795 * Deal with a forwarder entry.
796 *
797 * We do this seprately from kldrModPEQuerySymbol because the code is clumsy (as is all PE code
798 * thanks to the descriptive field names), and because it uses quite a bit more stack and we're
799 * trying to avoid allocating stack unless we have to.
800 *
801 * @returns See kLdrModQuerySymbol.
802 * @param pModPE The PE module interpreter instance.
803 * @param pvBits Where to read the image from.
804 * @param pszForwarder The forwarder entry name.
805 * @param pfnGetForwarder The callback for resolving forwarder symbols. (optional)
806 * @param pvUser The user argument for the callback.
807 * @param puValue Where to put the value. (optional)
808 * @param pfKind Where to put the symbol kind. (optional)
809 */
810static int kldrModPEDoForwarderQuery(PKLDRMODPE pModPE, const void *pvBits, const char *pszForwarder,
811 PFNKLDRMODGETIMPORT pfnGetForwarder, void *pvUser, PKLDRADDR puValue, uint32_t *pfKind)
812{
813 const IMAGE_IMPORT_DESCRIPTOR *paImpDir;
814 uint32_t iImpModule;
815 uint32_t cchImpModule;
816 const char *pszSymbol;
817 uint32_t iSymbol;
818 int rc;
819
820 if (!pfnGetForwarder)
821 return KLDR_ERR_FORWARDER_SYMBOL;
822
823 /*
824 * Separate the name into a module name and a symbol name or ordinal.
825 *
826 * The module name ends at the first dot ('.').
827 * After the dot follows either a symbol name or a hash ('#') + ordinal.
828 */
829 pszSymbol = pszForwarder;
830 while (*pszSymbol != '.')
831 pszSymbol++;
832 if (!*pszSymbol)
833 return KLDR_ERR_PE_BAD_FORWARDER;
834 cchImpModule = pszSymbol - pszForwarder;
835
836 pszSymbol++; /* skip the dot */
837 if (!*pszSymbol)
838 return KLDR_ERR_PE_BAD_FORWARDER;
839 if (*pszSymbol == '#')
840 {
841 unsigned uBase;
842 pszSymbol++; /* skip the hash */
843
844 /* base detection */
845 uBase = 10;
846 if (pszSymbol[0] == '0' && (pszSymbol[1] == 'x' || pszSymbol[1] == 'X'))
847 {
848 uBase = 16;
849 pszSymbol += 2;
850 }
851
852 /* ascii to integer */
853 iSymbol = 0;
854 for (;;)
855 {
856 /* convert char to digit. */
857 unsigned uDigit = *pszSymbol++;
858 if (uDigit >= '0' && uDigit <= '9')
859 uDigit -= '0';
860 else if (uDigit >= 'a' && uDigit <= 'z')
861 uDigit -= 'a' + 10;
862 else if (uDigit >= 'A' && uDigit <= 'Z')
863 uDigit -= 'A' + 10;
864 else if (!uDigit)
865 break;
866 else
867 return KLDR_ERR_PE_BAD_FORWARDER;
868 if (uDigit >= uBase)
869 return KLDR_ERR_PE_BAD_FORWARDER;
870
871 /* insert the digit */
872 iSymbol *= uBase;
873 iSymbol += uDigit;
874 }
875
876 pszSymbol = NULL; /* no symbol name. */
877 }
878 else
879 iSymbol = NIL_KLDRMOD_SYM_ORDINAL; /* no ordinal number. */
880
881
882 /*
883 * Find the import module name.
884 *
885 * We ASSUME the linker will make sure there is an import
886 * entry for the module... not sure if this is right though.
887 */
888 if ( !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
889 || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
890 return KLDR_ERR_PE_FORWARDER_IMPORT_NOT_FOUND;
891 paImpDir = KLDRMODPE_RVA2TYPE(pvBits,
892 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
893 const IMAGE_IMPORT_DESCRIPTOR *);
894
895 kldrModPENumberOfImports(pModPE->pMod, pvBits);
896 for (iImpModule = 0; iImpModule < pModPE->cImportModules; iImpModule++)
897 {
898 const char *pszName = KLDRMODPE_RVA2TYPE(pvBits, paImpDir[iImpModule].Name, const char *);
899 size_t cchName = kLdrHlpStrLen(pszName);
900 if ( ( cchName == cchImpModule
901 || ( cchName > cchImpModule
902 && pszName[cchImpModule] == '.'
903 && (pszName[cchImpModule + 1] == 'd' || pszName[cchImpModule + 1] == 'D')
904 && (pszName[cchImpModule + 2] == 'l' || pszName[cchImpModule + 2] == 'L')
905 && (pszName[cchImpModule + 3] == 'l' || pszName[cchImpModule + 3] == 'L'))
906 )
907 && kLdrHlpMemIComp(pszName, pszForwarder, cchImpModule)
908 )
909 {
910 /*
911 * Now the rest is up to the callback (almost).
912 */
913 rc = pfnGetForwarder(pModPE->pMod, iImpModule, iSymbol, pszSymbol,
914 pszSymbol ? kLdrHlpStrLen(pszSymbol) : 0, NULL, puValue, pfKind, pvUser);
915 if (!rc && pfKind)
916 *pfKind |= KLDRSYMKIND_FORWARDER;
917 return rc;
918 }
919 }
920 return KLDR_ERR_PE_FORWARDER_IMPORT_NOT_FOUND;
921}
922
923
924/** @copydoc kLdrModEnumSymbols */
925static int kldrModPEEnumSymbols(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress,
926 uint32_t fFlags, PFNKLDRMODENUMSYMS pfnCallback, void *pvUser)
927{
928 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
929 const uint32_t *paFunctions;
930 const IMAGE_EXPORT_DIRECTORY *pExpDir;
931 const uint32_t *paRVANames;
932 const uint16_t *paOrdinals;
933 uint32_t iFunction;
934 uint32_t cFunctions;
935 uint32_t cNames;
936 int rc;
937
938 /*
939 * Make sure we've got mapped bits and resolve any base address aliases.
940 */
941 rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, &BaseAddress);
942 if (rc)
943 return rc;
944
945 if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size
946 < sizeof(IMAGE_EXPORT_DIRECTORY))
947 return 0; /* no exports to enumerate, return success. */
948
949 pExpDir = KLDRMODPE_RVA2TYPE(pvBits,
950 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,
951 PIMAGE_EXPORT_DIRECTORY);
952
953 /*
954 * Enumerate the ordinal exports.
955 */
956 paRVANames = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, const uint32_t *);
957 paOrdinals = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, const uint16_t *);
958 paFunctions = KLDRMODPE_RVA2TYPE(pvBits, pExpDir->AddressOfFunctions, const uint32_t *);
959 cFunctions = pExpDir->NumberOfFunctions;
960 cNames = pExpDir->NumberOfNames;
961 for (iFunction = 0; iFunction < cFunctions; iFunction++)
962 {
963 unsigned fFoundName;
964 uint32_t iName;
965 const uint32_t uRVA = paFunctions[iFunction];
966 const KLDRADDR uValue = BaseAddress + uRVA;
967 uint32_t fKind = (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32)
968 ? KLDRSYMKIND_32BIT : KLDRSYMKIND_64BIT)
969 | KLDRSYMKIND_NO_TYPE;
970 if ( uRVA - pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
971 < pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
972 fKind |= KLDRSYMKIND_FORWARDER;
973
974 /*
975 * Any symbol names?
976 */
977 fFoundName = 0;
978 for (iName = 0; iName < cNames; iName++)
979 {
980 const char *pszName;
981 if (paOrdinals[iName] != iFunction)
982 continue;
983 fFoundName = 1;
984 pszName = KLDRMODPE_RVA2TYPE(pvBits, paRVANames[iName], const char *);
985 rc = pfnCallback(pMod, iFunction + pExpDir->Base, pszName, kLdrHlpStrLen(pszName), NULL,
986 uValue, fKind, pvUser);
987 if (rc)
988 return rc;
989 }
990
991 /*
992 * If no names, call once with the ordinal only.
993 */
994 if (!fFoundName)
995 {
996 rc = pfnCallback(pMod, iFunction + pExpDir->Base, NULL, 0, NULL, uValue, fKind, pvUser);
997 if (rc)
998 return rc;
999 }
1000 }
1001
1002 return 0;
1003}
1004
1005
1006/** @copydoc kLdrModGetImport */
1007static int kldrModPEGetImport(PKLDRMOD pMod, const void *pvBits, uint32_t iImport, char *pszName, size_t cchName)
1008{
1009 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1010 const IMAGE_IMPORT_DESCRIPTOR *pImpDesc;
1011 const char *pszImportName;
1012 size_t cchImportName;
1013 int rc;
1014
1015 /*
1016 * Make sure we've got mapped bits and resolve any base address aliases.
1017 */
1018 rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, NULL);
1019 if (rc)
1020 return rc;
1021
1022 /*
1023 * Simple bounds check.
1024 */
1025 if (iImport >= (uint32_t)kldrModPENumberOfImports(pMod, pvBits))
1026 return KLDR_ERR_IMPORT_ORDINAL_OUT_OF_BOUNDS;
1027
1028 /*
1029 * Get the name.
1030 */
1031 pImpDesc = KLDRMODPE_RVA2TYPE(pvBits,
1032 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress
1033 + sizeof(IMAGE_IMPORT_DESCRIPTOR) * iImport,
1034 const IMAGE_IMPORT_DESCRIPTOR *);
1035 pszImportName = KLDRMODPE_RVA2TYPE(pvBits, pImpDesc->Name, const char *);
1036 cchImportName = kLdrHlpStrLen(pszImportName);
1037 if (cchImportName < cchName)
1038 {
1039 kLdrHlpMemCopy(pszName, pszImportName, cchImportName + 1);
1040 rc = 0;
1041 }
1042 else
1043 {
1044 kLdrHlpMemCopy(pszName, pszImportName, cchName);
1045 if (cchName)
1046 pszName[cchName - 1] = '\0';
1047 rc = KLDR_ERR_BUFFER_OVERFLOW;
1048 }
1049
1050 return rc;
1051}
1052
1053
1054/** @copydoc kLdrModNumberOfImports */
1055static int32_t kldrModPENumberOfImports(PKLDRMOD pMod, const void *pvBits)
1056{
1057 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1058 if (pModPE->cImportModules == ~(uint32_t)0)
1059 {
1060 /*
1061 * We'll have to walk the import descriptors to figure out their number.
1062 * First, make sure we've got mapped bits.
1063 */
1064 if (kldrModPEBitsAndBaseAddress(pModPE, &pvBits, NULL))
1065 return -1;
1066 pModPE->cImportModules = 0;
1067 if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
1068 && pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
1069 {
1070 const IMAGE_IMPORT_DESCRIPTOR *pImpDesc;
1071
1072 pImpDesc = KLDRMODPE_RVA2TYPE(pvBits,
1073 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
1074 const IMAGE_IMPORT_DESCRIPTOR *);
1075 while (pImpDesc->Name && pImpDesc->FirstThunk)
1076 {
1077 pModPE->cImportModules++;
1078 pImpDesc++;
1079 }
1080 }
1081 }
1082 return pModPE->cImportModules;
1083}
1084
1085
1086/** @copydoc kLdrModGetStackInfo */
1087static int kldrModPEGetStackInfo(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRSTACKINFO pStackInfo)
1088{
1089 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1090
1091 pStackInfo->Address = NIL_KLDRADDR;
1092 pStackInfo->LinkAddress = NIL_KLDRADDR;
1093 pStackInfo->cbStack = pStackInfo->cbStackThread = pModPE->Hdrs.OptionalHeader.SizeOfStackReserve;
1094
1095 return 0;
1096}
1097
1098
1099/** @copydoc kLdrModQueryMainEntrypoint */
1100static int kldrModPEQueryMainEntrypoint(PKLDRMOD pMod, const void *pvBits, KLDRADDR BaseAddress, PKLDRADDR pMainEPAddress)
1101{
1102 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1103 int rc;
1104
1105 /*
1106 * Resolve base address alias if any.
1107 */
1108 rc = kldrModPEBitsAndBaseAddress(pModPE, NULL, &BaseAddress);
1109 if (rc)
1110 return rc;
1111
1112 /*
1113 * Convert the address from the header.
1114 */
1115 *pMainEPAddress = pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint
1116 ? BaseAddress + pModPE->Hdrs.OptionalHeader.AddressOfEntryPoint
1117 : NIL_KLDRADDR;
1118 return 0;
1119}
1120
1121
1122/** @copydoc kLdrModEnumDbgInfo */
1123static int kldrModPEEnumDbgInfo(PKLDRMOD pMod, const void *pvBits, PFNKLDRENUMDBG pfnCallback, void *pvUser)
1124{
1125 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1126 const IMAGE_DEBUG_DIRECTORY *pDbgDir;
1127 uint32_t iDbgInfo;
1128 uint32_t cb;
1129 int rc;
1130
1131 /*
1132 * Check that there is a debug directory first.
1133 */
1134 cb = pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
1135 if ( cb < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
1136 || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
1137 return 0;
1138
1139 /*
1140 * Make sure we've got mapped bits.
1141 */
1142 rc = kldrModPEBitsAndBaseAddress(pModPE, &pvBits, NULL);
1143 if (rc)
1144 return rc;
1145
1146 /*
1147 * Enumerate the debug directory.
1148 */
1149 pDbgDir = KLDRMODPE_RVA2TYPE(pvBits,
1150 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress,
1151 const IMAGE_DEBUG_DIRECTORY *);
1152 for (iDbgInfo = 0;; iDbgInfo++, pDbgDir++, cb -= sizeof(IMAGE_DEBUG_DIRECTORY))
1153 {
1154 KLDRDBGINFOTYPE enmDbgInfoType;
1155
1156 /* convert the type. */
1157 switch (pDbgDir->Type)
1158 {
1159 case IMAGE_DEBUG_TYPE_UNKNOWN:
1160 case IMAGE_DEBUG_TYPE_FPO:
1161 case IMAGE_DEBUG_TYPE_COFF: /*stabs dialect??*/
1162 case IMAGE_DEBUG_TYPE_MISC:
1163 case IMAGE_DEBUG_TYPE_EXCEPTION:
1164 case IMAGE_DEBUG_TYPE_FIXUP:
1165 case IMAGE_DEBUG_TYPE_BORLAND:
1166 default:
1167 enmDbgInfoType = KLDRDBGINFOTYPE_UNKNOWN;
1168 break;
1169 case IMAGE_DEBUG_TYPE_CODEVIEW:
1170 enmDbgInfoType = KLDRDBGINFOTYPE_CODEVIEW;
1171 break;
1172 }
1173
1174 rc = pfnCallback(pMod, iDbgInfo,
1175 enmDbgInfoType, pDbgDir->MajorVersion, pDbgDir->MinorVersion,
1176 pDbgDir->PointerToRawData ? pDbgDir->PointerToRawData : -1,
1177 pDbgDir->AddressOfRawData ? pDbgDir->AddressOfRawData : NIL_KLDRADDR,
1178 pDbgDir->SizeOfData,
1179 NULL,
1180 pvUser);
1181 if (rc)
1182 break;
1183
1184 /* next */
1185 if (cb <= sizeof(IMAGE_DEBUG_DIRECTORY))
1186 break;
1187 }
1188
1189 return rc;
1190}
1191
1192
1193/** @copydoc kLdrModHasDbgInfo */
1194static int kldrModPEHasDbgInfo(PKLDRMOD pMod, const void *pvBits)
1195{
1196 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1197
1198 /*
1199 * Base this entirely on the presence of a debug directory.
1200 */
1201 if ( pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size
1202 < sizeof(IMAGE_DEBUG_DIRECTORY) /* screw borland linkers */
1203 || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress)
1204 return KLDR_ERR_NO_DEBUG_INFO;
1205 return 0;
1206}
1207
1208
1209/** @copydoc kLdrModMap */
1210static int kldrModPEMap(PKLDRMOD pMod)
1211{
1212 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1213 int rc;
1214
1215 /*
1216 * Already mapped?
1217 */
1218 if (pModPE->pvMapping)
1219 return KLDR_ERR_ALREADY_MAPPED;
1220
1221 /*
1222 * We've got a common worker which does this.
1223 */
1224 rc = kldrModPEDoMap(pModPE, 1 /* the real thing */);
1225 if (rc)
1226 return rc;
1227 KLDRMODPE_ASSERT(pModPE->pvMapping);
1228 return 0;
1229}
1230
1231
1232/** @copydoc kLdrModUnmap */
1233static int kldrModPEUnmap(PKLDRMOD pMod)
1234{
1235 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1236 int rc;
1237
1238 /*
1239 * Mapped?
1240 */
1241 if (!pModPE->pvMapping)
1242 return KLDR_ERR_NOT_MAPPED;
1243
1244 /*
1245 * We've got a common worker which does this.
1246 */
1247 rc = kldrModPEDoUnmap(pModPE, pModPE->pvMapping);
1248 if (rc)
1249 return rc;
1250 KLDRMODPE_ASSERT(pModPE->pvMapping);
1251 return 0;
1252
1253}
1254
1255
1256/** @copydoc kLdrModAllocTLS */
1257static int kldrModPEAllocTLS(PKLDRMOD pMod)
1258{
1259 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1260
1261 /*
1262 * Mapped?
1263 */
1264 if (!pModPE->pvMapping)
1265 return KLDR_ERR_NOT_MAPPED;
1266
1267 /*
1268 * If no TLS directory then there is nothing to do.
1269 */
1270 if ( !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size
1271 || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress)
1272 return 0;
1273 /** @todo implement TLS. */
1274 return -1;
1275}
1276
1277
1278/** @copydoc kLdrModFreeTLS */
1279static void kldrModPEFreeTLS(PKLDRMOD pMod)
1280{
1281 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1282
1283 /*
1284 * Mapped?
1285 */
1286 if (!pModPE->pvMapping)
1287 return;
1288
1289 /*
1290 * If no TLS directory then there is nothing to do.
1291 */
1292 if ( !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size
1293 || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress)
1294 return;
1295 /** @todo implement TLS. */
1296 return;
1297}
1298
1299
1300/** @copydoc kLdrModReload */
1301static int kldrModPEReload(PKLDRMOD pMod)
1302{
1303 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1304
1305 /*
1306 * Mapped?
1307 */
1308 if (!pModPE->pvMapping)
1309 return KLDR_ERR_NOT_MAPPED;
1310
1311 /* the file provider does it all */
1312 return kLdrRdrRefresh(pMod->pRdr, (void *)pModPE->pvMapping, pMod->cSegments, pMod->aSegments);
1313}
1314
1315
1316/** @copydoc kLdrModFixupMapping */
1317static int kldrModPEFixupMapping(PKLDRMOD pMod, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1318{
1319 PKLDRMODPE pModPE = (PKLDRMODPE)pMod->pvData;
1320 int rc, rc2;
1321
1322 /*
1323 * Mapped?
1324 */
1325 if (!pModPE->pvMapping)
1326 return KLDR_ERR_NOT_MAPPED;
1327
1328 /*
1329 * Before doing anything we'll have to make all pages writable.
1330 */
1331 rc = kLdrRdrProtect(pMod->pRdr, (void *)pModPE->pvMapping, pMod->cSegments, pMod->aSegments, 1 /* unprotect */);
1332 if (rc)
1333 return rc;
1334
1335 /*
1336 * Apply base relocations.
1337 */
1338 rc = kldrModPEDoFixups(pModPE, (void *)pModPE->pvMapping, (uintptr_t)pModPE->pvMapping,
1339 pModPE->Hdrs.OptionalHeader.ImageBase);
1340
1341 /*
1342 * Resolve imports.
1343 */
1344 if (!rc)
1345 rc = kldrModPEDoImports(pModPE, (void *)pModPE->pvMapping, pfnGetImport, pvUser);
1346
1347 /*
1348 * Restore protection.
1349 */
1350 rc2 = kLdrRdrProtect(pMod->pRdr, (void *)pModPE->pvMapping, pMod->cSegments, pMod->aSegments, 0 /* protect */);
1351 if (!rc && rc2)
1352 rc = rc2;
1353 return rc;
1354}
1355
1356
1357/**
1358 * Applies base relocations to a (unprotected) image mapping.
1359 *
1360 * @returns 0 on success, non-zero kLdr status code on failure.
1361 * @param pModPE The PE module interpreter instance.
1362 * @param pvMapping The mapping to fixup.
1363 * @param NewBaseAddress The address to fixup the mapping to.
1364 * @param OldBaseAddress The address the mapping is currently fixed up to.
1365 */
1366static int kldrModPEDoFixups(PKLDRMODPE pModPE, void *pvMapping, KLDRADDR NewBaseAddress, KLDRADDR OldBaseAddress)
1367{
1368 const KLDRADDR Delta = NewBaseAddress - OldBaseAddress;
1369 uint32_t cbLeft = pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
1370 const IMAGE_BASE_RELOCATION *pBR, *pFirstBR;
1371
1372 /*
1373 * Don't don anything if the delta is 0 or there aren't any relocations.
1374 */
1375 if ( !Delta
1376 || !cbLeft
1377 || !pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
1378 return 0;
1379
1380 /*
1381 * Process the fixups block by block.
1382 * (These blocks appears to be 4KB on all archs despite the native page size.)
1383 */
1384 pBR = pFirstBR = KLDRMODPE_RVA2TYPE(pvMapping,
1385 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
1386 const IMAGE_BASE_RELOCATION *);
1387 while ( cbLeft > sizeof(IMAGE_BASE_RELOCATION)
1388 && pBR->SizeOfBlock >= sizeof(IMAGE_BASE_RELOCATION) /* paranoia */)
1389 {
1390 union
1391 {
1392 uint8_t *pu8;
1393 uint16_t *pu16;
1394 uint32_t *pu32;
1395 uint64_t *pu64;
1396 } uChunk,
1397 u;
1398 const uint16_t *poffFixup = (const uint16_t *)(pBR + 1);
1399 const uint32_t cbBlock = KLDR_MIN(cbLeft, pBR->SizeOfBlock) - sizeof(IMAGE_BASE_RELOCATION); /* more caution... */
1400 uint32_t cFixups = cbBlock / sizeof(poffFixup[0]);
1401 uChunk.pu8 = KLDRMODPE_RVA2TYPE(pvMapping, pBR->VirtualAddress, uint8_t *);
1402
1403 /*
1404 * Loop thru the fixups in this chunk.
1405 */
1406 while (cFixups > 0)
1407 {
1408 u.pu8 = uChunk.pu8 + (*poffFixup & 0xfff);
1409 switch (*poffFixup >> 12) /* ordered by value. */
1410 {
1411 /* 0 - Alignment placeholder. */
1412 case IMAGE_REL_BASED_ABSOLUTE:
1413 break;
1414
1415 /* 1 - 16-bit, add 2nd 16-bit part of the delta. (rare) */
1416 case IMAGE_REL_BASED_HIGH:
1417 *u.pu16 += (uint16_t)(Delta >> 16);
1418 break;
1419
1420 /* 2 - 16-bit, add 1st 16-bit part of the delta. (rare) */
1421 case IMAGE_REL_BASED_LOW:
1422 *u.pu16 += (uint16_t)Delta;
1423 break;
1424
1425 /* 3 - 32-bit, add delta. (frequent in 32-bit images) */
1426 case IMAGE_REL_BASED_HIGHLOW:
1427 *u.pu32 += (uint32_t)Delta;
1428 break;
1429
1430 /* 4 - 16-bit, add 2nd 16-bit of the delta, sign adjust for the lower 16-bit. one arg. (rare) */
1431 case IMAGE_REL_BASED_HIGHADJ:
1432 {
1433 int32_t i32;
1434 if (cFixups <= 1)
1435 return KLDR_ERR_PE_BAD_FIXUP;
1436
1437 i32 = (uint32_t)*u.pu16 << 16;
1438 i32 |= *++poffFixup; cFixups--; /* the addend argument */
1439 i32 += (uint32_t)Delta;
1440 i32 += 0x8000;
1441 *u.pu16 = (uint16_t)(i32 >> 16);
1442 break;
1443 }
1444
1445 /* 5 - 32-bit MIPS JMPADDR, no implemented. */
1446 case IMAGE_REL_BASED_MIPS_JMPADDR:
1447 *u.pu32 = (*u.pu32 & 0xc0000000)
1448 | ((uint32_t)((*u.pu32 << 2) + (uint32_t)Delta) >> 2);
1449 break;
1450
1451 /* 6 - Intra section? Reserved value in later specs. Not implemented. */
1452 case IMAGE_REL_BASED_SECTION:
1453 KLDRMODPE_ASSERT(!"SECTION");
1454 return KLDR_ERR_PE_BAD_FIXUP;
1455
1456 /* 7 - Relative intra section? Reserved value in later specs. Not implemented. */
1457 case IMAGE_REL_BASED_REL32:
1458 KLDRMODPE_ASSERT(!"SECTION");
1459 return KLDR_ERR_PE_BAD_FIXUP;
1460
1461 /* 8 - reserved according to binutils... */
1462 case 8:
1463 KLDRMODPE_ASSERT(!"RESERVERED8");
1464 return KLDR_ERR_PE_BAD_FIXUP;
1465
1466 /* 9 - IA64_IMM64 (/ MIPS_JMPADDR16), no specs nor need to support the platform yet.
1467 * Bet this requires more code than all the other fixups put together in good IA64 spirit :-) */
1468 case IMAGE_REL_BASED_IA64_IMM64:
1469 KLDRMODPE_ASSERT(!"IA64_IMM64 / MIPS_JMPADDR16");
1470 return KLDR_ERR_PE_BAD_FIXUP;
1471
1472 /* 10 - 64-bit, add delta. (frequently in 64-bit images) */
1473 case IMAGE_REL_BASED_DIR64:
1474 *u.pu64 += (uint64_t)Delta;
1475 break;
1476
1477 /* 11 - 16-bit, add 3rd 16-bit of the delta, sign adjust for the lower 32-bit. two args. (rare) */
1478 case IMAGE_REL_BASED_HIGH3ADJ:
1479 {
1480 int64_t i64;
1481 if (cFixups <= 2)
1482 return KLDR_ERR_PE_BAD_FIXUP;
1483
1484 i64 = (uint64_t)*u.pu16 << 32
1485 | ((uint32_t)poffFixup[2] << 16)
1486 | poffFixup[1];
1487 i64 += Delta;
1488 i64 += 0x80008000UL;
1489 *u.pu16 = (uint16_t)(i64 >> 32);
1490 /* skip the addends arguments */
1491 poffFixup += 2;
1492 cFixups -= 2;
1493 break;
1494 }
1495
1496 /* the rest are yet to be defined.*/
1497 default:
1498 return KLDR_ERR_PE_BAD_FIXUP;
1499 }
1500
1501 /*
1502 * Next relocation.
1503 */
1504 poffFixup++;
1505 cFixups--;
1506 }
1507
1508
1509 /*
1510 * Next block.
1511 */
1512 cbLeft -= pBR->SizeOfBlock;
1513 pBR = (PIMAGE_BASE_RELOCATION)((uintptr_t)pBR + pBR->SizeOfBlock);
1514 }
1515
1516 return 0;
1517}
1518
1519
1520
1521/**
1522 * Resolves imports.
1523 *
1524 * @returns 0 on success, non-zero kLdr status code on failure.
1525 * @param pModPE The PE module interpreter instance.
1526 * @param pvMapping The mapping which imports should be resolved.
1527 * @param pfnGetImport The callback for resolving an imported symbol.
1528 * @param pvUser User argument to the callback.
1529 */
1530static int kldrModPEDoImports(PKLDRMODPE pModPE, void *pvMapping, PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1531{
1532 const IMAGE_IMPORT_DESCRIPTOR *pImpDesc;
1533
1534 /*
1535 * If no imports, there is nothing to do.
1536 */
1537 kldrModPENumberOfImports(pModPE->pMod, pvMapping);
1538 if (!pModPE->cImportModules)
1539 return 0;
1540
1541 pImpDesc = KLDRMODPE_RVA2TYPE(pvMapping,
1542 pModPE->Hdrs.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress,
1543 const IMAGE_IMPORT_DESCRIPTOR *);
1544 if (pModPE->Hdrs.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
1545 return kldrModPEDoImports32Bit(pModPE, pvMapping, pImpDesc, pfnGetImport, pvUser);
1546 return kldrModPEDoImports64Bit(pModPE, pvMapping, pImpDesc, pfnGetImport, pvUser);
1547}
1548
1549
1550/**
1551 * Resolves imports, 32-bit image.
1552 *
1553 * @returns 0 on success, non-zero kLdr status code on failure.
1554 * @param pModPE The PE module interpreter instance.
1555 * @param pvMapping The mapping which imports should be resolved.
1556 * @param pImpDesc Pointer to the first import descriptor.
1557 * @param pfnGetImport The callback for resolving an imported symbol.
1558 * @param pvUser User argument to the callback.
1559 */
1560static int kldrModPEDoImports32Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc,
1561 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1562{
1563 PKLDRMOD pMod = pModPE->pMod;
1564 uint32_t iImp;
1565
1566 /*
1567 * Iterate the import descriptors.
1568 */
1569 for (iImp = 0; iImp < pModPE->cImportModules; iImp++, pImpDesc++)
1570 {
1571 PIMAGE_THUNK_DATA32 pFirstThunk = KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, PIMAGE_THUNK_DATA32);
1572 const IMAGE_THUNK_DATA32 *pThunk = pImpDesc->u.OriginalFirstThunk
1573 ? KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->u.OriginalFirstThunk, const IMAGE_THUNK_DATA32 *)
1574 : KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, const IMAGE_THUNK_DATA32 *);
1575
1576 /* Iterate the thunks. */
1577 while (pThunk->u1.Ordinal != 0)
1578 {
1579 KLDRADDR Value;
1580 uint32_t fKind;
1581 int rc;
1582
1583 /* Ordinal or name import? */
1584 if (IMAGE_SNAP_BY_ORDINAL32(pThunk->u1.Ordinal))
1585 rc = pfnGetImport(pMod, iImp, IMAGE_ORDINAL32(pThunk->u1.Ordinal), NULL, 0, NULL, &Value, &fKind, pvUser);
1586 else if (KLDRMODPE_VALID_RVA(pModPE, pThunk->u1.Ordinal))
1587 {
1588 const IMAGE_IMPORT_BY_NAME *pName = KLDRMODPE_RVA2TYPE(pvMapping, pThunk->u1.Ordinal, const IMAGE_IMPORT_BY_NAME *);
1589 rc = pfnGetImport(pMod, iImp, NIL_KLDRMOD_SYM_ORDINAL, (const char *)pName->Name,
1590 kLdrHlpStrLen((const char *)pName->Name), NULL, &Value, &fKind, pvUser);
1591 }
1592 else
1593 {
1594 KLDRMODPE_ASSERT(!"bad 32-bit import");
1595 return KLDR_ERR_PE_BAD_IMPORT;
1596 }
1597
1598 /* Apply it. */
1599 pFirstThunk->u1.Function = (uint32_t)Value;
1600 if (pFirstThunk->u1.Function != Value)
1601 {
1602 KLDRMODPE_ASSERT(!"overflow");
1603 return KLDR_ERR_ADDRESS_OVERFLOW;
1604 }
1605
1606 /* next */
1607 pThunk++;
1608 pFirstThunk++;
1609 }
1610 }
1611
1612 return 0;
1613}
1614
1615
1616/**
1617 * Resolves imports, 64-bit image.
1618 *
1619 * @returns 0 on success, non-zero kLdr status code on failure.
1620 * @param pModPE The PE module interpreter instance.
1621 * @param pvMapping The mapping which imports should be resolved.
1622 * @param pImpDesc Pointer to the first import descriptor.
1623 * @param pfnGetImport The callback for resolving an imported symbol.
1624 * @param pvUser User argument to the callback.
1625 */
1626static int kldrModPEDoImports64Bit(PKLDRMODPE pModPE, void *pvMapping, const IMAGE_IMPORT_DESCRIPTOR *pImpDesc,
1627 PFNKLDRMODGETIMPORT pfnGetImport, void *pvUser)
1628{
1629 PKLDRMOD pMod = pModPE->pMod;
1630 uint32_t iImp;
1631
1632 /*
1633 * Iterate the import descriptors.
1634 */
1635 for (iImp = 0; iImp < pModPE->cImportModules; iImp++, pImpDesc++)
1636 {
1637 PIMAGE_THUNK_DATA64 pFirstThunk = KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, PIMAGE_THUNK_DATA64);
1638 const IMAGE_THUNK_DATA64 *pThunk = pImpDesc->u.OriginalFirstThunk
1639 ? KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->u.OriginalFirstThunk, const IMAGE_THUNK_DATA64 *)
1640 : KLDRMODPE_RVA2TYPE(pvMapping, pImpDesc->FirstThunk, const IMAGE_THUNK_DATA64 *);
1641
1642 /* Iterate the thunks. */
1643 while (pThunk->u1.Ordinal != 0)
1644 {
1645 KLDRADDR Value;
1646 uint32_t fKind;
1647 int rc;
1648
1649 /* Ordinal or name import? */
1650 if (IMAGE_SNAP_BY_ORDINAL64(pThunk->u1.Ordinal))
1651 rc = pfnGetImport(pMod, iImp, (uint32_t)IMAGE_ORDINAL64(pThunk->u1.Ordinal), NULL, 0, NULL, &Value, &fKind, pvUser);
1652 else if (KLDRMODPE_VALID_RVA(pModPE, pThunk->u1.Ordinal))
1653 {
1654 const IMAGE_IMPORT_BY_NAME *pName = KLDRMODPE_RVA2TYPE(pvMapping, pThunk->u1.Ordinal, const IMAGE_IMPORT_BY_NAME *);
1655 rc = pfnGetImport(pMod, iImp, NIL_KLDRMOD_SYM_ORDINAL, (const char *)pName->Name,
1656 kLdrHlpStrLen((const char *)pName->Name), NULL, &Value, &fKind, pvUser);
1657 }
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 NULL, /** @todo resources */
1958 NULL, /** @todo resources */
1959 kldrModPEEnumDbgInfo,
1960 kldrModPEHasDbgInfo,
1961 kldrModPEMap,
1962 kldrModPEUnmap,
1963 kldrModPEAllocTLS,
1964 kldrModPEFreeTLS,
1965 kldrModPEReload,
1966 kldrModPEFixupMapping,
1967 kldrModPECallInit,
1968 kldrModPECallTerm,
1969 kldrModPECallThread,
1970 kldrModPESize,
1971 kldrModPEGetBits,
1972 kldrModPERelocateBits,
1973 NULL, /** @todo mostly done */
1974 42 /* the end */
1975};
Note: See TracBrowser for help on using the repository browser.