source: trunk/kLdr/kLdrModPE.c@ 2860

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

Working on the mapping stuff (windows is gonna be a headache).

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