VirtualBox

source: kStuff/trunk/kLdr/kLdrModPE.c@ 89

Last change on this file since 89 was 89, checked in by bird, 8 years ago

kLdrModPE.cpp: warnings.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette