source: trunk/kLdr/kLdrModPE.c@ 2859

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

More debugging.

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