VirtualBox

source: kStuff/trunk/kLdr/kLdrModPE.c

Last change on this file was 117, checked in by bird, 5 years ago

kLdrModNative: Added KLDRMOD_OPEN_FLAGS_NATIVE_ALLOW_INIT_TERM to allow kWorker to re-init mspdb100.dll when _MSPDBSRV_ENDPOINT_ changes.

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