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

Last change on this file since 3574 was 3574, checked in by bird, 18 years ago

Generic kHlpString.h implementation.

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