source: trunk/kLdr/kLdrModPE.c@ 2877

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

Module interpreter for modules loaded by the native loader. (untested)

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