source: trunk/src/win32k/pe2lx/pe2lx.cpp@ 9957

Last change on this file since 9957 was 9957, checked in by bird, 22 years ago

Cleaned up Customb Dll handling, pluss exclude dll feature. Added support for all object RW.

File size: 228.9 KB
Line 
1/* $Id: pe2lx.cpp,v 1.35 2003-03-31 02:52:49 bird Exp $
2 *
3 * Pe2Lx class implementation. Ring 0 and Ring 3
4 *
5 * Copyright (c) 1998-2000 knut st. osmundsen (knut.stange.osmundsen@mynd.no)
6 * Copyright (c) 1998 Sander van Leeuwen (sandervl@xs4all.nl)
7 * Copyright (c) 1998 Peter Fitzsimmons
8 *
9 * Project Odin Software License can be found in LICENSE.TXT
10 *
11 */
12
13
14/*******************************************************************************
15* Defined Constants And Macros *
16*******************************************************************************/
17#define FOR_EXEHDR 1 /* To make all object flags OBJ???. */
18#define INCL_DOSERRORS /* DOS Error codes. */
19#define INCL_OS2KRNL_LDR /* Loader definitions. */
20#define INCL_OS2KRNL_PTDA /* PTDA definitions. */
21#ifdef RING0
22 #define INCL_NOAPI /* RING0: No apis. */
23#else /*RING3*/
24 #define INCL_DOSPROCESS /* RING3: DosSleep. */
25 #define INCL_OS2KRNL_LDR_NOAPIS /* No apis */
26#endif
27
28
29/*
30 * Configuration
31 */
32#define ORD_REGISTERPE2LXEXE 1203UL /* ordinal entry number for KERNEL32.RegisterPe2LxExe. */
33#define ORD_REGISTERPE2LXDLL 1209UL /* Ordinal entry number for KERNEL32.RegisterPe2LxDll. */
34#define TIBFIX_OFF_CALLADDRESS 14UL /* offset of 'mov cx, KERNEL32:RegisterPe2LxDll/Exe' */
35#define EXTRA_FIXUPS 1 /* TIBFIX call to KERNEL32:RegisterPe2LxDll/Exe. */
36#define SIZEOF_TIBFIX sizeof(achTIBFix)
37
38#define MIN_STACK_SIZE 0x20000 /* 128KB stack */
39
40
41/*
42 * (macro)
43 * Allocates more memory for pointer 'pointer'.
44 * @returns ERROR_NOT_ENOUGH_MEMORY if realloc or malloc failes.
45 * @param test Test which is TRUE if more memory have to be allocated.
46 * @param pointer Variable name of the pointer which holds/will hold the memory.
47 * This variable may be changed to point on new memory block.
48 * @param pointertype Type of the pointer.
49 * @param cballocated Variable which holds the count of bytes currently allocated.
50 * This variable will be updated with the new amount of memory.
51 * @param initsize Initial count of bytes allocated.
52 * @param addsize Count of bytes to add when the amount of memory is increased.
53 * @author knut st. osmundsen
54 */
55#define AllocateMoreMemory(test, pointer, pointertype, cballocated, initsize, addsize) \
56 if (test) \
57 { \
58 if (pointer != NULL) \
59 { \
60 PVOID pv = realloc(pointer, (size_t)(cballocated + addsize)); \
61 if (pv == NULL) \
62 return ERROR_NOT_ENOUGH_MEMORY; \
63 pointer = (pointertype)pv; \
64 cballocated += addsize; \
65 } \
66 else \
67 { /* first block */ \
68 pointer = (pointertype)malloc((size_t)(initsize)); \
69 if (pointer == NULL) \
70 return ERROR_NOT_ENOUGH_MEMORY; \
71 cballocated = initsize; \
72 } \
73 }
74
75
76
77/*******************************************************************************
78* Header Files *
79*******************************************************************************/
80#include <os2.h> /* OS/2 header file. */
81#include <peexe.h> /* Wine PE structs and definitions. */
82#include <neexe.h> /* Wine NE structs and definitions. */
83#include <newexe.h> /* OS/2 NE structs and definitions. */
84#include <exe386.h> /* OS/2 LX structs and definitions. */
85
86#include "devSegDf.h" /* Win32k segment definitions. */
87
88#include "malloc.h" /* win32k malloc (resident). Not C library! */
89#include "smalloc.h" /* win32k swappable heap. */
90#include "rmalloc.h" /* win32k resident heap. */
91
92#include <string.h> /* C library string.h. */
93#include <stdlib.h> /* C library stdlib.h. */
94#include <stddef.h> /* C library stddef.h. */
95#include <stdarg.h> /* C library stdarg.h. */
96#ifndef RING0
97#include <stdio.h>
98#endif
99
100#include "vprintf.h" /* win32k printf and vprintf. Not C library! */
101#include "dev32.h" /* 32-Bit part of the device driver. (SSToDS) */
102#include "OS2Krnl.h" /* kernel structs. (SFN) */
103#ifdef RING0
104 #include "avl.h" /* AVL tree. (ldr.h need it) */
105 #include "ldr.h" /* ldr helpers. (ldrGetExePath) */
106 #include "env.h" /* Environment helpers. */
107 #include "dev32hlp.h" /* 32-bit devhlpers. Needs LOCKHANDLE. */
108 #include "PerTaskW32kData.h" /* Per Task Win32k Data. */
109#endif
110#include "modulebase.h" /* ModuleBase class definitions, ++. */
111#include "pe2lx.h" /* Pe2Lx class definitions, ++. */
112#include <versionos2.h> /* Pe2Lx version. */
113#include "yield.h" /* Yield CPU. */
114#include "options.h" /* Win32k options. */
115
116
117/*******************************************************************************
118* Global Variables *
119*******************************************************************************/
120/**
121 * TIBFix code. This is the entry code for both EXEs and DLLs. All it does is
122 * calling a KERNEL32 function with tree parameters.
123 * For EXE: RegisterPe2LxExe; DLL: RegisterPe2LxDll.
124 */
125static UCHAR achTIBFix[] =
126{
127 /* push [esp+8] */
128 0xFF, 0x74, 0x24, 0x08,
129 /* push [esp+4] */
130 0xFF, 0x74, 0x24, 0x08,
131 /* push internal pe2lx version */
132 0x68, (UCHAR)(PE2LX_VERSION),
133 (UCHAR)((PE2LX_VERSION) >> 8),
134 (UCHAR)((PE2LX_VERSION) >> 16),
135 #ifdef RING0 /* RING0: */
136 (UCHAR)(((PE2LX_VERSION) >> 24) | 0x80), /* Win32k flag (high bit of the version dword) set. */
137 #else /* RING3: */
138 (UCHAR)((PE2LX_VERSION) >> 24), /* Win32k flag (high bit of the version dword) clear. */
139 #endif
140 /* mov ecx, KERNEL32:RegisterPe2LxDll/Exe (stdcall) */
141 0xB9, 0x99, 0x99, 0x99, 0x99,
142 /* call ecx */
143 0xFF, 0xD1,
144 /* ret */
145 0xC3
146};
147
148
149/**
150 * Conversion table. Used when converting characteristics for sections to flags for objects.
151 * Usage: Loop through the table checking if the characterisicts matches ((x & ch) = ch).
152 * When a match is found, the flFlags are ORed to the object flags.
153 */
154struct Pe2Lx::PeCharacteristicsToLxFlags Pe2Lx::paSecChars2Flags[] =
155{ /* PE section characteristics LX object flags */
156 {IMAGE_SCN_CNT_CODE, OBJBIGDEF | OBJREAD | OBJEXEC},
157 {IMAGE_SCN_MEM_DISCARDABLE, OBJBIGDEF | OBJDISCARD},
158 {IMAGE_SCN_MEM_SHARED, OBJBIGDEF | OBJSHARED},
159 {IMAGE_SCN_MEM_EXECUTE, OBJBIGDEF | OBJREAD | OBJEXEC},
160 {IMAGE_SCN_MEM_READ, OBJBIGDEF | OBJREAD},
161 {IMAGE_SCN_MEM_WRITE, OBJBIGDEF | OBJREAD | OBJWRITE}
162};
163
164
165/**
166 * The Pe2Lx LieList. This list is used when there is a name difference between
167 * the odin32 module name and the win32 modulename. A reason for such a difference
168 * is for example that the modulename exists in OS/2 or another OS/2 product.
169 *
170 * When this list is updated a similar list in kernel32\xxxx.cpp should also be
171 * updated!
172 */
173struct Pe2Lx::LieListEntry Pe2Lx::paLieList[] =
174{ /* Win32 Module name Odin32 Module name*/
175 {"NETAPI32", "WNETAP32"},
176 {"NETAPI32.DLL", "WNETAP32"},
177 {"OLE32", "OLE32OS2"},
178 {"OLE32.DLL", "OLE32OS2"},
179 {"OLEAUT32.DLL", "OLAUTOS2"},
180 {"OLEAUT32", "OLAUTOS2"},
181 {"OPENGL", "OPENGL32"},
182 {"OPENGL.DLL", "OPENGL32"},
183 {"CRTDLL", "CRTDLL32"},
184 {"CRTDLL.DLL", "CRTDLL32"},
185 {"MCICDA.DRV", "MCICDA.DLL"},
186 {"WINSPOOL.DRV", "WINSPOOL.DLL"},
187 {NULL, NULL} /* end-of-list entry */
188};
189
190LONG Pe2Lx::cLoadedModules; /* Count of existing objects. Updated by constructor and destructor. */
191const char * Pe2Lx::pszOdin32Path; /* Odin32 base path (include a slash). */
192ULONG Pe2Lx::cchOdin32Path; /* Odin32 base path length. */
193SFN Pe2Lx::sfnKernel32; /* Odin32 Kernel32 filehandle. */
194
195
196
197/**
198 * Constructor. Initiates all data members and sets hFile.
199 * @param hFile Filehandle.
200 * @status Completely implemented.
201 * @author knut st. osmundsen
202 * @remark Remember to update this everytime a new parameter is added.
203 */
204Pe2Lx::Pe2Lx(SFN hFile) :
205 ModuleBase(hFile),
206 fAllInOneObject(FALSE), paObjects(NULL), cObjects(0), cObjectsAllocated(0),
207 paObjTab(NULL), paObjPageTab(NULL),
208 pachResNameTable(NULL), offCurResName(0), cchRNTAllocated(0),
209 pEntryBundles(NULL), offCurEntryBundle(0), offLastEntryBundle(0),
210 ulLastOrdinal(0), cbEBAllocated(0),
211 fForwarders(FALSE),
212 paulFixupPageTable(NULL), cFixupPTEntries(0), cFPTEAllocated(0),
213 pFixupRecords(NULL), offCurFixupRec(0), cbFRAllocated(0),
214 pvCrossPageFixup(NULL), cbCrossPageFixup(0),
215 pachImpModuleNames(NULL), offCurImpModuleName(0), cchIMNAllocated(0),
216 pachImpFunctionNames(NULL), offCurImpFunctionName(0), cchIFNAllocated(0),
217 offNtHeaders(0), pNtHdrs(NULL), ulImageBase(0UL), pBaseRelocs(0),
218 fApplyFixups(~0UL), fDeltaOnly(0)
219{
220 memset(&LXHdr, 0, sizeof(LXHdr));
221 LXHdr.e32_magic[0] = E32MAGIC1;
222 LXHdr.e32_magic[1] = E32MAGIC2;
223 LXHdr.e32_border = E32LEBO;
224 LXHdr.e32_worder = E32LEWO;
225 LXHdr.e32_level = E32LEVEL;
226 LXHdr.e32_cpu = E32CPU386;
227 LXHdr.e32_os = NE_OS2;
228 LXHdr.e32_pagesize = PAGESIZE;
229 LXHdr.e32_objtab = sizeof(LXHdr);
230 cLoadedModules++;
231}
232
233
234/**
235 * Destructor.
236 * @status completely implemented.
237 * @author knut st. osmundsen
238 */
239Pe2Lx::~Pe2Lx()
240{
241 if (paObjects != NULL)
242 {
243 free(paObjects);
244 paObjects = NULL;
245 }
246 if (paObjTab != NULL)
247 {
248 free(paObjTab);
249 paObjTab = NULL;
250 }
251 if (paObjPageTab != NULL)
252 {
253 free(paObjPageTab);
254 paObjPageTab = NULL;
255 }
256 if (pachResNameTable != NULL)
257 {
258 free(pachResNameTable);
259 pachResNameTable = NULL;
260 }
261 if (pEntryBundles != NULL)
262 {
263 free(pEntryBundles);
264 pEntryBundles = NULL;
265 }
266 if (paulFixupPageTable != NULL)
267 {
268 free(paulFixupPageTable);
269 paulFixupPageTable = NULL;
270 }
271 if (pFixupRecords != NULL)
272 {
273 free(pFixupRecords);
274 pFixupRecords = NULL;
275 }
276 if (pvCrossPageFixup != NULL)
277 {
278 free(pvCrossPageFixup);
279 pvCrossPageFixup = NULL;
280 }
281 if (pachImpModuleNames != NULL)
282 {
283 free(pachImpModuleNames);
284 pachImpModuleNames = NULL;
285 }
286 if (pachImpFunctionNames != NULL)
287 {
288 free(pachImpFunctionNames);
289 pachImpFunctionNames = NULL;
290 }
291 if (pNtHdrs != NULL)
292 {
293 free(pNtHdrs);
294 pNtHdrs = NULL;
295 }
296 if (pBaseRelocs != NULL)
297 {
298 sfree(pBaseRelocs);
299 pBaseRelocs = NULL;
300 }
301 _res_heapmin();
302 _swp_heapmin();
303
304 /*
305 * If no Pe2Lx objects left, then invalidate the Odin32Path.
306 * We'll have to do this since we may (theoretically) not receive
307 * a close on a kernel32 handle if loading failes before kernel32
308 * is loaded and the odin32path is determined using ldrOpenPath.
309 * (Ie. no sfnKernel32.)
310 */
311 if (--cLoadedModules <= 0)
312 invalidateOdin32Path();
313#ifdef DEBUG
314 if (cLoadedModules < 0)
315 printIPE(("Pe2Lx::cLoadedModules is %d which is less that zero!\n", cLoadedModules));
316#endif
317}
318
319
320/**
321 * Initiates the Pe2Lx object - builds the virtual LX image.
322 * When this function completes the object is no longer in init-mode.
323 * @returns NO_ERROR on success.
324 * ERROR_NOT_ENOUGH_MEMORY
325 * ERROR_INVALID_EXE_SIGNATURE
326 * ERROR_BAD_EXE_FORMAT
327 * Error code returned by ReadAt.
328 * Error codes from the make* methods.
329 * @param pszFilename Module filename.
330 * @precond Called in init-mode.
331 * @sketch
332 * 0. pszFilename & pszModuleName.
333 * 1. Read the from the start of the file, expect a MZ header.
334 * 2. If an PE header was found jump to 4.
335 * 3. Verify valid MZ header - if not fail. Determin PE offset.
336 * 4. Read PE headers.
337 * 5. Validate PE header (Magics, Machine, subsystem, characteristics,...) - fail if not valid.
338 * 6. Read sectiontable.
339 * 7. Start converting the sections by adding the headerobject. (headerobject, see previous chapter).
340 * 8. Iterate thru the sectiontable converting the section to objects.
341 * 8a. Convert characteristics to flags
342 * 8b. Virtual/physical size (see note in code)
343 * 8c. Add object.
344 * 9.Find where the TIB fix is to be placed. (see 3.1.1 for placements.) Place the TIB fix.
345 * 9a. At the end of the header object.
346 * 9b. After MZ-Header (In the dos stub!).
347 * 9c.Add separate TIBFix object.
348 * 10.Add stack object.
349 * 11.Align section. (Fix which is applied to EXEs/Dlls which contain no fixups and has an
350 * alignment which is not a multiple of 64Kb. The sections are concatenated into one big object.
351 * 12.Update the LXHeader with info which is finalized now. (Stacksize, GUI/CUI, characteristics,...)
352 * 13.Convert exports.
353 * 14.Convert base relocations (fixups). Remember to add the fixup for RegisterPe2LxDll/Exe.
354 * 15.Make object table.
355 * 16.Make object page table.
356 * 17.Completing the LX header.
357 * 18.Set offLXFile in the object array.
358 * 19.The conversion method is completed. Object is now usable.
359 * 20.Dump virtual LX-file
360 * return successfully.
361 * @status Completely implemented; tested.
362 * @author knut st. osmundsen
363 */
364ULONG Pe2Lx::init(PCSZ pszFilename)
365{
366 APIRET rc;
367 PIMAGE_DOS_HEADER pMzHdr;
368 int i, j;
369 PIMAGE_SECTION_HEADER paSections; /* Pointer to section headers */
370
371 #ifdef DEBUG
372 if (!fInitTime)
373 {
374 printIPE(("init(..) called when not in init mode!\n"));
375 return ERROR_INITMETHOD_NOT_INITTIME;
376 }
377 #endif
378
379 printInf(("Started processing %s\n", pszFilename));
380
381 /* 0.pszFilename & pszModuleName. */
382 rc = ModuleBase::init(pszFilename);
383 if (rc != NO_ERROR)
384 return rc;
385
386 /* 1.Read the from the start of the file, expect a MZ header. */
387 pMzHdr = (PIMAGE_DOS_HEADER)malloc(sizeof(IMAGE_DOS_HEADER));
388 if (pMzHdr == NULL)
389 return ERROR_NOT_ENOUGH_MEMORY;
390 rc = ReadAt(hFile, 0UL, pMzHdr, sizeof(IMAGE_DOS_HEADER));
391 if (rc != NO_ERROR)
392 {
393 free(pMzHdr);
394 return rc;
395 }
396
397 /* 2.If an PE header was found jump to 4. */
398 if (*(PULONG)(pMzHdr) != IMAGE_NT_SIGNATURE)
399 {
400 /* 3.Verify valid MZ header - if not fail. Determin PE offset. */
401 if (pMzHdr->e_magic == IMAGE_DOS_SIGNATURE)
402 {
403 if (pMzHdr->e_lfanew > sizeof(IMAGE_DOS_HEADER) && pMzHdr->e_lfanew < 0x04000000UL) /* Larger than 64 bytes and less that 64MB. */
404 offNtHeaders = pMzHdr->e_lfanew;
405 else
406 rc = ERROR_INVALID_EXE_SIGNATURE;
407 }
408 else
409 rc = ERROR_INVALID_EXE_SIGNATURE;
410 }
411 else
412 offNtHeaders = 0UL;
413
414 free(pMzHdr);
415 pMzHdr = NULL;
416 if (rc != NO_ERROR)
417 {
418 printErr(("Not PE executable.\n"));
419 return rc;
420 }
421
422 /* 4.Read PE headers. */
423 pNtHdrs = (PIMAGE_NT_HEADERS)malloc(sizeof(IMAGE_NT_HEADERS));
424 if (pNtHdrs == NULL)
425 return ERROR_NOT_ENOUGH_MEMORY;
426 rc = ReadAt(hFile, offNtHeaders, pNtHdrs, sizeof(IMAGE_NT_HEADERS));
427 if (rc != NO_ERROR)
428 return rc;
429
430 /* 5.Validate PE header (Magics, Machine, subsystem, characteristics,...) - fail if not valid. */
431 if (pNtHdrs->Signature != IMAGE_NT_SIGNATURE)
432 {
433 printErr(("Invalid PE signature, '%c%c%c%c'\n",
434 ((PCHAR)&pNtHdrs->Signature)[0], ((PCHAR)&pNtHdrs->Signature)[1],
435 ((PCHAR)&pNtHdrs->Signature)[2], ((PCHAR)&pNtHdrs->Signature)[3]));
436 return ERROR_INVALID_EXE_SIGNATURE;
437 }
438 dumpNtHeaders(pNtHdrs);
439 if (pNtHdrs->FileHeader.Machine != IMAGE_FILE_MACHINE_I386)
440 {
441 printErr(("Invalid Machine! %#4x\n", pNtHdrs->FileHeader.Machine));
442 return ERROR_BAD_EXE_FORMAT;
443 }
444 if (!(pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE))
445 {
446 printErr(("Not executable file!\n"));
447 return ERROR_BAD_EXE_FORMAT;
448 }
449 if (pNtHdrs->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
450 {
451 printErr(("Invalid optional header.\n"));
452 return ERROR_BAD_EXE_FORMAT;
453 }
454 if (pNtHdrs->FileHeader.SizeOfOptionalHeader
455 - ((pNtHdrs->OptionalHeader.NumberOfRvaAndSizes - IMAGE_NUMBEROF_DIRECTORY_ENTRIES) * sizeof(IMAGE_DATA_DIRECTORY))
456 != sizeof(IMAGE_OPTIONAL_HEADER))
457 {
458 printErr(("Invalid optional header size.\n"));
459 return ERROR_BAD_EXE_FORMAT;
460 }
461 if (pNtHdrs->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_CUI &&
462 pNtHdrs->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_GUI &&
463 pNtHdrs->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_NATIVE)
464 {
465 printErr(("Subsystem not supported. %d\n", pNtHdrs->OptionalHeader.Subsystem));
466 return ERROR_BAD_EXE_FORMAT;
467 }
468
469 /* 6.Read sectiontable. */
470 paSections = (PIMAGE_SECTION_HEADER)malloc(sizeof(IMAGE_SECTION_HEADER) * pNtHdrs->FileHeader.NumberOfSections);
471 if (paSections == NULL)
472 return ERROR_NOT_ENOUGH_MEMORY;
473 rc = ReadAt(hFile,
474 offNtHeaders + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + pNtHdrs->FileHeader.SizeOfOptionalHeader,
475 paSections,
476 pNtHdrs->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
477 if (rc != NO_ERROR)
478 return rc;
479
480 /* 7.Start converting the sections by adding the headerobject. (headerobject, see previous chapter). */
481 rc = offNtHeaders + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + pNtHdrs->FileHeader.SizeOfOptionalHeader //could we use OptionalHeader.SizeOfHeaders?
482 + pNtHdrs->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
483 rc = addObject(0UL, rc, rc, OBJREAD | OBJBIGDEF, 0UL);
484 if (rc != NO_ERROR)
485 {
486 printErr(("Failed to add header object\n"));
487 return rc;
488 }
489
490 /* 8.Iterate thru the sectiontable converting the section to objects. */
491 for (i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++)
492 {
493 ULONG cbVirt,cbPhys;
494 ULONG flFlags = 0;
495
496 dumpSectionHeader(&paSections[i]);
497
498 /* 8a. Convert characteristics to flags and check/fix incompatible flags! */
499 for (j = 0; j < (sizeof(paSecChars2Flags)/sizeof(paSecChars2Flags[0])); j++)
500 if ((paSections[i].Characteristics & paSecChars2Flags[j].Characteristics) == paSecChars2Flags[j].Characteristics)
501 flFlags |= paSecChars2Flags[j].flFlags;
502 if ((flFlags & (OBJEXEC | OBJWRITE)) == (OBJEXEC | OBJWRITE))
503 flFlags &= (ULONG)~OBJEXEC;
504
505 /* 8b. Virtual/physical size */
506 /* The virtual size and physical size is somewhat problematic. Some linkers sets Misc.VirtualSize and
507 * others don't. Some linkers sets the Misc.VirtualSize to the exact size of data in the section, which
508 * may cause that the VirtualSize to be less than the SizeOfRawData due to file alignment.
509 * We assume/know certain things:
510 * -SizeOfRawData is allways the physical size when PointerToRawData is valid (not 0).
511 * (No matter what Matt Pietrek may have written!) NT maps in the entire physical size.
512 * -The VirtualSize may contain 0, then the virtual size is equal to the Physical size.
513 * -The VirtualSize may be less than the SizeOfRawData.
514 * This means that we can't allways use the VirtualSize as the size of LX objects.
515 */
516 cbPhys = paSections[i].PointerToRawData != 0UL ? paSections[i].SizeOfRawData : 0UL;
517 cbVirt = paSections[i].Misc.VirtualSize > paSections[i].SizeOfRawData ?
518 paSections[i].Misc.VirtualSize : paSections[i].SizeOfRawData;
519
520 /* 8c. Add object. */
521 rc = addObject(paSections[i].VirtualAddress, cbPhys, cbVirt, flFlags, paSections[i].PointerToRawData);
522 if (rc != NO_ERROR)
523 {
524 printErr(("Failed to add object for section no.%d. rc = %d\n", i, rc));
525 return rc;
526 }
527 }
528 free(paSections);
529 paSections = NULL;
530
531 /* 9.Find where the TIB fix is to be placed. (see 3.1.1 for placements.) Place the TIB fix. */
532 if (PAGESIZE - (paObjects[0].cbVirtual & (PAGESIZE-1)) >= SIZEOF_TIBFIX)
533 { /* 9a. At the end of the header object. */
534 paObjects[0].Misc.offTIBFix = paObjects[0].cbVirtual;
535 paObjects[0].Misc.fTIBFixObject = TRUE;
536 paObjects[0].cbVirtual += SIZEOF_TIBFIX;
537 paObjects[0].cbPhysical += SIZEOF_TIBFIX;
538 paObjects[0].flFlags |= OBJEXEC;
539 printInf(("TIBFix code at end of header object. offset=%#x\n", paObjects[0].Misc.offTIBFix));
540 }
541 else if (offNtHeaders >= sizeof(IMAGE_DOS_HEADER) + SIZEOF_TIBFIX)
542 { /* 9b. After MZ-Header (In the dos stub!). */
543 paObjects[0].Misc.offTIBFix = sizeof(IMAGE_DOS_HEADER);
544 paObjects[0].Misc.fTIBFixObject = TRUE;
545 paObjects[0].flFlags |= OBJEXEC;
546 printInf(("TIBFix code in dos stub. offset=%#x\n", paObjects[0].Misc.offTIBFix));
547 }
548 else
549 { /* 9c.Add separate TIBFix object. */
550 printInf(("TIBFix code in separate object.\n"));
551 rc = addTIBFixObject();
552 if (rc != NO_ERROR)
553 {
554 printErr(("Failed to insert TIBFix, rc=%d\n", rc));
555 return rc;
556 }
557 }
558
559 /* 10.Add stack object. */
560 if (!(pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL))
561 {
562 rc = addStackObject(max(pNtHdrs->OptionalHeader.SizeOfStackReserve, MIN_STACK_SIZE));
563 if (rc != NO_ERROR)
564 {
565 printErr(("Failed to insert TIBFix, rc=%d\n", rc));
566 return rc;
567 }
568 }
569
570 /* 11.Align section. (Fix which is applied to EXEs/Dlls which contain no fixups and has an
571 * alignment which is not a multiple of 64Kb. The sections are concatenated into one big object. */
572 /* TODO! this test has to be enhanced a bit. WWPack32, new Borland++ depends on image layout. */
573 fAllInOneObject = !isPEOneObjectDisabled()
574 && ( isPEOneObjectForced()
575 || (pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) == IMAGE_FILE_RELOCS_STRIPPED
576 );
577 if (fAllInOneObject)
578 {
579 printInf(("All-In-One-Object fix is applied.\n"));
580 if (pNtHdrs->OptionalHeader.ImageBase >= 0x04000000UL && !(pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL))
581 printWar(("ImageBase >= 64MB this object may not be runnable! (ImageBase=%#8x)\n",
582 pNtHdrs->OptionalHeader.ImageBase));
583 }
584
585 /* 12.Update the LXHeader with info which is finalized now. (Stacksize, GUI/CUI, characteristics,...) */
586 for (i = 0, j = 1; i < cObjects; i++, j += !fAllInOneObject ? 1 : 0)
587 {
588 if (paObjects[i].Misc.fTIBFixObject)
589 {
590 LXHdr.e32_startobj = j;
591 LXHdr.e32_eip = (fAllInOneObject ? paObjects[i].ulRVA : 0UL) + paObjects[i].Misc.offTIBFix;
592 }
593 else if (paObjects[i].Misc.fStackObject)
594 {
595 LXHdr.e32_stackobj = j;
596 LXHdr.e32_esp = (fAllInOneObject ? paObjects[i].ulRVA : 0UL) + paObjects[i].cbVirtual;
597 LXHdr.e32_stacksize = paObjects[i].cbVirtual;
598 }
599 }
600 ulImageBase = pNtHdrs->OptionalHeader.ImageBase;
601 LXHdr.e32_mflags = pNtHdrs->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI
602 ? E32PMAPI : E32PMW;
603 if (pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL)
604 LXHdr.e32_mflags |= E32LIBINIT | E32LIBTERM | E32MODDLL;
605 else
606 {
607 LXHdr.e32_mflags |= E32MODEXE;
608#if 0
609 if ( pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED /* Force location if possible. */
610 || ulImageBase < 0x04000000 && ulImageBase + pNtHdrs->OptionalHeader.SizeOfImage < 0x04000000)
611 LXHdr.e32_mflags |= E32NOINTFIX;
612#endif
613 }
614
615 /* 13.Convert exports. */
616 rc = makeExports();
617 if (rc != NO_ERROR)
618 {
619 printErr(("Failed to make exports rc=%d\n", rc));
620 return rc;
621 }
622 Yield();
623
624 /* 14.Convert base relocations (fixups). Remember to add the fixup for RegisterPe2LxDll/Exe. */
625 rc = makeFixups();
626 if (rc != NO_ERROR)
627 {
628 printErr(("Failed to make fixups rc=%d\n", rc));
629 return rc;
630 }
631 Yield();
632
633 /* 15.Make object table. */
634 rc = makeObjectTable();
635 if (rc != NO_ERROR)
636 {
637 printErr(("Failed to make object table rc=%d\n", rc));
638 return rc;
639 }
640
641 /* 16.Make object page table. */
642 rc = makeObjectPageTable();
643 if (rc != NO_ERROR)
644 {
645 printErr(("Failed to make object table rc=%d\n", rc));
646 return rc;
647 }
648 Yield();
649
650 /* 17.Completing the LX header. */
651 LXHdr.e32_mpages = getCountOfPages();
652 LXHdr.e32_objcnt = fAllInOneObject ? 1 : cObjects;
653 LXHdr.e32_objmap = LXHdr.e32_objtab + sizeof(struct o32_obj) * LXHdr.e32_objcnt;
654 LXHdr.e32_restab = LXHdr.e32_objmap + LXHdr.e32_mpages * sizeof(struct o32_map);
655 LXHdr.e32_enttab = LXHdr.e32_restab + offCurResName;
656 LXHdr.e32_fpagetab = LXHdr.e32_enttab + offCurEntryBundle;
657 LXHdr.e32_frectab = LXHdr.e32_fpagetab + (LXHdr.e32_mpages + 1) * sizeof(ULONG);
658 LXHdr.e32_impmod = LXHdr.e32_frectab + offCurFixupRec;
659 LXHdr.e32_impproc = LXHdr.e32_impmod + offCurImpModuleName;
660 LXHdr.e32_datapage = LXHdr.e32_impproc + offCurImpFunctionName;
661
662 LXHdr.e32_fixupsize = (LXHdr.e32_mpages + 1) * sizeof(ULONG) /* fixup page table */
663 + offCurFixupRec /* fixup record table */
664 + offCurImpModuleName /* import module name table */
665 + offCurImpFunctionName; /* import procedure name table */
666
667 LXHdr.e32_ldrsize = LXHdr.e32_objcnt * sizeof(struct o32_obj) /* object table */
668 + LXHdr.e32_mpages * sizeof(struct o32_map) /* object page table */
669 + offCurResName /* resident names */
670 + offCurEntryBundle /* entry tables */
671 + (LXHdr.e32_mpages + 1) * sizeof(ULONG) /* fixup page table */
672 + offCurFixupRec /* fixup record table */
673 + offCurImpModuleName /* import module name table */
674 + offCurImpFunctionName; /* import procedure name table */
675
676 /* find import module count */
677 i = 0;
678 LXHdr.e32_impmodcnt = 0;
679 while (i < offCurImpModuleName)
680 {
681 LXHdr.e32_impmodcnt++;
682 /* next */
683 i += pachImpModuleNames[i] + 1;
684 }
685
686 /* 18.Set offLXFile in the object array. */
687 ULONG offObjectData = LXHdr.e32_datapage;
688 for (i = 0; i < cObjects; i++)
689 {
690 if (paObjects[i].cbPhysical > 0UL)
691 {
692 paObjects[i].offLXFile = offObjectData;
693 offObjectData += paObjects[i].cbPhysical;
694 }
695 else
696 paObjects[i].offLXFile = 0UL;
697 }
698
699 /* 19.The conversion method is completed. Object is now usable. */
700 #ifdef DEBUG
701 fInitTime = FALSE;
702 #endif
703 releaseNtHeaders();
704
705 /* 20.Dump virtual LX-file */
706 dumpVirtualLxFile();
707
708 Yield();
709 _res_heapmin();
710 #ifndef RING0
711 #if 1 /* testing */
712 testApplyFixups();
713 #endif
714 #endif
715
716 return NO_ERROR;
717}
718
719
720/**
721 * Read data from the virtual LX-file.
722 * @param offLXFile Offset (into the virtual lx file) of the data to read
723 * @param pvBuffer Pointer to buffer where data is to be put.
724 * @param cbToRead Bytes to be read.
725 * @param fpBuffer Flags which was spesified to the ldrRead call.
726 * @parma pMTE Pointer to MTE which was specified to the ldrRead call.
727 * @return NO_ERROR if successful something else if not.
728 * @status completely implmented; tested.
729 * @author knut st. osmundsen
730 */
731ULONG Pe2Lx::read(ULONG offLXFile, PVOID pvBuffer, ULONG fpBuffer, ULONG cbToRead, PMTE pMTE)
732{
733 APIRET rc = NO_ERROR; /* Return code. */
734 ULONG cbReadVar; /* Number of bytes in a read operation. */
735 ULONG offPEFile; /* Offset into the PE-File of the read operation. */
736
737 /* validate input pointers */
738 if (pvBuffer < (PVOID)0x10000)
739 {
740 printErr(("Invalid parameter, pvBuffer = 0x%08x\n", pvBuffer));
741 return ERROR_INVALID_PARAMETER;
742 }
743 #ifdef DEBUG
744 if (fInitTime)
745 {
746 printErr(("the read method may not be called during init.\n"));
747 return ERROR_INVALID_PARAMETER;
748 }
749 #endif
750
751 printInf(("Pe2Lx::read(%d, 0x%08x, 0x%08x, %d)\n", offLXFile, pvBuffer, fpBuffer, cbToRead));
752
753 /* Could we skip right to the datapages? */
754 if (offLXFile < LXHdr.e32_datapage)
755 { /* -no. */
756 PVOID pv;
757 ULONG cb;
758 ULONG off;
759 ULONG ulIndex = 0;
760 while (ulIndex < 9 && cbToRead > 0UL)
761 {
762 /* ASSUME a given order of tables! (See near bottom of the init() method) */
763 switch (ulIndex)
764 {
765 case 0: /* LXHdr */
766 off = 0UL;
767 cb = sizeof(LXHdr);
768 break;
769 case 1: /* Object Table */
770 off = LXHdr.e32_objtab;
771 cb = sizeof(struct o32_obj) * LXHdr.e32_objcnt;
772 break;
773 case 2: /* Object Page Table */
774 off = LXHdr.e32_objmap;
775 cb = LXHdr.e32_mpages * sizeof(struct o32_map);
776 break;
777 case 3: /* Resident Name Table */
778 off = LXHdr.e32_restab;
779 cb = LXHdr.e32_enttab - off;
780 break;
781 case 4: /* Entry Table */
782 off = LXHdr.e32_enttab;
783 cb = LXHdr.e32_fpagetab - off;
784 break;
785 case 5: /* FixupTable */
786 off = LXHdr.e32_fpagetab;
787 cb = LXHdr.e32_frectab - off;
788 break;
789 case 6: /* Fixup Record Table */
790 off = LXHdr.e32_frectab;
791 cb = LXHdr.e32_impmod - off;
792 break;
793 case 7: /* Import Module Name Table */
794 off = LXHdr.e32_impmod;
795 cb = LXHdr.e32_impproc - off;
796 break;
797 case 8: /* Import Procedure Name Table */
798 off = LXHdr.e32_impproc;
799 cb = LXHdr.e32_datapage - off;
800 break;
801 default: printIPE(("invalid ulIndex. ulIndex = %d\n", ulIndex)); return ERROR_INTERNAL_PROCESSING_ERROR;
802 }
803
804 /* Is it this header part? */
805 if ((ulIndex == 0 || off != 0UL) && cb != 0UL && offLXFile < off + cb)
806 {
807 /* find pointer. */
808 switch (ulIndex)
809 {
810 case 0: /* LXHdr */
811 pv = &LXHdr;
812 break;
813 case 1: /* Object Table */
814 if (paObjTab == NULL)
815 rc = makeObjectTable();
816 pv = paObjTab;
817 break;
818 case 2: /* Object Page Table */
819 if (paObjPageTab == NULL)
820 rc = makeObjectPageTable();
821 pv = paObjPageTab;
822 break;
823 case 3: /* Resident Name Table */
824 if (pachResNameTable == NULL)
825 {
826 rc = makeExports();
827 releaseNtHeaders();
828 finalizeImportNames();
829 }
830 pv = pachResNameTable;
831 break;
832 case 4: /* Entry Table */
833 if (pEntryBundles == NULL)
834 {
835 rc = makeExports();
836 releaseNtHeaders();
837 finalizeImportNames();
838 }
839 pv = pEntryBundles;
840 break;
841 case 5: /* FixupTable */
842 if (paulFixupPageTable == NULL)
843 {
844 rc = makeFixups();
845 releaseNtHeaders();
846 }
847 pv = paulFixupPageTable;
848 break;
849 case 6: /* Fixup Record Table */
850 if (pFixupRecords == NULL)
851 {
852 rc = makeFixups();
853 releaseNtHeaders();
854 }
855 pv = pFixupRecords;
856 break;
857 case 7: /* Import Module Name Table */
858 if (pachImpModuleNames == NULL)
859 {
860 rc = makeFixups();
861 releaseNtHeaders();
862 }
863 pv = pachImpModuleNames;
864 break;
865 case 8: /* Import Procedure Name Table */
866 if (pachImpFunctionNames == NULL)
867 {
868 rc = makeFixups();
869 releaseNtHeaders();
870 }
871 pv = pachImpFunctionNames;
872 break;
873 default: printIPE(("invalid ulIndex. ulIndex = %d\n", ulIndex)); return ERROR_INTERNAL_PROCESSING_ERROR;
874 }
875
876 /* check if any operation has failed */
877 if (rc != NO_ERROR)
878 {
879 printErr(("A makeXxxxx operation failed with rc=%d, ulIndex=%d.\n", rc, ulIndex));
880 return ERROR_READ_FAULT;
881 }
882
883 /* verify that offLXfile is greater or equal to off. */
884 if (offLXFile < off)
885 {
886 printIPE(("offLXFile (%d) < off(%d)!\n", offLXFile, off));
887 return ERROR_READ_FAULT;
888 }
889
890 /* do the actual "read" operation. */
891 cbReadVar = cb - (offLXFile - off); /* left of this header part. */
892 cbReadVar = min(cbReadVar, cbToRead);
893 memcpy(pvBuffer, (PVOID)((ULONG)pv + (offLXFile - off)), (size_t)cbReadVar);
894
895 /* Could this header part be freed now? */
896 if (cbReadVar + (offLXFile - off) == cb) /* have read to end of this header part. */
897 {
898 switch (ulIndex)
899 {
900 case 0: /* LXHdr - ignore */
901 break;
902 case 1: /* Object Table */
903 free(paObjTab);
904 paObjTab = NULL;
905 break;
906 case 2: /* Object Page Table */
907 free(paObjPageTab);
908 paObjPageTab = NULL;
909 break;
910 case 3: /* Resident Name Table */
911 free(pachResNameTable);
912 pachResNameTable = NULL;
913 cchRNTAllocated = offCurResName = 0UL;
914 break;
915 case 4: /* Entry Table */
916 free(pEntryBundles);
917 pEntryBundles = NULL;
918 offCurEntryBundle = offLastEntryBundle = ulLastOrdinal = cbEBAllocated = 0UL;
919 break;
920 case 5: /* FixupTable */
921 free(paulFixupPageTable);
922 paulFixupPageTable = NULL;
923 cFixupPTEntries = cFPTEAllocated = 0UL;
924 break;
925 case 6: /* Fixup Record Table */
926 free(pFixupRecords);
927 pFixupRecords = NULL;
928 offCurFixupRec = cbFRAllocated = 0UL;
929 break;
930 case 7: /* Import Module Name Table */
931 free(pachImpModuleNames);
932 pachImpModuleNames = NULL;
933 offCurImpModuleName = cchIMNAllocated = 0UL;
934 break;
935 case 8: /* Import Procedure Name Table */
936 free(pachImpFunctionNames);
937 pachImpFunctionNames = NULL;
938 offCurImpFunctionName = cchIFNAllocated = 0UL;
939 break;
940 default: printIPE(("invalid ulIndex. ulIndex = %d\n", ulIndex)); return ERROR_INTERNAL_PROCESSING_ERROR;
941 }
942 }
943
944 /* next */
945 cbToRead -= cbReadVar;
946 offLXFile += cbReadVar;
947 pvBuffer = (PVOID)((ULONG)pvBuffer + cbReadVar);
948
949 } /* read it */
950
951 /* next */
952 ulIndex++;
953 } /* while loop */
954 }
955
956
957 /*
958 * data within the objects?
959 */
960 ULONG iObj = 0UL;
961 while (cbToRead > 0UL && rc == NO_ERROR)
962 {
963 /* find object with requested data */
964 while (iObj < cObjects && offLXFile >= paObjects[iObj].offLXFile + paObjects[iObj].cbPhysical)
965 iObj++;
966 if (iObj >= cObjects)
967 { /* data not found... */
968 if (cbReadVar > 0UL)
969 printWar(("Read request crossing end of file.\n"));
970 else
971 printErr(("Read request after end of file.\n"));
972 rc = ERROR_NO_DATA; /*??*/
973 break;
974 }
975
976 /* calc offsets */
977 ULONG offObject = offLXFile - paObjects[iObj].offLXFile;
978 offPEFile = offObject + paObjects[iObj].offPEFile;
979
980 /* TIBFix object? */
981 if (!paObjects[iObj].Misc.fTIBFixObject
982 || paObjects[iObj].Misc.offTIBFix + (ULONG)SIZEOF_TIBFIX <= offObject)
983 { /* not TIB object OR after the TIBFix code */
984 /* calc PE offset and size of read. */
985 cbReadVar = min(paObjects[iObj].cbPhysical - offObject, cbToRead);
986 rc = ReadAtF(hFile, offPEFile, pvBuffer, fpBuffer, cbReadVar, pMTE);
987 }
988 else
989 { /* before or in the TIBFix code. */
990 if (offObject < paObjects[iObj].Misc.offTIBFix)
991 { /* before TIBFix code. */
992 cbReadVar = min(paObjects[iObj].Misc.offTIBFix - offObject, cbToRead);
993 rc = ReadAtF(hFile, offPEFile, pvBuffer, fpBuffer, cbReadVar, pMTE);
994 }
995 else
996 { /* TIBFix code.*/
997 offObject -= paObjects[iObj].Misc.offTIBFix; /* now offset into the TIBFix. */
998 cbReadVar = min(SIZEOF_TIBFIX - offObject, cbToRead);
999 memcpy(pvBuffer, &achTIBFix[offObject], (size_t)cbReadVar);
1000 }
1001 }
1002
1003 if (rc == NO_ERROR)
1004 { /* success - update variables */
1005 cbToRead -= cbReadVar;
1006 offLXFile += cbReadVar;
1007 pvBuffer = (PVOID)((ULONG)pvBuffer + cbReadVar);
1008 }
1009 else
1010 printErr(("Read operation failed with rc=%d, offPEFile=0x%x, cbReadVar=%d, iObj=%d\n",
1011 rc, offPEFile, cbReadVar, iObj));
1012 }
1013
1014 NOREF(fpBuffer);
1015 NOREF(pMTE);
1016 return rc;
1017}
1018
1019
1020/**
1021 * Applies relocation fixups to a page which is being loaded.
1022 * @returns NO_ERROR on success?
1023 * error code on error?
1024 * @param pMTE Pointer Module Table Entry.
1025 * @param iObject Index into the object table. (0-based)
1026 * @param iPageTable Index into the page table. (0-based)
1027 * @param pvPage Pointer to the page which is being loaded.
1028 * @param ulPageAddress Address of page.
1029 * @param pvPTDA Pointer to Per Task Data Aera
1030 *
1031 * @sketch Find RVA.
1032 * @remarks Some more information on relocations:
1033 * From Web:
1034 * IMAGE_REL_I386_ABSOLUTE Reference is absolute, no relocation is necessary
1035 * IMAGE_REL_I386_DIR16 Direct 16-bit reference to the symbols virtual address
1036 * IMAGE_REL_I386_REL16 PC-relative 16-bit reference to the symbols virtual address
1037 * IMAGE_REL_I386_DIR32 Direct 32-bit reference to the symbols virtual address
1038 * IMAGE_REL_I386_DIR32NB Direct 32-bit reference to the symbols virtual address, base not included
1039 * IMAGE_REL_I386_SEG12 Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address
1040 * IMAGE_REL_I386_SECTION ?
1041 * IMAGE_REL_I386_SECREL ?
1042 * IMAGE_REL_I386_REL32 PC-relative 32-bit reference to the symbols virtual address
1043 *
1044 * From TIS:
1045 * Type = 4­bit fixup type. This value has the following definitions:
1046 * 0h Absolute. This is a NOP. The fixup is skipped.
1047 * 1h High. Add the high 16 bits of the delta to the 16 bit field at Offset.
1048 * The 16bit field represents the high value of a 32 bit word.
1049 * 2h Low. Add the low 16 bits of the delta to the 16 bit field at Offset.
1050 * The 16 bit field represents the low half value of a 32 bit word. This
1051 * fixup will only be emitted for a RISC machine when the image Object
1052 * Align isn't the default of 64K.
1053 * 3h Highlow. Apply the 32 bit delta to the 32 bit field at Offset.
1054 * 4h Highadjust. This fixup requires a full 32 bit value. The high 16 bits
1055 * is located at Offset, and the low 16 bits is located in the next Offset
1056 * array element (this array element is included in the Size field). The
1057 * two need to be combined into a signed variable. Add the 32 bit delta.
1058 * Then add 0x8000 and store the high 16 bits of the signed variable to
1059 * the 16 bit field at Offset.
1060 * 5h ­ Mipsjmpaddr.
1061 *
1062 * TODO: implement the above mentioned fixups.
1063 */
1064ULONG Pe2Lx::applyFixups(PMTE pMTE, ULONG iObject, ULONG iPageTable, PVOID pvPage,
1065 ULONG ulPageAddress, PVOID pvPTDA)
1066{
1067 APIRET rc;
1068
1069 if (fApplyFixups != FALSE && pBaseRelocs != NULL)
1070 {
1071 ULONG ulRVAPage;
1072 ULONG ulDelta;
1073 PSMTE pSMTE = pMTE->mte_swapmte;
1074
1075 /* validate input */
1076 if (pSMTE < (PSMTE)0x10000)
1077 {
1078 printErr(("Invalid pSMTE(0x%08x)\n", pSMTE));
1079 return ERROR_INVALID_PARAMETER;
1080 }
1081 #ifdef DEBUG
1082 if (pSMTE->smte_objcnt <= iObject)
1083 {
1084 printErr(("Invalid iObject(%d), smte_objcnt=%d\n", iObject, pSMTE->smte_objcnt));
1085 return ERROR_INVALID_PARAMETER;
1086 }
1087 if (cObjects <= iObject)
1088 {
1089 printErr(("Invalid iObject(%d), cObjects=%d\n", iObject, cObjects));
1090 return ERROR_INVALID_PARAMETER;
1091 }
1092 #endif
1093
1094 /* some calculations */
1095 ulDelta = pSMTE->smte_objtab[iObject].ote_base - paObjects[iObject].ulRVA - ulImageBase;
1096 ulRVAPage = paObjects[iObject].ulRVA + ulPageAddress - pSMTE->smte_objtab[iObject].ote_base;
1097
1098 /* check if the fixup needs to be applied? */
1099 if (fApplyFixups == ~0UL)
1100 {
1101 fDeltaOnly = TRUE; /* IMPORTANT: Later code assumes that this is true when fAllInOneObject is true. */
1102 if (fAllInOneObject)
1103 fApplyFixups = ulImageBase != pSMTE->smte_objtab[0].ote_base;
1104 else
1105 {
1106 int i = 0;
1107 #ifdef DEBUG
1108 if (cObjects != pSMTE->smte_objcnt)
1109 printErr(("cObjects(%d) != smte_objcnt(%d)\n", cObjects, pSMTE->smte_objcnt));
1110 #endif
1111 fApplyFixups = FALSE;
1112 while (i < cObjects && (!fApplyFixups || fDeltaOnly))
1113 {
1114 register ULONG ulTmp = pSMTE->smte_objtab[i].ote_base - ulImageBase - paObjects[i].ulRVA;
1115 if (ulTmp != 0)
1116 fApplyFixups = TRUE;
1117 if (ulTmp != ulDelta)
1118 fDeltaOnly = FALSE;
1119 i++;
1120 }
1121 }
1122 if (!fApplyFixups)
1123 return NO_ERROR;
1124 }
1125
1126 if (fDeltaOnly)
1127 return applyFixupsDelta(pvPage, ulDelta, ulRVAPage);
1128
1129 /*
1130 * Iterate thru the fixup chunks until we find one or two with fixups valid for
1131 * this page. I say one or two since we might have cross page fixups from the previous page
1132 * So, we'll have to start working at the previous page.
1133 * ASSUME: -fixups are sorted ascendingly on page RVA. only one chunk per page.
1134 * -only one cross page fixup at each end which doesn't overlapp with other fixups.
1135 */
1136 PIMAGE_BASE_RELOCATION pbr = pBaseRelocs;
1137
1138 while ((unsigned)pbr - (unsigned)pBaseRelocs + 8 < cbBaseRelocs /* 8= VirtualAddress and SizeOfBlock members */
1139 && pbr->SizeOfBlock >= 8
1140 && pbr->VirtualAddress < ulRVAPage + PAGESIZE)
1141 {
1142
1143 if (pbr->VirtualAddress + PAGESIZE >= ulRVAPage)
1144 {
1145 PWORD pwoffFixup = &pbr->TypeOffset[0];
1146 ULONG cRelocations = (pbr->SizeOfBlock - offsetof(IMAGE_BASE_RELOCATION, TypeOffset)) / sizeof(WORD); /* note that sizeof(BaseReloc) is 12 bytes! */
1147
1148 /* Some bound checking just to be sure it works... */
1149 if ((unsigned)pbr - (unsigned)pBaseRelocs + pbr->SizeOfBlock > cbBaseRelocs)
1150 {
1151 printWar(("Block ends after BaseRelocation datadirectory.\n"));
1152 cRelocations = (((unsigned)pBaseRelocs + cbBaseRelocs) - (unsigned)pbr - offsetof(IMAGE_BASE_RELOCATION, TypeOffset)) / sizeof(WORD);
1153 }
1154
1155
1156 /*
1157 * skip to near end of previous page to save time
1158 * I just don't dare to skip to the second last offset,
1159 * 7 offsets from the end sounds nice and secure.
1160 */
1161 if (pbr->VirtualAddress < ulRVAPage && cRelocations > 7)
1162 {
1163 pwoffFixup += cRelocations - 7; /* */
1164 cRelocations = 7;
1165 }
1166
1167
1168 /*
1169 * Loop thru the fixups in this chunk.
1170 */
1171 while (cRelocations != 0)
1172 {
1173 /*
1174 * Fixup size table. 0xFF for fixups which aren't supported
1175 * or is just non-sense.
1176 */
1177 #define CBFIXUPMAX 4
1178 static char acbFixupTypes[16] = {0xFF, 0x02, 0x02, 0x04,
1179 0xFF, 0xFF, 0xFF, 0xFF,
1180 0xFF, 0xFF, 0xFF, 0xFF,
1181 0xFF, 0xFF, 0xFF, 0xFF};
1182 int offFixup = *pwoffFixup & (int)(PAGESIZE-1);
1183 int fType = *pwoffFixup >> 12;
1184 int cbFixup = acbFixupTypes[fType];
1185
1186 if (cbFixup <= CBFIXUPMAX
1187 && offFixup + pbr->VirtualAddress + (cbFixup-1) >= ulRVAPage
1188 && offFixup + pbr->VirtualAddress < ulRVAPage + PAGESIZE
1189 )
1190 {
1191 ULONG iObj;
1192 ULONG ulTarget;
1193 ULONG ul; /* Crosspage fixups: Content of fixup target */
1194
1195 if (offFixup + pbr->VirtualAddress < ulRVAPage)
1196 { /*
1197 * Crosspagefixup - from the page before
1198 * Start by reading the bytes on the previous page. We have to in case
1199 * of carray.
1200 */
1201 //printInf(("Crosspagefixup at offset=%d type=%d\n", offFixup - PAGESIZE, fType));
1202 printf("Crosspagefixup at offset=%d type=%d\n", offFixup - PAGESIZE, fType);
1203 rc = readAtRVA(ulRVAPage + offFixup - PAGESIZE, SSToDS(&ul), sizeof(ul));
1204 if (rc != NO_ERROR)
1205 {
1206 printErr(("readAtRVA(0x%08x, ul(Before)..) failed with rc=%d\n", ulRVAPage + offFixup - PAGESIZE, rc));
1207 return rc;
1208 }
1209
1210 /*
1211 * If none-delta and highlow fixup try resolve target address.
1212 * Falls back on delta fixup. We have to do this because of
1213 * object alignment problems.
1214 */
1215 iObj = ~0UL;
1216 if (!fDeltaOnly && fType == IMAGE_REL_BASED_HIGHLOW)
1217 {
1218 /* Get target pointer, find it's object and apply the fixup */
1219 ulTarget = ul - ulImageBase; /* ulTarget is now an RVA */
1220 iObj = 0UL;
1221 while (iObj < cObjects
1222 && ulTarget >= (iObj + 1 < cObjects ? paObjects[iObj+1].ulRVA
1223 : ALIGN(paObjects[iObj].cbVirtual, PAGESIZE) + paObjects[iObj].ulRVA)
1224 )
1225 iObj++;
1226 if (iObj < cObjects)
1227 ul = pSMTE->smte_objtab[iObj].ote_base + ulTarget - paObjects[iObj].ulRVA;
1228 }
1229
1230 /*
1231 * Apply delta fixup.
1232 */
1233 if (iObj >= cObjects)
1234 {
1235 switch (fType)
1236 {
1237 case IMAGE_REL_BASED_LOW:
1238 case IMAGE_REL_BASED_HIGHLOW:
1239 ul += ulDelta;
1240 break;
1241 case IMAGE_REL_BASED_HIGH:
1242 case IMAGE_REL_BASED_HIGHADJ: /* According to M$ docs these seems to be the same fixups. */
1243 case IMAGE_REL_BASED_HIGH3ADJ:
1244 ul += ulDelta >> 16;
1245 break;
1246 case IMAGE_REL_BASED_ABSOLUTE:
1247 break;
1248 default:
1249 printErr(("Unknown fixup type %d offset=%0x%08x\n", fType, offFixup));
1250 }
1251 }
1252
1253 /*
1254 * Copy the needed fixup data from ul to the page.
1255 */
1256 if (cbFixup <= CBFIXUPMAX)
1257 memcpy(pvPage, (char*)SSToDS(&ul) + PAGESIZE - offFixup, (size_t)(cbFixup - PAGESIZE + offFixup));
1258 }
1259 else if (offFixup + pbr->VirtualAddress + cbFixup > ulRVAPage + PAGESIZE)
1260 { /*
1261 * Crosspagefixup - into the page afterwards
1262 */
1263 printInf(("Crosspagefixup at offset=%d type=%d\n", PAGESIZE-offFixup, fType));
1264
1265 /*
1266 * If none-delta and highlow fixup then read the full 4 bytes so we can
1267 * resolve the target address and fix it.
1268 * If we fail to fix it we'll fall back on delta fixup.
1269 */
1270 iObj = ~0UL;
1271 if (!fDeltaOnly && fType == IMAGE_REL_BASED_HIGHLOW)
1272 {
1273 rc = readAtRVA(ulRVAPage + offFixup, SSToDS(&ul), sizeof(ul));
1274 if (rc != NO_ERROR)
1275 {
1276 printErr(("readAtRVA(0x%08x, ul(After)..) failed with rc=%d\n", ulRVAPage+offFixup, rc));
1277 return rc;
1278 }
1279
1280 /* Get target pointer, find it's object and apply the fixup */
1281 ulTarget = ul - ulImageBase; /* ulTarget is now an RVA */
1282 iObj = 0UL;
1283 while (iObj < cObjects
1284 && ulTarget >= (iObj + 1 < cObjects ? paObjects[iObj+1].ulRVA
1285 : ALIGN(paObjects[iObj].cbVirtual, PAGESIZE) + paObjects[iObj].ulRVA)
1286 )
1287 iObj++;
1288 if (iObj < cObjects)
1289 ul = pSMTE->smte_objtab[iObj].ote_base + ulTarget - paObjects[iObj].ulRVA;
1290 }
1291
1292 /*
1293 * Apply delta fixup.
1294 */
1295 if (iObj >= cObjects)
1296 {
1297 ul = 0;
1298 memcpy(SSToDS(&ul), (char*)pvPage + offFixup, (size_t)(PAGESIZE - offFixup));
1299 switch (fType)
1300 {
1301 case IMAGE_REL_BASED_LOW:
1302 case IMAGE_REL_BASED_HIGHLOW:
1303 ul += ulDelta;
1304 break;
1305 case IMAGE_REL_BASED_HIGH:
1306 case IMAGE_REL_BASED_HIGHADJ: /* According to M$ docs these seems to be the same fixups. */
1307 case IMAGE_REL_BASED_HIGH3ADJ:
1308 ul += ulDelta >> 8;
1309 break;
1310 case IMAGE_REL_BASED_ABSOLUTE:
1311 break;
1312 default:
1313 printErr(("Unknown fixup type %d offset=%0x%08x\n", fType, offFixup));
1314 }
1315 }
1316
1317 /*
1318 * Copy the needed fixup data from ul to the page.
1319 */
1320 if (cbFixup <= CBFIXUPMAX)
1321 memcpy((char*)pvPage + offFixup, (char*)SSToDS(&ul), (size_t)(PAGESIZE - offFixup));
1322 }
1323 else
1324 { /*
1325 * Common fixup
1326 */
1327 PULONG pul; /* Pointer to fixup target */
1328 pul = (PULONG)((unsigned)pvPage + offFixup + pbr->VirtualAddress - ulRVAPage);
1329 switch (fType)
1330 {
1331 case IMAGE_REL_BASED_HIGHLOW:
1332 printInfA(("IMAGE_REL_BASED_HIGHLOW offset=0x%08x\n", offFixup));
1333 if (fDeltaOnly)
1334 *pul += ulDelta;
1335 else
1336 {
1337 ulTarget = *pul - ulImageBase; /* ulTarget is now an RVA */
1338 iObj = 0UL;
1339 while (iObj < cObjects
1340 && ulTarget >= (iObj + 1 < cObjects ? paObjects[iObj+1].ulRVA
1341 : ALIGN(paObjects[iObj].cbVirtual, PAGESIZE) + paObjects[iObj].ulRVA)
1342 )
1343 iObj++;
1344 if (iObj < cObjects)
1345 *pul = pSMTE->smte_objtab[iObj].ote_base + ulTarget - paObjects[iObj].ulRVA;
1346 else
1347 *pul += ulDelta;
1348 }
1349 break;
1350
1351 /* Placeholder. */
1352 case IMAGE_REL_BASED_ABSOLUTE:
1353 break;
1354
1355 /* Will probably not work very well until the 64KB object alignment is gone! */
1356 case IMAGE_REL_BASED_HIGH:
1357 case IMAGE_REL_BASED_HIGHADJ: /* According to M$ docs these seems to be the same fixups. */
1358 case IMAGE_REL_BASED_HIGH3ADJ:
1359 printInfA(("IMAGE_REL_BASED_HIGH offset=0x%08x\n", offFixup));
1360 *(PUSHORT)pul += (USHORT)(ulDelta >> 16);
1361 break;
1362 /* Will probably not work very well until the 64KB object alignment is gone! */
1363 case IMAGE_REL_BASED_LOW:
1364 printInfA(("IMAGE_REL_BASED_LOW offset=0x%08x\n", offFixup));
1365 *(PUSHORT)pul += (USHORT)ulDelta;
1366 break;
1367 default:
1368 printErr(("Unknown fixup type %d offset=%0x%08x\n", fType, offFixup));
1369 }
1370 }
1371 }
1372
1373 /*
1374 * Next offset/type
1375 */
1376 pwoffFixup++;
1377 cRelocations--;
1378 } /* while loop */
1379
1380 } /* else: not touching this page */
1381
1382 /*
1383 * Next Fixup chunk. (i.e. next page)
1384 */
1385 pbr = (PIMAGE_BASE_RELOCATION)((unsigned)pbr + pbr->SizeOfBlock);
1386 } /* while loop */
1387 } /* else: don't need to apply fixups */
1388 NOREF(iPageTable);
1389 NOREF(pvPTDA);
1390
1391 return NO_ERROR;
1392}
1393
1394
1395/**
1396 * applyFixups worker used when only deltas are to be applied.
1397 */
1398ULONG Pe2Lx::applyFixupsDelta(PVOID pvPage, ULONG ulDelta, ULONG ulRVAPage)
1399{
1400 /*
1401 * Iterate thru the fixup chunks until we find one or two with fixups valid for
1402 * this page. I say one or two since we might have cross page fixups from the previous page
1403 * So, we'll have to start working at the previous page.
1404 * ASSUME: -fixups are sorted ascendingly on page RVA. only one chunk per page.
1405 * -only one cross page fixup at each end which doesn't overlapp with other fixups.
1406 */
1407 PIMAGE_BASE_RELOCATION pbr = pBaseRelocs;
1408
1409 while ((unsigned)pbr - (unsigned)pBaseRelocs + 8 < cbBaseRelocs /* 8= VirtualAddress and SizeOfBlock members */
1410 && pbr->SizeOfBlock >= 8
1411 && pbr->VirtualAddress < ulRVAPage + PAGESIZE)
1412 {
1413
1414 if (pbr->VirtualAddress + PAGESIZE >= ulRVAPage)
1415 {
1416 PWORD pwoffFixup = &pbr->TypeOffset[0];
1417 ULONG cRelocations = (pbr->SizeOfBlock - offsetof(IMAGE_BASE_RELOCATION, TypeOffset)) / sizeof(WORD); /* note that sizeof(BaseReloc) is 12 bytes! */
1418
1419 /* Some bound checking just to be sure it works... */
1420 if ((unsigned)pbr - (unsigned)pBaseRelocs + pbr->SizeOfBlock > cbBaseRelocs)
1421 {
1422 printWar(("Block ends after BaseRelocation datadirectory.\n"));
1423 cRelocations = (((unsigned)pBaseRelocs + cbBaseRelocs) - (unsigned)pbr - offsetof(IMAGE_BASE_RELOCATION, TypeOffset)) / sizeof(WORD);
1424 }
1425
1426
1427 /*
1428 * skip to near end of previous page to save time
1429 * I just don't dare to skip to the second last offset,
1430 * 7 offsets from the end sounds nice and secure.
1431 */
1432 if (pbr->VirtualAddress < ulRVAPage && cRelocations > 7)
1433 {
1434 pwoffFixup += cRelocations - 7; /* */
1435 cRelocations = 7;
1436 }
1437
1438
1439 /*
1440 * Loop thru the fixups in this chunk.
1441 */
1442 while (cRelocations != 0)
1443 {
1444 /*
1445 * Fixup size table. 0xFF for fixups which aren't supported
1446 * or is just non-sense.
1447 */
1448 #define CBFIXUPMAX 4
1449 static char acbFixupTypes[16] = {0xFF, 0x02, 0x02, 0x04,
1450 0xFF, 0xFF, 0xFF, 0xFF,
1451 0xFF, 0xFF, 0xFF, 0xFF,
1452 0xFF, 0xFF, 0xFF, 0xFF};
1453 int offFixup = *pwoffFixup & (int)(PAGESIZE-1);
1454 int fType = *pwoffFixup >> 12;
1455 int cbFixup = acbFixupTypes[fType];
1456
1457 if (cbFixup <= CBFIXUPMAX
1458 && offFixup + pbr->VirtualAddress + (cbFixup-1) >= ulRVAPage
1459 && offFixup + pbr->VirtualAddress < ulRVAPage + PAGESIZE
1460 )
1461 {
1462 ULONG ul; /* Crosspage fixups: Content of fixup target */
1463
1464 if (offFixup + pbr->VirtualAddress < ulRVAPage)
1465 { /*
1466 * Crosspagefixup - from the page before
1467 * Start by reading the bytes on the previous page. We have to in case
1468 * of carray.
1469 */
1470 printInf(("Crosspagefixup at offset=%d type=%d\n", offFixup - PAGESIZE, fType));
1471 APIRET rc = readAtRVA(ulRVAPage + offFixup - PAGESIZE, SSToDS(&ul), sizeof(ul));
1472 if (rc != NO_ERROR)
1473 {
1474 printErr(("readAtRVA(0x%08x, ul(Before)..) failed with rc=%d\n", ulRVAPage + offFixup - PAGESIZE, rc));
1475 return rc;
1476 }
1477
1478 /*
1479 * Apply delta fixup.
1480 */
1481 switch (fType)
1482 {
1483 case IMAGE_REL_BASED_LOW:
1484 case IMAGE_REL_BASED_HIGHLOW:
1485 ul += ulDelta;
1486 break;
1487 case IMAGE_REL_BASED_HIGH:
1488 case IMAGE_REL_BASED_HIGHADJ: /* According to M$ docs these seems to be the same fixups. */
1489 case IMAGE_REL_BASED_HIGH3ADJ:
1490 ul += ulDelta >> 16;
1491 break;
1492 case IMAGE_REL_BASED_ABSOLUTE:
1493 break;
1494 default:
1495 printErr(("Unknown fixup type %d offset=%0x%08x\n", fType, offFixup));
1496 }
1497
1498 /*
1499 * Copy the needed fixup data from ul to the page.
1500 */
1501 if (cbFixup <= CBFIXUPMAX)
1502 memcpy(pvPage, (char*)SSToDS(&ul) + PAGESIZE - offFixup, (size_t)(cbFixup - PAGESIZE + offFixup));
1503 }
1504 else if (offFixup + pbr->VirtualAddress + cbFixup > ulRVAPage + PAGESIZE)
1505 { /*
1506 * Crosspagefixup - into the page afterwards
1507 */
1508 printInf(("Crosspagefixup at offset=%d type=%d\n", PAGESIZE-offFixup, fType));
1509
1510 /*
1511 * Apply delta fixup.
1512 */
1513 ul = 0;
1514 memcpy(SSToDS(&ul), (char*)pvPage + offFixup, (size_t)(PAGESIZE - offFixup));
1515 switch (fType)
1516 {
1517 case IMAGE_REL_BASED_LOW:
1518 case IMAGE_REL_BASED_HIGHLOW:
1519 ul += ulDelta;
1520 break;
1521 case IMAGE_REL_BASED_HIGH:
1522 case IMAGE_REL_BASED_HIGHADJ: /* According to M$ docs these seems to be the same fixups. */
1523 case IMAGE_REL_BASED_HIGH3ADJ:
1524 ul += ulDelta >> 8;
1525 break;
1526 case IMAGE_REL_BASED_ABSOLUTE:
1527 break;
1528 default:
1529 printErr(("Unknown fixup type %d offset=%0x%08x\n", fType, offFixup));
1530 }
1531
1532 /*
1533 * Copy the needed fixup data from ul to the page.
1534 */
1535 if (cbFixup <= CBFIXUPMAX)
1536 memcpy((char*)pvPage + offFixup, (char*)SSToDS(&ul), (size_t)(PAGESIZE - offFixup));
1537 }
1538 else
1539 { /*
1540 * Common fixup
1541 */
1542 PULONG pul; /* Pointer to fixup target */
1543 pul = (PULONG)((unsigned)pvPage + offFixup + pbr->VirtualAddress - ulRVAPage);
1544 switch (fType)
1545 {
1546 case IMAGE_REL_BASED_HIGHLOW:
1547 printInfA(("IMAGE_REL_BASED_HIGHLOW offset=0x%08x\n", offFixup));
1548 *pul += ulDelta;
1549 break;
1550 /* Placeholder. */
1551 case IMAGE_REL_BASED_ABSOLUTE:
1552 break;
1553 /* Will probably not work very well until the 64KB object alignment is gone! */
1554 case IMAGE_REL_BASED_HIGH:
1555 case IMAGE_REL_BASED_HIGHADJ: /* According to M$ docs these seems to be the same fixups. */
1556 case IMAGE_REL_BASED_HIGH3ADJ:
1557 printInfA(("IMAGE_REL_BASED_HIGH offset=0x%08x\n", offFixup));
1558 *(PUSHORT)pul += (USHORT)(ulDelta >> 16);
1559 break;
1560 /* Will probably not work very well until the 64KB object alignment is gone! */
1561 case IMAGE_REL_BASED_LOW:
1562 printInfA(("IMAGE_REL_BASED_LOW offset=0x%08x\n", offFixup));
1563 *(PUSHORT)pul += (USHORT)ulDelta;
1564 break;
1565 default:
1566 printErr(("Unknown fixup type %d offset=%0x%08x\n", fType, offFixup));
1567 }
1568 }
1569 }
1570
1571 /*
1572 * Next offset/type
1573 */
1574 pwoffFixup++;
1575 cRelocations--;
1576 } /* while loop */
1577
1578 } /* else: not touching this page */
1579
1580 /*
1581 * Next Fixup chunk. (i.e. next page)
1582 */
1583 pbr = (PIMAGE_BASE_RELOCATION)((unsigned)pbr + pbr->SizeOfBlock);
1584 } /* while loop */
1585
1586 return NO_ERROR;
1587}
1588
1589/**
1590 * openPath - opens file eventually searching loader specific paths.
1591 * This method is only called for DLLs. (DosLoadModule and Imports.)
1592 *
1593 *
1594 * @returns OS2 return code.
1595 * pLdrLv->lv_sfn is set to filename handle.
1596 * @param pachFilename Pointer to filename. Not zero terminated!
1597 * @param cchFilename Filename length.
1598 * @param pLdrLv Loader local variables? (Struct from KERNEL.SDF)
1599 * @param pful Pointer to flags which are passed on to ldrOpen.
1600 * @sketch
1601 * This is roughly what the original ldrOpenPath does:
1602 * if !CLASS_GLOBAL or miniifs then
1603 * ldrOpen(pachModName)
1604 * else
1605 * loop until no more libpath elements
1606 * get next libpath element and add it to the modname.
1607 * try open the modname
1608 * if successfull then break the loop.
1609 * endloop
1610 * endif
1611 */
1612ULONG Pe2Lx::openPath(PCHAR pachFilename, USHORT cchFilename, ldrlv_t *pLdrLv, PULONG pful, ULONG lLibPath) /* (ldrOpenPath) */
1613{
1614 #ifdef RING0
1615
1616 /*
1617 * Mark the SFN invalid in the case of error.
1618 * Initiate the Odin32 Path static variable and call worker.
1619 */
1620 #ifdef DEBUG
1621 APIRET rc;
1622 //kprintf(("pe2lx::openPath(%.*s, %d, %x, %x, %x)\n",
1623 // cchFilename, pachFilename, cchFilename, pLdrLv, pful, lLibPath));
1624 rc = openPath2(pachFilename, cchFilename, pLdrLv, pful, lLibPath, initOdin32Path());
1625 //kprintf(("pe2lx::openPath rc=%d\n", rc));
1626 return rc;
1627 #else
1628 return openPath2(pachFilename, cchFilename, pLdrLv, pful, lLibPath, initOdin32Path());
1629 #endif
1630
1631 #else
1632 NOREF(pachFilename);
1633 NOREF(cchFilename);
1634 NOREF(pLdrLv);
1635 NOREF(pful);
1636 NOREF(lLibPath);
1637 return ERROR_NOT_SUPPORTED;
1638 #endif
1639}
1640
1641
1642/**
1643 * openPath2 - Worker for openPath which is also used by initOdin32Path.
1644 *
1645 * @returns OS2 return code.
1646 * pLdrLv->lv_sfn is set to filename handle.
1647 * @param pachFilename Pointer to filename. Not zero terminated!
1648 * @param cchFilename Filename length.
1649 * @param pLdrLv Loader local variables? (Struct from KERNEL.SDF)
1650 * @param pful Pointer to flags which are passed on to ldrOpen.
1651 * @param fOdin32PathValid Flag indicating that the pszOdin32Path is valid or not.
1652 * @sketch
1653 * This is roughly what the original ldrOpenPath does:
1654 * if !CLASS_GLOBAL or miniifs then
1655 * ldrOpen(pachModName)
1656 * else
1657 * loop until no more libpath elements
1658 * get next libpath element and add it to the modname.
1659 * try open the modname
1660 * if successfull then break the loop.
1661 * endloop
1662 * endif
1663 * @remark cchFilename has to be ULONG due to an optimization bug in VA 3.08.
1664 * (cchFilename should have been USHORT. But, then the compiler would
1665 * treat it as an ULONG.)
1666 * TODO: Support quotes.
1667 */
1668ULONG Pe2Lx::openPath2(PCHAR pachFilename, ULONG cchFilename, ldrlv_t *pLdrLv, PULONG pful, ULONG lLibPath, BOOL fOdin32PathValid)
1669{
1670 #ifdef RING0
1671
1672 APIRET rc; /* Returncode. */
1673 ULONG cchExt; /* Count of chars in additional extention. (0 if extention exists.) */
1674
1675 /* These defines sets the order the paths and pathlists are examined. */
1676 #define FINDDLL_EXECUTABLEDIR 1
1677 #define FINDDLL_CURRENTDIR 2
1678 #define FINDDLL_SYSTEM32DIR 3
1679 #define FINDDLL_SYSTEM16DIR 4
1680 #define FINDDLL_WINDIR 5
1681 #define FINDDLL_PATH 6
1682 #define FINDDLL_BEGINLIBPATH 7 /* uses ldrOpenPath */
1683 #define FINDDLL_LIBPATH 8 /* uses ldrOpenPath */
1684 #define FINDDLL_ENDLIBPATH 9 /* uses ldrOpenPath */
1685 #define FINDDLL_FIRST FINDDLL_EXECUTABLEDIR
1686 #define FINDDLL_LAST FINDDLL_ENDLIBPATH
1687
1688 struct _LocalVars
1689 {
1690 char sz[CCHMAXPATH];
1691 char szPath[CCHMAXPATH];
1692 } *pVars;
1693
1694
1695 /** @sketch
1696 * Mark the SFN invalid in the case of error.
1697 * Allocate memory for local variables.
1698 * Check for extention.
1699 */
1700 pLdrLv->lv_sfn = 0xffff;
1701 pVars = (struct _LocalVars*)rmalloc(sizeof(struct _LocalVars));
1702 if (pVars == NULL)
1703 {
1704 printErr(("openPath2: rmalloc failed\n"));
1705 return ERROR_NOT_ENOUGH_MEMORY;
1706 }
1707
1708 cchExt = cchFilename - 1;
1709 while (cchExt != 0 && pachFilename[cchExt] != '.')
1710 cchExt--;
1711 cchExt = cchExt != 0 ? 0 : 4;
1712
1713
1714 /** @sketch
1715 * Loop thru the paths and pathlists searching them for the filename.
1716 */
1717 for (int iPath = FINDDLL_FIRST; iPath <= FINDDLL_LAST; iPath++)
1718 {
1719 char * pszPath; /* Pointer to the path being examined. */
1720
1721 /** @sketch
1722 * Get the path/dir to examin. (This is determined by the value if iPath.)
1723 */
1724 switch (iPath)
1725 {
1726 case FINDDLL_EXECUTABLEDIR:
1727 if ((pszPath = ldrGetExePath(pVars->szPath, TRUE)) == NULL)
1728 {
1729 //kprintf(("openPath2: failed to find exe path.\n")); //DEBUG
1730 continue;
1731 }
1732 break;
1733
1734 case FINDDLL_CURRENTDIR:
1735 pszPath = ".";
1736 break;
1737
1738 case FINDDLL_SYSTEM32DIR:
1739 if (!fOdin32PathValid)
1740 {
1741 //kprintf(("openPath2: invalid odin32 paths.\n"));
1742 continue;
1743 }
1744 pszPath = pVars->szPath;
1745 strcpy(pszPath, pszOdin32Path);
1746 strcpy(pszPath + cchOdin32Path, "System32");
1747 break;
1748
1749 case FINDDLL_SYSTEM16DIR:
1750 if (!fOdin32PathValid)
1751 {
1752 //kprintf(("openPath2: invalid odin32 paths.\n"));
1753 continue;
1754 }
1755 pszPath = pVars->szPath;
1756 strcpy(pszPath, pszOdin32Path);
1757 strcpy(pszPath + cchOdin32Path, "System");
1758 break;
1759
1760 case FINDDLL_WINDIR:
1761 if (!fOdin32PathValid)
1762 {
1763 //kprintf(("openPath2: invalid odin32 paths.\n"));
1764 continue;
1765 }
1766 pszPath = pVars->szPath;
1767 strcpy(pszPath, pszOdin32Path);
1768 pszPath[cchOdin32Path - 1] = '\0'; /* remove slash */
1769 break;
1770
1771 case FINDDLL_PATH:
1772 {
1773 PPTD pptd = GetTaskData(NULL, FALSE);
1774 pszPath = NULL;
1775 if (pptd)
1776 pszPath = pptd->pszzOdin32Env;
1777 if (!pszPath)
1778 pszPath = (char*)GetEnv(TRUE);
1779 if (pszPath == NULL)
1780 {
1781 //kprintf(("openPath2: failed to GetEnv.\n"));
1782 continue;
1783 }
1784 pszPath = (char*)ScanEnv(pszPath, "PATH");
1785 break;
1786 }
1787
1788 #if 1
1789 case FINDDLL_BEGINLIBPATH:
1790 pszPath = NULL;
1791 if (ptdaGetCur())
1792 pszPath = ptdaGet_ptda_pBeginLIBPATH(ptdaGetCur());
1793 if (pszPath == NULL)
1794 continue;
1795 break;
1796
1797 case FINDDLL_LIBPATH:
1798 pszPath = *pLdrLibPath;
1799 break;
1800
1801 case FINDDLL_ENDLIBPATH:
1802 pszPath = NULL;
1803 if (ptdaGetCur())
1804 pszPath = ptdaGet_ptda_pEndLIBPATH(ptdaGetCur());
1805 if (pszPath == NULL)
1806 continue;
1807 break;
1808 #endif
1809
1810 default: /* !internalerror! */
1811 printIPE(("Pe2Lx::openPath(%.*s,..): iPath is %d which is invalid.\n", cchFilename, pachFilename, iPath));
1812 rfree(pVars);
1813 return ERROR_FILE_NOT_FOUND;
1814 }
1815
1816 //kprintf(("openPath2: level:%d path=%s\n", iPath, pszPath));
1817
1818 /** @sketch
1819 * pszPath is now set to the pathlist to be searched.
1820 * So we'll loop thru all the paths in the list.
1821 */
1822 while (pszPath != NULL && *pszPath != '\0')
1823 {
1824 char * pszNext; /* Pointer to the next pathlist path */
1825 int cch; /* Length of path (including the slash after the slash is added). */
1826
1827 /** @sketch
1828 * Find the end of the path and set pszNext.
1829 * Uncount any trailing slash.
1830 * Check that the filename fits within the buffer (and OS/2 filelength limits).
1831 */
1832 pszNext = strchr(pszPath, ';');
1833 if (pszNext != NULL)
1834 {
1835 cch = pszNext - pszPath;
1836 pszNext++;
1837 }
1838 else
1839 cch = strlen(pszPath);
1840
1841 if (pszPath[cch - 1] == '\\' || pszPath[cch-1] == '/')
1842 cch--;
1843
1844 if (cch == 0 || cch + cchFilename + 2 + cchExt > sizeof(pVars->sz)) /* assertion */
1845 {
1846 printErr(("Pe2Lx::openPath(%.*s,..): cch (%d) + cchFilename (%d) + 2 + cchExt (%d) > sizeof(pVars->sz) (%d) - path's too long!, iPath=%d",
1847 cchFilename, pachFilename, cch, cchExt, cchFilename, sizeof(pVars->sz), iPath));
1848
1849 pszPath = pszNext;
1850 continue;
1851 }
1852
1853
1854 /** @sketch
1855 * Copy the path into the pVars->sz buffer.
1856 * Add a '\\' and the filename (pszFullname) to the path;
1857 * then we'll have a fullpath.
1858 */
1859 memcpy(pVars->sz, pszPath, cch);
1860 pVars->sz[cch++] = '\\';
1861 memcpy(&pVars->sz[cch], pachFilename, (size_t)cchFilename);
1862 if (cchExt != 0)
1863 memcpy(&pVars->sz[cch + cchFilename], ".DLL", 5);
1864 else
1865 pVars->sz[cch + cchFilename] = '\0';
1866
1867
1868 /** @sketch
1869 * Try open the file using myLdrOpen.
1870 * Return if successfully opened or if fatal error.
1871 */
1872 rc = myldrOpen(&pLdrLv->lv_sfn, pVars->sz, pful);
1873 switch (rc)
1874 {
1875 /* these errors are ignored (not fatal) */
1876 case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: case ERROR_ACCESS_DENIED: case ERROR_INVALID_ACCESS:
1877 case ERROR_INVALID_DRIVE: case ERROR_NOT_DOS_DISK: case ERROR_REM_NOT_LIST: case ERROR_BAD_NETPATH:
1878 case ERROR_NETWORK_BUSY: case ERROR_DEV_NOT_EXIST: case ERROR_TOO_MANY_CMDS: case ERROR_ADAP_HDW_ERR:
1879 case ERROR_UNEXP_NET_ERR: case ERROR_BAD_REM_ADAP: case ERROR_NETNAME_DELETED: case ERROR_BAD_DEV_TYPE:
1880 case ERROR_NETWORK_ACCESS_DENIED: case ERROR_BAD_NET_NAME: case ERROR_TOO_MANY_SESS: case ERROR_REQ_NOT_ACCEP:
1881 case ERROR_INVALID_PASSWORD: case ERROR_OPEN_FAILED: case ERROR_INVALID_NAME: case ERROR_FILENAME_EXCED_RANGE:
1882 case ERROR_VC_DISCONNECTED: case ERROR_DRIVE_LOCKED:
1883 rc = ERROR_FILE_NOT_FOUND;
1884 pszPath = pszNext;
1885 break;
1886
1887 /* all errors and success is let out here */
1888 case NO_ERROR:
1889 default:
1890 rfree(pVars);
1891 return rc;
1892 }
1893
1894 /** @sketch
1895 * Advance to the next path part
1896 */
1897 pszPath = pszNext;
1898 }
1899 } /* for iPath */
1900
1901
1902 /*
1903 * Cleanup: free local variables.
1904 * Since we haven't found the file yet we'll return thru ldrOpenPath.
1905 */
1906 rfree(pVars);
1907 NOREF(lLibPath);
1908 return ERROR_FILE_NOT_FOUND;//ldrOpenPath(pachFilename, (USHORT)cchFilename, pLdrLv, pful, lLibPath);
1909
1910 #else
1911 NOREF(pachFilename);
1912 NOREF(cchFilename);
1913 NOREF(pLdrLv);
1914 NOREF(pful);
1915 NOREF(lLibPath);
1916 NOREF(fOdin32PathValid);
1917 return ERROR_NOT_SUPPORTED;
1918 #endif
1919}
1920
1921
1922#ifndef RING0
1923/**
1924 * This method test the applyFixups method.
1925 * @returns Last rc from applyFixups.
1926 * @status
1927 * @author knut st. osmundsen
1928 * @remark Testing only...
1929 */
1930ULONG Pe2Lx::testApplyFixups()
1931{
1932 static SMTE smte;
1933 static MTE mte;
1934 static achPage[PAGESIZE];
1935 int i;
1936 APIRET rc;
1937
1938 mte.mte_swapmte = &smte;
1939 smte.smte_objcnt = cObjects;
1940 smte.smte_objtab = (POTE)malloc(cObjects * sizeof(OTE));
1941 makeObjectTable();
1942 memcpy(smte.smte_objtab, paObjTab, sizeof(OTE) * cObjects);
1943 smte.smte_objtab[0].ote_base = 0x132d0000;
1944 for (i = 1; i < cObjects; i++)
1945 smte.smte_objtab[i].ote_base = ALIGN(smte.smte_objtab[i-1].ote_size + smte.smte_objtab[i-1].ote_base, 0x10000);
1946
1947 rc = loadBaseRelocations();
1948 if (rc != NO_ERROR)
1949 {
1950 printErr(("loadBaseRelocations failed with rc=%d\n", rc));
1951 return rc;
1952 }
1953
1954 /*
1955 * Test load and apply all (internal) fixups.
1956 */
1957 for (i = 0; i < cObjects; i++)
1958 {
1959 ULONG ulAddress = smte.smte_objtab[i].ote_base;
1960 ULONG ulRVA = paObjects[i].ulRVA;
1961 LONG cbObject = paObjects[i].cbVirtual;
1962 for (i=i; cbObject > 0; cbObject -= PAGESIZE, ulAddress += PAGESIZE, ulRVA += PAGESIZE)
1963 {
1964 printInf(("Page at RVA 0x%08x\n", ulRVA));
1965 rc = readAtRVA(ulRVA, &achPage[0], PAGESIZE);
1966 if (rc != NO_ERROR)
1967 {
1968 printErr(("readAtRVA failed with rc=%d\n"));
1969 return rc;
1970 }
1971 rc = applyFixups(&mte, i, ulRVA >> PAGESHIFT, &achPage[0], ulAddress, NULL);
1972 if (rc != NO_ERROR)
1973 {
1974 printErr(("applyFixups failed with rc=%d\n"));
1975 return rc;
1976 }
1977 }
1978 }
1979
1980 return rc;
1981}
1982
1983
1984
1985/**
1986 * Writes the virtual LX file to a file. (Ring 3 only!)
1987 * @returns NO_ERROR on success. Error code on error.
1988 * @param pszLXFilename Pointer to name of the LX file.
1989 * @sketch Find size of the virtual LX-file.
1990 * Open the output file.
1991 * LOOP while more to left of file
1992 * BEGIN
1993 * read into buffer from virtual LX-file.
1994 * write to output file.
1995 * END
1996 * return success or errorcode.
1997 * @status compeletely implemented; tested.
1998 * @author knut st. osmundsen
1999 */
2000ULONG Pe2Lx::writeFile(PCSZ pszLXFilename)
2001{
2002 static CHAR achReadBuffer[65000];
2003 APIRET rc;
2004 ULONG ulAction = 0;
2005 ULONG ulWrote;
2006 HFILE hLXFile = NULLHANDLE;
2007 ULONG cbLXFile;
2008 ULONG offLXFile;
2009
2010 /* Find size of the virtual LX-file. */
2011 cbLXFile = querySizeOfLxFile();
2012 if (cbLXFile == ~0UL)
2013 return ERROR_BAD_EXE_FORMAT;
2014
2015 printInf(("\n"));
2016 printInf(("Creating LX file - %s\n", pszLXFilename));
2017 printInf(("\n"));
2018 printInf(("Size of virtual LX-file: %d bytes\n", cbLXFile));
2019
2020 /* Open the output file. */
2021 rc = DosOpen(pszLXFilename, &hLXFile, &ulAction, cbLXFile,
2022 FILE_NORMAL,
2023 OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_REPLACE_IF_EXISTS,
2024 OPEN_FLAGS_SEQUENTIAL | OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYWRITE | OPEN_ACCESS_WRITEONLY,
2025 NULL);
2026 if (rc == NO_ERROR)
2027 {
2028 offLXFile = 0UL;
2029 while (cbLXFile > 0UL)
2030 {
2031 ULONG cbToRead = min(cbLXFile, sizeof(achReadBuffer));
2032 rc = read(offLXFile, &achReadBuffer[0], 0UL, cbToRead, NULL);
2033 if (rc != NO_ERROR)
2034 {
2035 printErr(("read failed with rc=%d.\n", rc));
2036 break;
2037 }
2038 /* write to output file. */
2039 rc = DosWrite(hLXFile, &achReadBuffer[0], cbToRead, &ulWrote);
2040 if (rc != NO_ERROR || ulWrote != cbToRead)
2041 {
2042 printErr(("DosWrite failed with rc=%d\n", rc));
2043 break;
2044 }
2045
2046 /* move along */
2047 offLXFile += cbToRead;
2048 cbLXFile -= cbToRead;
2049 }
2050 DosClose(hLXFile);
2051 }
2052 else
2053 printErr(("Failed to open output file, '%s', for writing. rc = %d\n",
2054 pszLXFilename, rc));
2055
2056 if (rc == NO_ERROR)
2057 printInf(("File created successfully.\n"));
2058
2059 return rc;
2060}
2061#endif
2062
2063
2064/**
2065 * Is this module an executable?
2066 * @returns TRUE if executable.
2067 * FALSE if not an executable.
2068 * @sketch
2069 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
2070 */
2071BOOL Pe2Lx::isExe()
2072{
2073 return ((this->LXHdr.e32_mflags & E32MODMASK) == E32MODEXE);
2074}
2075
2076
2077/**
2078 * Is this module an dynamic link library.
2079 * @returns TRUE if dynamic link library.
2080 * FALSE if not a dynamic link library.
2081 * @sketch
2082 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
2083 */
2084BOOL Pe2Lx::isDll()
2085{
2086 return ((this->LXHdr.e32_mflags & E32MODMASK) == E32MODDLL);
2087}
2088
2089
2090/**
2091 * Invalidates the odin32path.
2092 * Called by ldrClose when the kernel32 handle is closed.
2093 * @sketch Free path
2094 * nullify path pointer and kernel32 handle.
2095 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
2096 */
2097VOID Pe2Lx::invalidateOdin32Path()
2098{
2099 if (pszOdin32Path != NULL)
2100 {
2101 rfree((void*)pszOdin32Path);
2102 pszOdin32Path = NULL;
2103 }
2104 sfnKernel32 = NULLHANDLE;
2105}
2106
2107
2108/**
2109 * Gets the size of the virtual LX-file.
2110 * @returns Size of the virtual LX-file in bytes.
2111 * ~0UL on failure.
2112 * @sketch Find last object with valid pages.
2113 * IF not found THEN return error.
2114 * return LX offset + physical size of object; ie. the size of the LX file.
2115 * @status completely implemented; tested.
2116 * @author knut st. osmundsen
2117 * @remark Not called in during init.
2118 */
2119ULONG Pe2Lx::querySizeOfLxFile()
2120{
2121 LONG iObj;
2122
2123 #ifdef DEBUG
2124 /* call-time test. */
2125 if (fInitTime)
2126 {
2127 printIPE(("querySizeOfLXFile should not be called during init!\n"));
2128 return ~0UL;
2129 }
2130 #endif
2131
2132 /* find last object with valid pages. */
2133 iObj = cObjects - 1;
2134 while (iObj >= 0 && paObjects[iObj].cbPhysical == 0UL)
2135 iObj--;
2136
2137 /* check for impossible error. */
2138 if (iObj < 0)
2139 {
2140 printIPE(("This could not happen! No objects with valid pages!\n"));
2141 return ~0UL;
2142 }
2143
2144 return paObjects[iObj].offLXFile + paObjects[iObj].cbPhysical;
2145}
2146
2147
2148/**
2149 * Dumps info on the virtual Lx file.
2150 * Currently it only dumps sizes and offsets.
2151 * @status partially implemented.
2152 * @author knut st. osmundsen
2153 */
2154VOID Pe2Lx::dumpVirtualLxFile()
2155{
2156 ULONG ul, ulIndex;
2157 ULONG off, cb, cbA;
2158 PCSZ pszName;
2159
2160 printInf(("\n"));
2161 printInf(("----- Pe2Lx::dumpVirtualLxFile() start -----\n"));
2162
2163 /* Dump sizes */
2164 printInf(("\n"));
2165 ul = querySizeOfLxFile();
2166 printInf(("Size of Virtual LX file: %d (%#x)\n", ul, ul));
2167 for (ulIndex = 0; ulIndex <= 9; ulIndex++)
2168 {
2169 /* ASSUME a given order of tables! (See near bottom of the init() method) */
2170 switch (ulIndex)
2171 {
2172 case 0: /* LXHdr */
2173 pszName = "LX Header";
2174 off = 0UL;
2175 cb = sizeof(LXHdr);
2176 cbA = 0UL;
2177 break;
2178 case 1: /* Object Table */
2179 pszName = "Object Table";
2180 off = LXHdr.e32_objtab;
2181 cb = sizeof(struct o32_obj) * LXHdr.e32_objcnt;
2182 cbA = _msize(this->paObjTab);
2183 break;
2184 case 2: /* Object Page Table */
2185 pszName = "Object Page Table";
2186 off = LXHdr.e32_objmap;
2187 cb = LXHdr.e32_mpages * sizeof(struct o32_map);
2188 cbA = _msize(paObjPageTab);
2189 break;
2190 case 3: /* Resident Name Table */
2191 pszName = "Resident Name Table";
2192 off = LXHdr.e32_restab;
2193 cb = LXHdr.e32_enttab - off;
2194 cbA = _msize(pachResNameTable);
2195 break;
2196 case 4: /* Entry Table */
2197 pszName = "Entry Table";
2198 off = LXHdr.e32_enttab;
2199 cb = LXHdr.e32_fpagetab - off;
2200 cbA = _msize(pEntryBundles);
2201 break;
2202 case 5: /* FixupTable */
2203 pszName = "Fixup Page Table";
2204 off = LXHdr.e32_fpagetab;
2205 cb = LXHdr.e32_frectab - off;
2206 cbA = _msize(paulFixupPageTable);
2207 break;
2208 case 6: /* Fixup Record Table */
2209 pszName = "Fixup Record Table";
2210 off = LXHdr.e32_frectab;
2211 cb = LXHdr.e32_impmod - off;
2212 cbA = _msize(pFixupRecords);
2213 break;
2214 case 7: /* Import Module Name Table */
2215 pszName = "Import Module Name Table";
2216 off = LXHdr.e32_impmod;
2217 cb = LXHdr.e32_impproc - off;
2218 cbA = _msize(pachImpModuleNames);
2219 break;
2220 case 8: /* Import Procedure Name Table */
2221 pszName = "Import Procedure Name Table";
2222 off = LXHdr.e32_impproc;
2223 cb = LXHdr.e32_datapage - off;
2224 cbA = _msize(pachImpFunctionNames);
2225 break;
2226 case 9: /* data pages.*/
2227 pszName = "Data Pages";
2228 off = LXHdr.e32_datapage;
2229 cb = querySizeOfLxFile() - off;
2230 cbA = 0UL;
2231 break;
2232 default: printIPE(("invalid ulIndex. ulIndex = %d\n", ulIndex));
2233 }
2234 ul = strlen(pszName);
2235 printInf((" %s %*s off: %.6d (0x%08x) size: %.6d (0x%08x) allocated: %.6d (0x%08x)\n",
2236 pszName, ul > 30UL ? 0 : 30 - ul, "", off, off, cb, cb, cbA, cbA));
2237 }
2238
2239 /* Size of Pe2Lx object. (heap size) */
2240 printInf(("\n"));
2241 printInf(("Size of Pe2Lx object on heap:\n"));
2242 for (ulIndex = 0UL, cbA = 0UL; ulIndex <= 13UL; ulIndex ++)
2243 {
2244 switch (ulIndex)
2245 {
2246 case 0:
2247 pszName = "The Pe2Lx Object";
2248 cb = sizeof(Pe2Lx);
2249 break;
2250 case 1:
2251 pszName = "pszFilename";
2252 cb = _msize(pszFilename);
2253 break;
2254 case 2:
2255 pszName = "paObjects";
2256 cb = _msize(paObjects);
2257 break;
2258 case 3:
2259 pszName = "paObjTab";
2260 cb = _msize(paObjTab);
2261 break;
2262 case 4:
2263 pszName = "paObjPageTab";
2264 cb = _msize(paObjPageTab);
2265 break;
2266 case 5:
2267 pszName = "pachResNameTable";
2268 cb = _msize(pachResNameTable);
2269 break;
2270 case 6:
2271 pszName = "pEntryBundles";
2272 cb = _msize(pEntryBundles);
2273 break;
2274 case 7:
2275 pszName = "paulFixupPageTable";
2276 cb = _msize(paulFixupPageTable);
2277 break;
2278 case 8:
2279 pszName = "pFixupRecords";
2280 cb = _msize(pFixupRecords);
2281 break;
2282 case 9:
2283 pszName = "pvCrossPageFixup";
2284 cb = _msize(pvCrossPageFixup);
2285 break;
2286 case 10:
2287 pszName = "pachImpModuleNames";
2288 cb = _msize(pachImpModuleNames);
2289 break;
2290 case 11:
2291 pszName = "pachImpFunctionNames";
2292 cb = _msize(pachImpFunctionNames);
2293 break;
2294 case 12:
2295 pszName = "pNtHdrs";
2296 cb = _msize(pNtHdrs);
2297 break;
2298 case 13:
2299 pszName = "total";
2300 cb = cbA;
2301 break;
2302 default: printIPE(("invalid ulIndex. ulIndex = %d\n", ulIndex));
2303 }
2304
2305 ul = strlen(pszName);
2306 printInf((" %s %*s size: %.6d (0x%08x)\n", pszName, ul >= 30UL ? 0 : 30 - ul, "", cb, cb));
2307 cbA += cb;
2308 }
2309
2310
2311 printInf(("----- Pe2Lx::dumpVirtualLxFile() end -----\n"));
2312}
2313
2314
2315/**
2316 * Adds a stack object.
2317 * The stack array is sorted ascending on ulRVA.
2318 * @returns NO_ERROR
2319 * ERROR_NOT_ENOUGH_MEMORY
2320 * ERROR_INITMETHOD_NOT_INITTIME (debug only)
2321 * @param ulRVA Virtual address of this object.
2322 * @param cbPhysical Physical size of the object.
2323 * @param cbVirtual Virtual size of the object.
2324 * @param flFlags LX object flags.
2325 * @param offPEFile Data offset into the PEFile.
2326 * @precond We're in init-mode, ie. called from init().
2327 * @status Completely implemented; tested.
2328 * @author knut st. osmundsen
2329 */
2330ULONG Pe2Lx::addObject(ULONG ulRVA, ULONG cbPhysical, ULONG cbVirtual, ULONG flFlags, ULONG offPEFile)
2331{
2332 int i;
2333 #ifdef DEBUG
2334 if (!fInitTime)
2335 {
2336 printIPE(("addObject(,,,,) called when not in init mode!\n"));
2337 return ERROR_INITMETHOD_NOT_INITTIME;
2338 }
2339 #endif
2340
2341 /* Check that there is a free entry in the array for the new object. If not allocate one (or more)! */
2342 if (cObjectsAllocated == 0UL)
2343 {
2344 cObjectsAllocated = (USHORT)(pNtHdrs == NULL ? 2 :
2345 pNtHdrs->FileHeader.NumberOfSections + (pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL ? 0 : 1));
2346 paObjects = (PLXOBJECT)malloc(sizeof(LXOBJECT) * cObjectsAllocated);
2347 if (paObjects == NULL)
2348 {
2349 cObjectsAllocated = 0;
2350 return ERROR_NOT_ENOUGH_MEMORY;
2351 }
2352 }
2353 else if (cObjectsAllocated == cObjects)
2354 {
2355 PLXOBJECT paObjTmp = (PLXOBJECT)realloc(paObjects, sizeof(LXOBJECT) * (cObjectsAllocated + 1));
2356 if (paObjTmp == NULL)
2357 return ERROR_NOT_ENOUGH_MEMORY;
2358 paObjects = paObjTmp;
2359 cObjectsAllocated++;
2360 }
2361
2362 /* insert sorted. Move objects after the new object. */
2363 for (i = cObjects; i > 0 && paObjects[i-1].ulRVA > ulRVA; i--)
2364 memcpy(&paObjects[i-1], &paObjects[i], sizeof(paObjects[0]));
2365
2366 paObjects[i].ulRVA = ulRVA;
2367 paObjects[i].cbPhysical = cbPhysical;
2368 paObjects[i].cbVirtual = cbVirtual;
2369 paObjects[i].flFlags = flFlags;
2370 paObjects[i].Misc.offTIBFix = 0UL;
2371 paObjects[i].Misc.fTIBFixObject = FALSE;
2372 paObjects[i].Misc.fStackObject = FALSE;
2373 paObjects[i].offPEFile = offPEFile;
2374 paObjects[i].offLXFile = 0UL;
2375 cObjects++;
2376
2377 return NO_ERROR;
2378}
2379
2380
2381/**
2382 * Adds a TIBFix object.
2383 * @returns NO_ERROR
2384 * ERROR_NOT_ENOUGH_MEMORY
2385 * ERROR_INITMETHOD_NOT_INITTIME (debug only)
2386 * @precond We're in init-mode, ie. called from init().
2387 * @status partially implemented.
2388 * @author knut st. osmundsen
2389 * @remark Possible problem: section alignment! FIXME!
2390 */
2391ULONG Pe2Lx::addTIBFixObject()
2392{
2393 APIRET rc;
2394
2395 #ifdef DEBUG
2396 if (!fInitTime)
2397 {
2398 printIPE(("addTIBFixObject(,,,,) called when not in init mode!\n"));
2399 return ERROR_INITMETHOD_NOT_INITTIME;
2400 }
2401 #endif
2402
2403 rc = addObject(cObjects == 0 ? ulImageBase
2404 : ALIGN(paObjects[cObjects-1].ulRVA + paObjects[cObjects-1].cbVirtual, PAGESIZE),
2405 SIZEOF_TIBFIX, SIZEOF_TIBFIX, OBJREAD | OBJBIGDEF | OBJEXEC, 0UL);
2406
2407 if (rc == NO_ERROR)
2408 paObjects[cObjects-1].Misc.fTIBFixObject = TRUE;
2409
2410 return rc;
2411}
2412
2413
2414/**
2415 * Adds a stack object.
2416 * @returns NO_ERROR
2417 * ERROR_INVALID_PARAMETER
2418 * ERROR_NOT_ENOUGH_MEMORY
2419 * ERROR_INITMETHOD_NOT_INITTIME (debug only)
2420 * @param cbStack Stack size.
2421 * @precond The stack object may not be the first object. (cObjects != 0)
2422 * We're in init-mode, ie. called from init().
2423 * @status partly implemented; tested.
2424 * @author knut st. osmundsen
2425 * @remark Possible problem: section alignment! FIXME!
2426 */
2427ULONG Pe2Lx::addStackObject(ULONG cbStack)
2428{
2429 APIRET rc;
2430 #ifdef DEBUG
2431 if (!fInitTime)
2432 {
2433 printIPE(("addStackObject(,,,,) called when not in init mode!\n"));
2434 rc = ERROR_INITMETHOD_NOT_INITTIME;
2435 }
2436 #endif
2437
2438 if (cObjects != 0)
2439 {
2440 rc = addObject(ALIGN(paObjects[cObjects-1].ulRVA + paObjects[cObjects-1].cbVirtual, PAGESIZE),
2441 0UL, cbStack, OBJREAD | OBJWRITE | OBJBIGDEF, 0UL);
2442 if (rc == NO_ERROR)
2443 paObjects[cObjects-1].Misc.fStackObject = TRUE;
2444 }
2445 else
2446 {
2447 printIPE(("addStackObject(,,,,) called when cObjects == 0!\n"));
2448 rc = ERROR_INVALID_PARAMETER;
2449 }
2450
2451 return rc;
2452}
2453
2454
2455/**
2456 * Creates the page table according to the current settings of paObjects array and fAllInOneModule.
2457 * @returns NO_ERROR
2458 * ERROR_NOT_ENOUGH_MEMORY
2459 * @sketch IF valid object table pointer THEN return successfully.
2460 * (try) allocate memory for the object table.
2461 * IF all in one object THEN make one big object which covers the entire range described in paObjects.
2462 * ELSE loop tru paObject and create LX objects.
2463 * return successfully.
2464 * @status completely implemented.
2465 * @author knut st. osmundsen
2466 * @remark Object Table format (from Linear eXecutable Module Format,lxspec.inf, Rev.8):
2467 *
2468 * The number of entries in the Object Table is given by the # Objects in Module field in the
2469 * linear EXE header. Entries in the Object Table are numbered starting from one. Each Object
2470 * Table entry has the following format:
2471 *
2472 * ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
2473 * 00h ³ VIRTUAL SIZE ³ RELOC BASE ADDR ³
2474 * ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŽ
2475 * 08h ³ OBJECT FLAGS ³ PAGE TABLE INDEX ³
2476 * ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŽ
2477 * 10h ³ # PAGE TABLE ENTRIES ³ RESERVED ³
2478 * ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
2479 *
2480 * Object Table
2481 *
2482 * VIRTUAL SIZE = DD Virtual memory size. This is the size of the object that will be
2483 * allocated when the object is loaded. The object data length must be less than or equal
2484 * to the total size of the pages in the EXE file for the object. This memory size must also
2485 * be large enough to contain all of the iterated data and uninitialized data in the EXE file.
2486 *
2487 * RELOC BASE ADDR = DD Relocation Base Address. The relocation base address the object is
2488 * currently relocated to. If the internal relocation fixups for the module have been removed,
2489 * this is the address the object will be allocated at by the loader.
2490 *
2491 * OBJECT FLAGS = DW Flag bits for the object. The object flag bits have the following definitions.
2492 *
2493 * 0001h = Readable Object.
2494 * 0002h = Writable Object.
2495 * 0004h = Executable Object. The readable, writable and executable flags provide support
2496 * for all possible protections. In systems where all of these protections are not
2497 * supported, the loader will be responsible for making the appropriate protection match
2498 * for the system.
2499 *
2500 * 0008h = Resource Object.
2501 * 0010h = Discardable Object.
2502 * 0020h = Object is Shared.
2503 * 0040h = Object has Preload Pages.
2504 * 0080h = Object has Invalid Pages.
2505 * 0100h = Object has Zero Filled Pages.
2506 * 0200h = Object is Resident (valid for VDDs, PDDs only).
2507 * 0300h = Object is Resident Contiguous (VDDs, PDDs only).
2508 * 0400h = Object is Resident 'long-lockable' (VDDs, PDDs only).
2509 * 0800h = Reserved for system use.
2510 * 1000h = 16
2511 * 2000h = Big/Default Bit Setting (80x86 Specific). The 'big/default' bit , for data
2512 * segments, controls the setting of the Big bit in the segment descriptor. (The Big
2513 * bit, or B-bit, determines whether ESP or SP is used as the stack pointer.) For code
2514 * segments, this bit controls the setting of the Default bit in the segment descriptor.
2515 * (The Default bit, or D-bit, determines whether the default word size is 32-bits or
2516 * 16-bits. It also affects the interpretation of the instruction stream.)
2517 *
2518 * 4000h = Object is conforming for code (80x86 Specific).
2519 * 8000h = Object I/O privilege level (80x86 Specific). Only used for 16
2520 *
2521 * PAGE TABLE INDEX = DD Object Page Table Index. This specifies the number of the first
2522 * object page table entry for this object. The object page table specifies where in the EXE
2523 * file a page can be found for a given object and specifies per-page attributes. The object
2524 * table entries are ordered by logical page in the object table. In other words the object
2525 * table entries are sorted based on the object page table index value.
2526 *
2527 * # PAGE TABLE ENTRIES = DD # of object page table entries for this object. Any logical
2528 * pages at the end of an object that do not have an entry in the object page table associated
2529 * with them are handled as zero filled or invalid pages by the loader. When the last logical
2530 * pages of an object are not specified with an object page table entry, they are treated as
2531 * either zero filled pages or invalid pages based on the last entry in the object page table
2532 * for that object. If the last entry was neither a zero filled or invalid page, then the
2533 * additional pages are treated as zero filled pages.
2534 *
2535 * RESERVED = DD Reserved for future use. Must be set to zero.
2536 *
2537 * ------------
2538 *
2539 * We have object page table entries for all pages! (we can optimize this later)
2540 *
2541 */
2542ULONG Pe2Lx::makeObjectTable()
2543{
2544 /* check if valid object table pointer. */
2545 if (paObjTab != NULL || cObjects == 0UL)
2546 return NO_ERROR;
2547
2548 /* (try) allocate memory for the object table. */
2549 paObjTab = (struct o32_obj*)malloc(sizeof(struct o32_obj) * (fAllInOneObject ? 1 : cObjects));
2550 if (paObjTab != NULL)
2551 {
2552 if (fAllInOneObject)
2553 {
2554 paObjTab[0].o32_size = paObjects[cObjects-1].ulRVA + paObjects[cObjects-1].cbVirtual;
2555 paObjTab[0].o32_base = ulImageBase + paObjects[0].ulRVA;
2556 paObjTab[0].o32_flags = OBJREAD | OBJWRITE | OBJBIGDEF;
2557 paObjTab[0].o32_pagemap = 1; /* 1 based */
2558 paObjTab[0].o32_mapsize = ALIGN(paObjTab[0].o32_size, PAGESIZE) >> PAGESHIFT;
2559 paObjTab[0].o32_reserved = 0;
2560 }
2561 else
2562 {
2563 int i;
2564 ULONG ulPageMap = 1;
2565 for (i = 0; i < cObjects; i++)
2566 {
2567 paObjTab[i].o32_size = paObjects[i].cbVirtual;
2568 paObjTab[i].o32_base = ulImageBase + paObjects[i].ulRVA;
2569 paObjTab[i].o32_flags = paObjects[i].flFlags;
2570 if (isAllRWObjectsEnabled())
2571 paObjTab[i].o32_flags = OBJREAD | OBJWRITE | OBJBIGDEF;
2572 paObjTab[i].o32_pagemap = ulPageMap;
2573 paObjTab[i].o32_mapsize = ALIGN(paObjTab[i].o32_size, PAGESIZE) >> PAGESHIFT;
2574 paObjTab[i].o32_reserved = 0;
2575 ulPageMap += paObjTab[i].o32_mapsize;
2576 }
2577 }
2578 }
2579 else
2580 return ERROR_NOT_ENOUGH_MEMORY;
2581
2582 return NO_ERROR;
2583}
2584
2585
2586/**
2587 * Creates the object page table.
2588 * @returns NO_ERROR
2589 * ERROR_NOT_ENOUGH_MEMORY
2590 * @sketch IF valid pointer or no objects THEN return successfully.
2591 * Allocate memory.
2592 * LOOP thru all pages/objects
2593 * BEGIN
2594 * IF current object offset within physical size THEN
2595 * BEGIN
2596 * make a VALID page entry .
2597 * add the smaller of pagesize and physical size - object offset to offPageData.
2598 * END
2599 * ELSE make a ZEROED page entry. (remeber fAllInOneObject)
2600 * next page/object.
2601 * END
2602 * return successfully.
2603 * @status completely implemented; tested.
2604 * @author knut st. osmundsen
2605 * @remark Object Page Table format (from Linear eXecutable Module Format,lxspec.inf, Rev.8):
2606 *
2607 * The Object page table provides information about a logical page in an object. A logical page
2608 * may be an enumerated page, a pseudo page or an iterated page. The structure of the object
2609 * page table in conjunction with the structure of the object table allows for efficient access
2610 * of a page when a page fault occurs, while still allowing the physical page data to be
2611 * located in the preload page, demand load page or iterated data page sections in the linear
2612 * EXE module. The logical page entries in the Object Page Table are numbered starting from one.
2613 * The Object Page Table is parallel to the Fixup Page Table as they are both indexed by the
2614 * logical page number. Each Object Page Table entry has the following format:
2615 *
2616 * 63 32 31 16 15 0
2617 * ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄ¿
2618 * 00h ³ PAGE DATA OFFSET ³ DATA SIZE ³ FLAGS ³
2619 * ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÙ
2620 *
2621 * Object Page Table Entry
2622 *
2623 * PAGE DATA OFFSET = DD Offset to the page data in the EXE file. This field, when bit
2624 * shifted left by the PAGE OFFSET SHIFT from the module header, specifies the offset from
2625 * the beginning of the Preload Page section of the physical page data in the EXE file that
2626 * corresponds to this logical page entry. The page data may reside in the Preload Pages,
2627 * Demand Load Pages or the Iterated Data Pages sections. A page might not start at the next
2628 * available alignment boundary. Extra padding is acceptable between pages as long as each
2629 * page starts on an alignment boundary. For example, several alignment boundarys may be
2630 * skipped in order to start a frequently accessed page on a sector boundary. If the FLAGS
2631 * field specifies that this is a Zero-Filled page then the PAGE DATA OFFSET field will
2632 * contain a 0. If the logical page is specified as an iterated data page, as indicated by
2633 * the FLAGS field, then this field specifies the offset into the Iterated Data Pages section.
2634 * The logical page number (Object Page Table index), is used to index the Fixup Page Table to
2635 * find any fixups associated with the logical page.
2636 *
2637 * DATA SIZE = DW Number of bytes of data for this page. This field specifies the actual
2638 * number of bytes that represent the page in the file. If the PAGE SIZE field from the
2639 * module header is greater than the value of this field and the FLAGS field indicates a Legal
2640 * Physical Page, the remaining bytes are to be filled with zeros. If the FLAGS field
2641 * indicates an Iterated Data Page, the iterated data records will completely fill out the
2642 * remainder.
2643 *
2644 * FLAGS = DW Attributes specifying characteristics of this logical page. The bit definitions
2645 * for this word field follow,
2646 *
2647 * 00h = Legal Physical Page in the module (Offset from Preload Page Section).
2648 * 01h = Iterated Data Page (Offset from Iterated Data Pages Section).
2649 * 02h = Invalid Page (zero).
2650 * 03h = Zero Filled Page (zero).
2651 * 04h = Range of Pages.
2652 * 05h = Compressed Page (Offset from Preload Pages Section).
2653 *
2654 * -----------
2655 *
2656 * Not space optimized yet!
2657 *
2658 */
2659ULONG Pe2Lx::makeObjectPageTable()
2660{
2661 ULONG cPages;
2662 ULONG i;
2663 ULONG iObj; /* Index to Current object. */
2664 ULONG offObject; /* Offset of the current page into the object. */
2665 ULONG offPageData; /* Offset from e32_datapage in virtual LX file. */
2666
2667 /* check if valid object page table pointer or no objects */
2668 if (paObjPageTab != NULL || cObjects == 0)
2669 return NO_ERROR;
2670
2671 /* allocate memory */
2672 cPages = getCountOfPages();
2673 paObjPageTab = (struct o32_map*)malloc((size_t)(cPages * sizeof(struct o32_map)));
2674 if (paObjPageTab == NULL)
2675 return ERROR_NOT_ENOUGH_MEMORY;
2676
2677 /* loop */
2678 iObj = 0UL;
2679 offObject = 0UL;
2680 offPageData = 0UL;
2681 for (i = 0UL; i < cPages; i++)
2682 {
2683 paObjPageTab[i].o32_pagedataoffset = offPageData;
2684 if (offObject < paObjects[iObj].cbPhysical)
2685 {
2686 paObjPageTab[i].o32_pagesize = (USHORT)min(paObjects[iObj].cbPhysical - offObject, PAGESIZE);
2687 paObjPageTab[i].o32_pageflags = VALID;
2688 offPageData += min(paObjects[iObj].cbPhysical - offObject, PAGESIZE);
2689 }
2690 else
2691 {
2692 paObjPageTab[i].o32_pagesize = (USHORT)(fAllInOneObject && iObj + 1UL < cObjects ?
2693 PAGESIZE : min(paObjects[iObj].cbVirtual - offObject, PAGESIZE));
2694 paObjPageTab[i].o32_pageflags = ZEROED;
2695 }
2696
2697 /* next */
2698 if (offObject + PAGESIZE >=
2699 (fAllInOneObject && iObj + 1UL < cObjects ?
2700 paObjects[iObj + 1].ulRVA - paObjects[iObj].ulRVA : paObjects[iObj].cbVirtual)
2701 )
2702 { /* object++ */
2703 iObj++;
2704 offObject = 0UL;
2705 }
2706 else /* page++ */
2707 offObject += PAGESIZE;
2708 }
2709
2710 return NO_ERROR;
2711}
2712
2713
2714/**
2715 * Convert baserelocation and imports to LX fixups. Complex stuff!
2716 * @returns NO_ERROR on succes. Errorcode on error.
2717 * @sketch If valid pointers to fixups exist then return successfully without processing.
2718 * Validate pNtHdrs.
2719 * IF forwarders present and exports not made THEN makeExports!
2720 * Check and read directories for imports and relocations.
2721 * Create necessary Buffered RVA Readers.
2722 * Make sure kernel32 is the first imported module.
2723 * Initiate the import variables (if any imports):
2724 * Loop thru the import descriptiors looking for the lowest FirstThunk RVA. (ulRVAOrgFirstThunk and ulRVAFirstThunk)
2725 * When found read the module name and add it. (ulModuleOrdinal)
2726 * Initiate base relocations by reading the first Base Relocation.
2727 * Initiate iObj to 0UL, ulRVAPage to the RVA for the first object (which is allways 0UL!).
2728 *
2729 * LOOP thru all objects as long as all processing is successful
2730 * BEGIN
2731 * Add a new page table entry.
2732 * IF Page with TIBFix THEN add import fixup for RegisterEXE/DLL call.
2733 * IF Import fixups on current page THEN
2734 * BEGIN
2735 * LOOP while no processing errors and more imports on this page
2736 * BEGIN
2737 * Read Thunk
2738 * IF not end of thunk array THEN
2739 * BEGIN
2740 * IF ordinal import THEN add ordinal import fixup
2741 * ELSE IF valid RVA THEN
2742 * get name and add name import fixup
2743 * ELSE
2744 * complain and fail.
2745 * Next Thunk array element (ulRVAFirstThunk and ulRVAOrgFirstThunk)
2746 * END
2747 * ELSE
2748 * BEGIN
2749 * LOOP thru ImportDescriptors and find the following FirstThunk array. (ulRVAOrgFirstThunk and ulRVAFirstThunk)
2750 * IF found THEN read the module name and add it. (ulModuleOrdinal)
2751 * ELSE Disable Import Processing.
2752 * END
2753 * END
2754 * END
2755 * IF BaseRelocation chunk for current page THEN
2756 * BEGIN
2757 * LOOP thru all relocation in this chunk.
2758 * BEGIN
2759 * Get relocation type/offset.
2760 * Get target.
2761 * IF BASED_HIGHLOW fixup THEN add it ELSE ignore it.
2762 * END
2763 * Read next relocation chunk header - if any.
2764 * END
2765 * Next page in object or next object. (ulRVAPage and iObj)
2766 * END
2767 * IF success THEN add final page table entry.
2768 * delete reader objects.
2769 * IF success THEN release unused memory in fixup and import structures.
2770 * return errorcode.
2771 *
2772 * @status completely
2773 * @author knut st. osmundsen
2774 * @remark stack usage: 26*4 + 5*4 = 124 bytes
2775 * heap usage: 5 blocks   (4096 + 4*4) bytes = 20110 bytes
2776 * See bottom of addForwarderEntry remark!
2777 *
2778 * BTW. This piece of code remindes me about cobol programming - large and clumsy.
2779 * (I have not programmed cobol, but have read and debugged it.)
2780 */
2781ULONG Pe2Lx::makeFixups()
2782{
2783 BOOL fImports; /* fImport is set when a valid import directory is present. */
2784 ULONG ulRVAImportDesc; /* RVA of the first import descriptor. */
2785 IMAGE_IMPORT_DESCRIPTOR ImportDesc; /* Import descriptor struct used while reading. */
2786 BufferedRVARead *pImportReader; /* Buffered reader import descriptors reads. */
2787 BufferedRVARead *pImpNameReader; /* Buffered reader for names reads; ie. function and module names. */
2788 BufferedRVARead *pImpThunkReader; /* Buffered reader for thunk reads; ie. reading from the OrgiginalFirstThunk array. */
2789 ULONG ulModuleOrdinal; /* Module ordinal. Valid as long as fImport is set. */
2790 #ifndef RING0
2791 ULONG ulCustomModOrdinal; /* Module ordinal of custom Odin dll. Valid as long as fImport is set. */
2792 char szModuleName[128];
2793 #endif
2794 char * pszModuleName; /* Pointer to the current modulename or NULL. Only used with Custombuild. */
2795 ULONG ulRVAFirstThunk; /* Current first thunk array RVA. Points at current entry. */
2796 ULONG ulRVAOrgFirstThunk; /* Current original first thunk array RVA. Points at current entry. */
2797 #ifndef RING0
2798 BOOL fBaseRelocs; /* fBaseReloc is set when a valid base reloc directory is present. */
2799 ULONG ulRVABaseReloc; /* RVA of the current base relocation chunk. (Not the first!) */
2800 LONG cbBaseRelocs; /* Count of bytes left of base relocation. Used to determin eof baserelocs. */
2801 IMAGE_BASE_RELOCATION BaseReloc; /* Base Relocation struct which is used while reading. */
2802 BufferedRVARead *pPageReader; /* Buffered reader for page reads; ie. getting the target address. */
2803 BufferedRVARead *pRelocReader; /* Buffered reader for relocation reads; ie getting the type/offset word. */
2804 #endif
2805 ULONG ulRVAPage; /* RVA for the current page. */
2806 ULONG ul; /* temporary unsigned long variable. Many uses. */
2807 PSZ psz; /* temporary string pointer. Used for modulenames and functionnames. */
2808 ULONG iObj; /* Object iterator. (Index into paObjects) */
2809 APIRET rc; /* return code. */
2810
2811 /* Test if valid fixup data pointers - return if vaild */
2812 if (pFixupRecords != NULL && paulFixupPageTable != NULL)
2813 return NO_ERROR;
2814
2815 /* initiate data members of this object */
2816 rc = initFixups();
2817 if (rc != NO_ERROR)
2818 return rc;
2819
2820 /* Check that the NtHdr is valid. */
2821 rc = loadNtHeaders();
2822 if (rc != NO_ERROR)
2823 return rc;
2824
2825 /* if there are forwarder entries present, we'll have to make them first. */
2826 if (fForwarders && pEntryBundles == NULL)
2827 {
2828 rc = makeExports();
2829 if (rc != NO_ERROR)
2830 return rc;
2831 }
2832
2833 /* Check if empty import directory. */
2834 fImports = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size > 0UL
2835 &&
2836 (ulRVAImportDesc = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress) > 0UL
2837 &&
2838 ulRVAImportDesc < pNtHdrs->OptionalHeader.SizeOfImage;
2839
2840 /* Check if empty base relocation directory. */
2841 #ifndef RING0
2842 fBaseRelocs = (cbBaseRelocs = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size) > 0UL
2843 &&
2844 (ulRVABaseReloc = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) > 0UL
2845 &&
2846 ulRVABaseReloc < pNtHdrs->OptionalHeader.SizeOfImage
2847 &&
2848 areFixupsEnabled();
2849 #endif
2850 printInf(("\n"));
2851 #ifndef RING0
2852 printInf(("Make fixups, fBaseReloc=%s, fImports=%s\n",
2853 fBaseRelocs ? "true" : "false",
2854 fImports ? "true" : "false"));
2855 #else
2856 printInf(("Make fixups, fImports=%s\n", fImports ? "true" : "false"));
2857 #endif
2858 printInf(("\n"));
2859
2860 /* create reader buffers */
2861 #ifndef RING0
2862 if (fBaseRelocs)
2863 {
2864 pPageReader = new BufferedRVARead(hFile, cObjects, paObjects);
2865 pRelocReader = new BufferedRVARead(hFile, cObjects, paObjects);
2866 if (pPageReader == NULL || pRelocReader == NULL)
2867 rc = ERROR_NOT_ENOUGH_MEMORY;
2868 }
2869 else
2870 pRelocReader = pPageReader = NULL;
2871 #endif
2872 if (fImports)
2873 {
2874 pImportReader = new BufferedRVARead(hFile, cObjects, paObjects);
2875 pImpNameReader = new BufferedRVARead(hFile, cObjects, paObjects);
2876 pImpThunkReader = new BufferedRVARead(hFile, cObjects, paObjects);
2877 if (pImportReader == NULL || pImpNameReader == NULL || pImpThunkReader == NULL)
2878 rc = ERROR_NOT_ENOUGH_MEMORY;
2879 }
2880 else
2881 pImpThunkReader = pImpNameReader = pImportReader = NULL;
2882
2883 /* check for errors */
2884 if (rc != NO_ERROR)
2885 { /* error: clean up and return! */
2886 #ifndef RING0
2887 if (pPageReader != NULL)
2888 delete pPageReader;
2889 if (pRelocReader != NULL)
2890 delete pRelocReader;
2891 #endif
2892 if (pImportReader != NULL)
2893 delete pImportReader;
2894 if (pImpNameReader != NULL)
2895 delete pImpNameReader;
2896 if (pImpThunkReader != NULL)
2897 delete pImpThunkReader;
2898 return rc;
2899 }
2900
2901 /* Make sure kernel32/customdll is the first imported module */
2902 #ifndef RING0
2903 if (hasCustomDll())
2904 {
2905 rc = addModule(options.pszCustomDll, (PULONG)SSToDS(&ul));
2906 ulCustomModOrdinal = ul;
2907 }
2908 else
2909 #endif
2910 rc = addModule("KERNEL32.DLL", (PULONG)SSToDS(&ul));
2911
2912 /* initiate the import variables */
2913 if (fImports && rc == NO_ERROR)
2914 {
2915 rc = pImportReader->readAtRVA(ulRVAImportDesc, SSToDS(&ImportDesc), sizeof(ImportDesc));
2916 if (rc == NO_ERROR)
2917 {
2918 ul = 0;
2919 ulRVAFirstThunk = ~0UL;
2920 while (rc == NO_ERROR && ImportDesc.Name != 0UL && ImportDesc.FirstThunk != 0UL)
2921 {
2922 if ((ULONG)ImportDesc.FirstThunk < ulRVAFirstThunk || ulRVAFirstThunk == 0UL) /* 0 test: just in case... */
2923 {
2924 ulRVAFirstThunk = (ULONG)ImportDesc.FirstThunk;
2925 ulRVAOrgFirstThunk = (ULONG)ImportDesc.u.OriginalFirstThunk != 0UL ?
2926 (ULONG)ImportDesc.u.OriginalFirstThunk : (ULONG)ImportDesc.FirstThunk;
2927 ulModuleOrdinal = ImportDesc.Name;
2928 }
2929
2930 /* next */
2931 ul++;
2932 rc = pImportReader->readAtRVA(ulRVAImportDesc + ul * sizeof(ImportDesc), SSToDS(&ImportDesc), sizeof(ImportDesc));
2933 }
2934
2935 if (ulRVAFirstThunk != ~0UL)
2936 {
2937 rc = pImpNameReader->dupString(ulModuleOrdinal, (PSZ*)SSToDS(&psz));
2938 if (rc == NO_ERROR)
2939 {
2940 pszModuleName = NULL;
2941 #ifdef RING0
2942 rc = addModule(psz, (PULONG)SSToDS(&ulModuleOrdinal));
2943
2944 #else
2945 /* Uppercase the module names, and skip the extension. */
2946 if (hasCustomDll())
2947 {
2948 strcpy((pszModuleName = (char*)SSToDS(szModuleName)), psz);
2949 ulModuleOrdinal = ulCustomModOrdinal;
2950 for (char *pszTmp = pszModuleName; *pszTmp !='\0' && *pszTmp != '.'; pszTmp++)
2951 if (*pszTmp >= 'a' && *pszTmp <= 'z')
2952 *pszTmp += ('A' - 'a');
2953 *pszTmp = '\0';
2954 }
2955 if (!hasCustomDll() || isCustomDllExcluded(pszModuleName))
2956 {
2957 rc = addModule(psz, (PULONG)SSToDS(&ulModuleOrdinal));
2958 szModuleName[0] = '\0';
2959 pszModuleName = NULL;
2960 }
2961 #endif
2962 free(psz);
2963 }
2964 }
2965 else
2966 fImports = FALSE;
2967 }
2968 }
2969
2970
2971 /* read start of the first basereloc chunk */
2972 #ifndef RING0
2973 if (fBaseRelocs && rc == NO_ERROR)
2974 rc = pRelocReader->readAtRVA(ulRVABaseReloc, SSToDS(&BaseReloc), sizeof(BaseReloc));
2975 #endif
2976
2977
2978 /*
2979 * The Loop! Iterate thru all pages for all objects.
2980 */
2981 iObj = 0UL;
2982 if (iObj < cObjects)
2983 ulRVAPage = paObjects[iObj].ulRVA;
2984 while (iObj < cObjects && rc == NO_ERROR)
2985 {
2986 printInfA(("Page at RVA=0x%08x, object no.%d\n", ulRVAPage, iObj));
2987
2988 /* insert new fixup page and fixup record structs */
2989 rc = addPageFixupEntry();
2990 if (rc != NO_ERROR)
2991 break;
2992
2993 /* check for TibFix, add import fixup for it */
2994 if (paObjects[iObj].Misc.fTIBFixObject
2995 && ((paObjects[iObj].Misc.offTIBFix + paObjects[iObj].ulRVA) & ~(PAGESIZE-1UL)) == ulRVAPage)
2996 {
2997 PCSZ pszTmp = NULL;
2998 #ifndef RING0
2999 if (hasCustomDll())
3000 {
3001 pszTmp = "KERNEL32";
3002 rc = addModule(options.pszCustomDll, (PULONG)SSToDS(&ul));
3003 }
3004 else
3005 #endif
3006 rc = addModule("KERNEL32.DLL", (PULONG)SSToDS(&ul));
3007 if (rc == NO_ERROR)
3008 {
3009 printInfA(("TibFix import fixup\n"));
3010 rc = add32OrdImportFixup((WORD)((paObjects[iObj].Misc.offTIBFix + paObjects[iObj].ulRVA + TIBFIX_OFF_CALLADDRESS) & (PAGESIZE-1UL)),
3011 ul,
3012 pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL ?
3013 ORD_REGISTERPE2LXDLL : ORD_REGISTERPE2LXEXE, pszTmp);
3014 }
3015 if (rc != NO_ERROR)
3016 break;
3017 }
3018
3019
3020 /* check for imports at this page */
3021 if (fImports && ulRVAFirstThunk < ulRVAPage + PAGESIZE)
3022 {
3023 while (rc == NO_ERROR && ulRVAFirstThunk < ulRVAPage + PAGESIZE)
3024 {
3025 IMAGE_THUNK_DATA Thunk;
3026 rc = pImpThunkReader->readAtRVA(ulRVAOrgFirstThunk, SSToDS(&Thunk), sizeof(Thunk));
3027 if (rc != NO_ERROR)
3028 break;
3029 if (Thunk.u1.Ordinal != 0UL)
3030 {
3031 if (Thunk.u1.Ordinal & (ULONG)IMAGE_ORDINAL_FLAG)
3032 rc = add32OrdImportFixup((WORD)(ulRVAFirstThunk & (PAGESIZE-1)),
3033 ulModuleOrdinal, Thunk.u1.Ordinal & 0xffff, pszModuleName);
3034 else if (Thunk.u1.Ordinal > 0UL && Thunk.u1.Ordinal < pNtHdrs->OptionalHeader.SizeOfImage)
3035 {
3036 rc = pImpNameReader->dupString(Thunk.u1.Ordinal + offsetof(IMAGE_IMPORT_BY_NAME, Name),
3037 (PSZ*)SSToDS(&psz));
3038 if (rc != NO_ERROR)
3039 break;
3040 rc = add32NameImportFixup((WORD)(ulRVAFirstThunk & (PAGESIZE-1)),
3041 ulModuleOrdinal, psz, pszModuleName);
3042 free(psz);
3043 }
3044 else
3045 {
3046 printErr(("invalid value in thunk array, neither an ordinal value nor an valid RVA. 0x%08x\n", Thunk.u1.Ordinal));
3047 rc = ERROR_INVALID_ADDRESS;
3048 break;
3049 }
3050
3051 /* next */
3052 ulRVAFirstThunk += sizeof(IMAGE_THUNK_DATA);
3053 ulRVAOrgFirstThunk += sizeof(IMAGE_THUNK_DATA);
3054 }
3055 else
3056 { /* next module */
3057 rc = pImportReader->readAtRVA(ulRVAImportDesc, SSToDS(&ImportDesc), sizeof(ImportDesc));
3058 if (rc == NO_ERROR)
3059 {
3060 ULONG ulRVAFirstThunkPrev = ulRVAFirstThunk;
3061 ul = 0;
3062 ulRVAFirstThunk = ~0UL;
3063 while (rc == NO_ERROR && ImportDesc.Name != 0UL && ImportDesc.FirstThunk != 0UL)
3064 {
3065 if ((ULONG)ImportDesc.FirstThunk < ulRVAFirstThunk
3066 && (ULONG)ImportDesc.FirstThunk > ulRVAFirstThunkPrev)
3067 {
3068 ulRVAFirstThunk = (ULONG)ImportDesc.FirstThunk;
3069 ulRVAOrgFirstThunk = (ULONG)ImportDesc.u.OriginalFirstThunk != 0UL ?
3070 (ULONG)ImportDesc.u.OriginalFirstThunk : (ULONG)ImportDesc.FirstThunk;
3071 ulModuleOrdinal = ImportDesc.Name;
3072 }
3073
3074 /* next */
3075 ul++;
3076 rc = pImportReader->readAtRVA(ulRVAImportDesc + ul * sizeof(ImportDesc), SSToDS(&ImportDesc), sizeof(ImportDesc));
3077 }
3078
3079 if (ulRVAFirstThunk != ~0UL)
3080 { /* modulename */
3081 rc = pImpNameReader->dupString(ulModuleOrdinal, (PSZ*)SSToDS(&psz));
3082 if (rc == NO_ERROR)
3083 {
3084 pszModuleName = NULL;
3085 #ifdef RING0
3086 rc = addModule(psz, (PULONG)SSToDS(&ulModuleOrdinal));
3087
3088 #else
3089 if (hasCustomDll())
3090 {
3091 strcpy((pszModuleName = (char*)SSToDS(szModuleName)), psz);
3092 ulModuleOrdinal = ulCustomModOrdinal;
3093 for (char *pszTmp = pszModuleName; *pszTmp !='\0' && *pszTmp != '.'; pszTmp++)
3094 if (*pszTmp >= 'a' && *pszTmp <= 'z')
3095 *pszTmp += ('A' - 'a');
3096 *pszTmp = '\0';
3097 }
3098 if (!hasCustomDll() || isCustomDllExcluded(pszModuleName))
3099 {
3100 rc = addModule(psz, (PULONG)SSToDS(&ulModuleOrdinal));
3101 szModuleName[0] = '\0';
3102 pszModuleName = NULL;
3103 }
3104 #endif
3105 free(psz);
3106 }
3107 }
3108 else
3109 fImports = FALSE;
3110 }
3111 }
3112 } /* while */
3113 if (rc != NO_ERROR)
3114 break;
3115 }
3116
3117
3118 /* check for fixups for this page. ASSUMES that fixups are sorted and that each chunk covers one page, no more no less. */
3119 #ifndef RING0
3120 if (fBaseRelocs && BaseReloc.VirtualAddress == ulRVAPage)
3121 {
3122 ULONG c = (BaseReloc.SizeOfBlock - sizeof(BaseReloc.SizeOfBlock) - sizeof(BaseReloc.VirtualAddress)) / sizeof(WORD); /* note that sizeof(BaseReloc) is 12 bytes! */
3123 PWORD pawoffFixup = NULL;
3124
3125 if (c != 0)
3126 {
3127 pawoffFixup = (PWORD)malloc((size_t)(c * sizeof(WORD)));
3128 if (pawoffFixup != NULL)
3129 rc = pRelocReader->readAtRVA(ulRVABaseReloc + offsetof(IMAGE_BASE_RELOCATION, TypeOffset),
3130 pawoffFixup, c * sizeof(WORD));
3131 else
3132 rc = ERROR_NOT_ENOUGH_MEMORY;
3133
3134 /* loop thru the baserelocation in this chunk. */
3135 for (ul = 0; ul < c && rc == NO_ERROR; ul++)
3136 {
3137 WORD woffFixup;
3138 ULONG ulTarget;
3139 /* Get relocation type/offset. */
3140 if (pawoffFixup != NULL)
3141 woffFixup = pawoffFixup[ul];
3142
3143 /* Get target. */
3144 rc = pPageReader->readAtRVA(BaseReloc.VirtualAddress + (woffFixup & 0x0FFF),
3145 SSToDS(&ulTarget), sizeof(ulTarget));
3146 if (rc == NO_ERROR)
3147 {
3148 switch (woffFixup >> 12)
3149 {
3150 case IMAGE_REL_BASED_HIGHLOW:
3151 rc = add32OffsetFixup((WORD)(woffFixup & 0x0FFF), ulTarget);
3152 printInfA(("Fixup: 0x%03x target 0x%08x (rc = %d) %s\n",
3153 (woffFixup & 0x0FFF), ulTarget, rc,
3154 pvCrossPageFixup ? "crosspage" : ""));
3155 break;
3156 case IMAGE_REL_BASED_ABSOLUTE: /* ignored! */
3157 break;
3158 default:
3159 printWar(("Unknown/unsupported fixup type!, 0x%1x\n", woffFixup >> 12));
3160 }
3161 }
3162 }
3163 }
3164
3165 /* cleanup */
3166 if (pawoffFixup != NULL)
3167 free(pawoffFixup);
3168
3169 /* break on error */
3170 if (rc != NO_ERROR)
3171 break;
3172
3173 /* read next descriptor if any */
3174 ulRVABaseReloc += BaseReloc.SizeOfBlock;
3175 cbBaseRelocs -= BaseReloc.SizeOfBlock;
3176 if (cbBaseRelocs > 0)
3177 {
3178 rc = pRelocReader->readAtRVA(ulRVABaseReloc, SSToDS(&BaseReloc), sizeof(BaseReloc));
3179 if (rc != NO_ERROR)
3180 break;
3181 }
3182 else
3183 fBaseRelocs = FALSE;
3184 }
3185 #endif /*ifndef RING */
3186
3187 /** next **/
3188 if (ulRVAPage + PAGESIZE >=
3189 (fAllInOneObject && iObj + 1 < cObjects ?
3190 paObjects[iObj + 1].ulRVA : paObjects[iObj].ulRVA + paObjects[iObj].cbVirtual)
3191 )
3192 { /* object++ */
3193 iObj++;
3194 if (iObj < cObjects)
3195 ulRVAPage = paObjects[iObj].ulRVA;
3196 }
3197 else /* page++ */
3198 ulRVAPage += PAGESIZE;
3199 Yield();
3200 } /* The Loop! */
3201
3202
3203 /* insert final fixup page struct */
3204 if (rc == NO_ERROR)
3205 rc = addPageFixupEntry(TRUE);
3206
3207 /* finished! - cleanup! */
3208 #ifndef RING0
3209 if (pPageReader != NULL)
3210 delete pPageReader;
3211 if (pRelocReader != NULL)
3212 delete pRelocReader;
3213 #endif
3214 if (pImportReader != NULL)
3215 delete pImportReader;
3216 if (pImpNameReader != NULL)
3217 delete pImpNameReader;
3218 if (pImpThunkReader != NULL)
3219 delete pImpThunkReader;
3220
3221 /* Release unused memory in fixup and import structures. */
3222 if (rc == NO_ERROR)
3223 {
3224 finalizeImportNames();
3225 finalizeFixups();
3226 }
3227 #ifdef RING0
3228 /* load base relocations... */
3229 if (rc == NO_ERROR)
3230 return loadBaseRelocations();
3231 #endif
3232 return rc;
3233}
3234
3235
3236/**
3237 * Convert exports to LX entries and resident name table.
3238 * It also creates the modulename.
3239 * @returns Return code. (NO_ERROR)
3240 * @sketch IF valid pointers THEN - nothing to do - return successfully.
3241 * Check that the NtHdr is valid.
3242 * Init datastructues.
3243 * Add modulename to resident name table with ordinal 0.
3244 * IF empty export directory THEN finalizeExports and return successfully.
3245 * Create buffered readers.
3246 * Read Export Directory.
3247 * Convert Address of Functions to LX entry points:
3248 * LOOP thru all entries in the AddressOfFunctions array
3249 * BEGIN
3250 * Read entry. (ulRVA)
3251 * IF forwarder THEN add forwarder.
3252 * IF not forwarder THEN add entry.
3253 * END
3254 *
3255 * Convert function names to resident names (if any names of course).
3256 * LOOP thru all entries in the two parallell arrays AddressOfNames and AddressOfNameOrdinals
3257 * BEGIN
3258 * Read entries from both tables.
3259 * Read Name.
3260 * Add resident name.
3261 * END
3262 *
3263 * Add last entry.
3264 * Delete readers.
3265 * Finalize Exports.
3266 * return return code.
3267 *
3268 * @status completely implemented.
3269 * @author knut st. osmundsen
3270 */
3271ULONG Pe2Lx::makeExports()
3272{
3273 IMAGE_EXPORT_DIRECTORY ExpDir; /* Export directory struct used when reading the export directory. */
3274 BufferedRVARead *pFATFOTReader; /* Buffered reader for function address table and function ordinal table reads. */
3275 BufferedRVARead *pFNTReader; /* Buffered reader for function name table reads. */
3276 BufferedRVARead *pNameReader; /* Buffered reader for function name and forwarder 'dll.function' reads. */
3277 ULONG ulRVAExportDir;
3278 APIRET rc;
3279 PSZ psz;
3280
3281
3282 /* check if valid pointers - nothing to do - return successfully.*/
3283 if (pEntryBundles != NULL && pachResNameTable != NULL)
3284 return NO_ERROR;
3285
3286 /* Check that the NtHdr is valid. */
3287 rc = loadNtHeaders();
3288 if (rc != NO_ERROR)
3289 return rc;
3290
3291 /* Init datastructues. */
3292 rc = initEntry();
3293 if (rc != NO_ERROR)
3294 return rc;
3295
3296 /* Add modulename to resident name table with ordinal 0. */
3297 rc = addResName(0UL, pszModuleName, ~0UL);
3298 if (rc != NO_ERROR)
3299 return rc;
3300
3301 /* Check if empty export directory. */
3302 if (!(pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size > 0UL
3303 &&
3304 (ulRVAExportDir = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) > 0UL
3305 &&
3306 ulRVAExportDir < pNtHdrs->OptionalHeader.SizeOfImage))
3307 { /* no exports */
3308 finalizeExports();
3309 return rc;
3310 }
3311
3312 printInf(("\n"));
3313 printInf(("Make exports\n"));
3314 printInf(("\n"));
3315
3316 /* Create buffered readers. */
3317 pFATFOTReader = new BufferedRVARead(hFile, cObjects, paObjects);
3318 pFNTReader = new BufferedRVARead(hFile, cObjects, paObjects);
3319 pNameReader = new BufferedRVARead(hFile, cObjects, paObjects);
3320 if (pFATFOTReader != NULL && pFNTReader != NULL && pNameReader != NULL)
3321 {
3322 /* Read export directory. */
3323 rc = pFATFOTReader->readAtRVA(ulRVAExportDir, SSToDS(&ExpDir), sizeof(ExpDir));
3324 if (rc == NO_ERROR)
3325 {
3326 ULONG ulRVA;
3327 ULONG ul;
3328
3329 /* (try) optimize diskreads. */
3330 if ((ULONG)ExpDir.AddressOfFunctions < ulRVAExportDir + BUFFEREDRVAREADER_BUFFERSIZE)
3331 *pFNTReader = *pFATFOTReader;
3332 *pNameReader = *pFATFOTReader;
3333
3334 /* Convert Address of Functions to LX entry points. */
3335 for (ul = 0; ul < ExpDir.NumberOfFunctions && rc == NO_ERROR; ul++)
3336 {
3337 rc = pFATFOTReader->readAtRVA((ULONG)ExpDir.AddressOfFunctions + sizeof(ULONG)*ul,
3338 SSToDS(&ulRVA), sizeof(ulRVA));
3339 /* empty? */
3340 if (ulRVA != 0UL)
3341 {
3342 BOOL fForwarder = FALSE;
3343
3344 /* forwarder? ulRVA within export directory. */
3345 if (ulRVA > pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
3346 && ulRVA < pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
3347 + pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size
3348 )
3349 { /* forwarder!(?) */
3350 PSZ pszDll;
3351 PSZ pszFn;
3352 rc = pNameReader->dupString(ulRVA, (PSZ*)SSToDS(&pszDll));
3353 if (rc != NO_ERROR)
3354 break;
3355 pszFn = strchr(pszDll, '.');
3356 if (pszFn != NULL && strlen(pszDll) != 0 && strlen(pszFn) != 0)
3357 {
3358 *pszFn++ = '\0';
3359 rc = addForwarderEntry(ul + ExpDir.Base, pszDll, pszFn);
3360 fForwarder = TRUE;
3361 }
3362 free(pszDll);
3363 }
3364
3365 /* non-forwarder export? */
3366 if (!fForwarder)
3367 rc = addEntry(ul + ExpDir.Base, ulRVA);
3368 }
3369 } /* for loop - export --> entry */
3370 if (rc != NO_ERROR)
3371 printErr(("export --> entry loop failed! ul = %d rc = %d\n", ul, rc));
3372 Yield();
3373
3374 /* Convert function names to resident names. */
3375 if (rc == NO_ERROR && ExpDir.NumberOfNames > 0UL)
3376 {
3377 if ((ULONG)ExpDir.AddressOfNameOrdinals != 0UL && (ULONG)ExpDir.AddressOfNames != 0UL
3378 && (ULONG)ExpDir.AddressOfNameOrdinals < pNtHdrs->OptionalHeader.SizeOfImage
3379 && (ULONG)ExpDir.AddressOfNames < pNtHdrs->OptionalHeader.SizeOfImage
3380 )
3381 {
3382 WORD usOrdinal;
3383
3384 for (ul = 0; ul < ExpDir.NumberOfNames && rc == NO_ERROR; ul++)
3385 {
3386 rc = pFNTReader->readAtRVA((ULONG)ExpDir.AddressOfNames + ul * sizeof(ULONG),
3387 SSToDS(&ulRVA), sizeof(ulRVA));
3388 if (rc != NO_ERROR)
3389 break;
3390 rc = pFATFOTReader->readAtRVA((ULONG)ExpDir.AddressOfNameOrdinals + ul * sizeof(WORD),
3391 SSToDS(&usOrdinal), sizeof(usOrdinal));
3392 if (rc != NO_ERROR)
3393 break;
3394 usOrdinal += ExpDir.Base;
3395 rc = pNameReader->dupString(ulRVA, (PSZ*)SSToDS(&psz));
3396 if (rc != NO_ERROR)
3397 break;
3398 rc = addResName(usOrdinal, psz, ~0UL);
3399 free(psz);
3400 Yield();
3401 }
3402 if (rc != NO_ERROR)
3403 printErr(("FnNames --> ResNames loop failed! ul = %d rc = %d\n", ul, rc));
3404 }
3405 else
3406 {
3407 printErr(("NumberOfNames = %d but AddressOfNames = 0x%08x and AddressOfNameOrdinals = 0x%08x, invalid RVA(s)!\n",
3408 ExpDir.AddressOfNames, ExpDir.AddressOfNameOrdinals));
3409 rc = ERROR_BAD_EXE_FORMAT;
3410 } /* endifelse: 'Names' integrity check */
3411
3412 /* Add last entry. */
3413 if (rc == NO_ERROR)
3414 rc = addLastEntry();
3415
3416 } /* endif: name */
3417 }
3418 }
3419 else
3420 rc = ERROR_NOT_ENOUGH_MEMORY;
3421
3422 /* delete readers */
3423 if (pFATFOTReader != NULL)
3424 delete pFATFOTReader;
3425 if (pFNTReader != NULL)
3426 delete pFNTReader;
3427 if (pNameReader != NULL)
3428 delete pNameReader;
3429
3430 /* Release unused memory in export structures */
3431 if (rc == NO_ERROR)
3432 finalizeExports();
3433
3434 return rc;
3435}
3436
3437
3438/**
3439 * Load the NT headers from disk if they're not present.
3440 * Call this function to make sure that pNtHdrs is valid.
3441 * @returns Error code. (NO_ERROR == success)
3442 * @status Competely implemented; tested.
3443 * @author knut st. osmundsen
3444 * @remark Minor error: Don't read more datadirectory entries than defined in the header files.
3445 * This is not a problem since we'll only use some of the first ones.
3446 */
3447ULONG Pe2Lx::loadNtHeaders()
3448{
3449 APIRET rc;
3450 if (pNtHdrs != NULL)
3451 return NO_ERROR;
3452 pNtHdrs = (PIMAGE_NT_HEADERS)malloc(sizeof(IMAGE_NT_HEADERS));
3453 if (pNtHdrs == NULL)
3454 return ERROR_NOT_ENOUGH_MEMORY;
3455 rc = ReadAt(hFile, offNtHeaders, pNtHdrs, sizeof(IMAGE_NT_HEADERS));
3456 if (rc != NO_ERROR)
3457 {
3458 free(pNtHdrs);
3459 pNtHdrs = NULL;
3460 }
3461 return rc;
3462}
3463
3464
3465/**
3466 * Releases memory used by the pNtHdrs pointer.
3467 * @status completely implemented; tested.
3468 * @author knut st. osmundsen
3469 */
3470VOID Pe2Lx::releaseNtHeaders()
3471{
3472 if (pNtHdrs != NULL)
3473 {
3474 free(pNtHdrs);
3475 pNtHdrs = NULL;
3476 }
3477}
3478
3479
3480/**
3481 * Loads the baserelocations from the PE-file.
3482 * @returns NO_ERROR on success, appropriate error message.
3483 * @sketch
3484 * @status completely implemented; untestd.
3485 * @author knut st. osmundsen
3486 */
3487ULONG Pe2Lx::loadBaseRelocations()
3488{
3489 APIRET rc;
3490 ULONG ulRVA;
3491
3492 /* ? */
3493 rc = loadNtHeaders();
3494 if (rc != NO_ERROR)
3495 return rc;
3496 /* end ? */
3497
3498 ulRVA = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;
3499 cbBaseRelocs = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
3500
3501 if (ulRVA > 0UL && cbBaseRelocs > 0UL && ulRVA < ~0UL && cbBaseRelocs < ~0UL)
3502 {
3503 pBaseRelocs = (PIMAGE_BASE_RELOCATION)smalloc((size_t)cbBaseRelocs);
3504 if (pBaseRelocs != NULL)
3505 {
3506 rc = readAtRVA(ulRVA, pBaseRelocs, cbBaseRelocs);
3507 if (rc != NO_ERROR)
3508 {
3509 printErr(("readAtRVA(0x%08x, 0x%08x, 0x%08x) failed with rc = %d\n",
3510 ulRVA, pBaseRelocs, cbBaseRelocs, rc));
3511 sfree(pBaseRelocs);
3512 pBaseRelocs = NULL;
3513 }
3514 #ifdef DEBUG
3515 else
3516 {
3517 PIMAGE_BASE_RELOCATION pbrCur = pBaseRelocs;
3518 while ((void*)pbrCur < (void*)((unsigned)pBaseRelocs + cbBaseRelocs)
3519 && pbrCur->SizeOfBlock >= 8)
3520 {
3521 if ((unsigned)pbrCur->SizeOfBlock + (unsigned)pbrCur > (unsigned)pBaseRelocs + cbBaseRelocs)
3522 printErr(("Debug-check - Chunk is larger than the base relocation directory. "
3523 "SizeOfBlock=0x%08x, VirtualAddress=0x%08x\n",
3524 pbrCur->SizeOfBlock, pbrCur->VirtualAddress));
3525 pbrCur = (PIMAGE_BASE_RELOCATION)((unsigned)pbrCur + pbrCur->SizeOfBlock);
3526 }
3527 }
3528 #endif
3529 return rc;
3530 }
3531 else
3532 {
3533 printErr(("rmalloc failed when allocating memory for pBaseReloc, cbSize=0x%x(%d)\n",
3534 cbBaseRelocs, cbBaseRelocs));
3535 rc = ERROR_NOT_ENOUGH_MEMORY;
3536 }
3537 }
3538 else
3539 {
3540 pBaseRelocs = NULL;
3541 cbBaseRelocs = 0;
3542 }
3543
3544 return NO_ERROR;
3545}
3546
3547
3548/**
3549 * Initiates the fixup data members of this object.
3550 * Called from makeFixup and initEntry().
3551 * Checks for forwarder stuff. If forwarders present, the import module and procdure name tables are not
3552 * freed - initEntry have done that.
3553 * @returns NO_ERROR.
3554 * @status completely implemented.
3555 * @author knut st. osmundsen
3556 */
3557ULONG Pe2Lx::initFixups()
3558{
3559 if (paulFixupPageTable != NULL)
3560 {
3561 free(paulFixupPageTable);
3562 paulFixupPageTable = NULL;
3563 }
3564 cFixupPTEntries = cFPTEAllocated = 0UL;
3565 if (pFixupRecords != NULL)
3566 {
3567 free(pFixupRecords);
3568 pFixupRecords = NULL;
3569 }
3570 offCurFixupRec = cbFRAllocated = 0UL;
3571 if (pvCrossPageFixup != NULL)
3572 {
3573 free(pvCrossPageFixup);
3574 pvCrossPageFixup = NULL;
3575 }
3576 cbCrossPageFixup = 0UL;
3577
3578 /* if there aren't forwarders we may safely free the Import Module/Procedure name tables */
3579 if (!fForwarders)
3580 {
3581 if (pachImpModuleNames != NULL)
3582 {
3583 free(pachImpModuleNames);
3584 pachImpModuleNames = NULL;
3585 }
3586 offCurImpModuleName = cchIMNAllocated = 0UL;
3587 if (pachImpFunctionNames != NULL)
3588 {
3589 free(pachImpFunctionNames);
3590 pachImpFunctionNames = NULL;
3591 }
3592 offCurImpFunctionName = cchIFNAllocated = 0UL;
3593 }
3594 return NO_ERROR;
3595}
3596
3597
3598/**
3599 * Adds a page fixup entry to the fixup page table array (paFixupPageTable).
3600 * @returns NO_ERROR on success. Errorcode on error.
3601 * @param fLast TRUE: last entry
3602 * FALSE: not last (default)
3603 * @sketch IF not enough memory THEN
3604 * BEGIN
3605 * IF no memory allocated THEN count pages and allocate memory for all pages (+1).
3606 * ELSE increase amount of memory according to fLast.
3607 * END
3608 *
3609 * Set offset of current entry to current Fixup Record Array offset.
3610 * IF last entry (fLast) THEN
3611 * IF Cross Page Fixup THEN error!
3612 * ELSE
3613 * IF Cross Page Fixup THEN check if enough memory and add it.
3614 * return successfully.
3615 *
3616 * @status Completely implemented; tested.
3617 * @author knut st. osmundsen
3618 * @remark Fixup Page Table format (from Linear eXecutable Module Format,lxspec.inf, Rev.8):
3619 *
3620 * The Fixup Page Table provides a simple mapping of a logical page number to an offset
3621 * into the Fixup Record Table for that page. This table is parallel to the Object Page
3622 * Table, except that there is one additional entry in this table to indicate the end of
3623 * the Fixup Record Table.
3624 * The format of each entry is:
3625 *
3626 * ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
3627 * Logical Page #1 ³ OFFSET FOR PAGE #1 ³
3628 * ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŽ
3629 * Logical Page #2 ³ OFFSET FOR PAGE #2 ³
3630 * ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
3631 * . . .
3632 * ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
3633 * Logical Page #n ³ OFFSET FOR PAGE #n ³
3634 * ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŽ
3635 * ³OFF TO END OF FIXUP REC³ This is equal to:
3636 * ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ Offset for page #n + Size
3637 * of fixups for page #n
3638 * Fixup Page Table
3639 *
3640 * OFFSET FOR PAGE # = DD Offset for fixup record for this page. This field specifies
3641 * the offset, from the beginning of the fixup record table, to the first fixup record
3642 * for this page.
3643 *
3644 * OFF TO END OF FIXUP REC = DD Offset to the end of the fixup records. This field
3645 * specifies the offset following the last fixup record in the fixup record table. This
3646 * is the last entry in the fixup page table. The fixup records are kept in order by
3647 * logical page in the fixup record table. This allows the end of each page's fixup
3648 * records is defined by the offset for the next logical page's fixup records. This last
3649 * entry provides support of this mechanism for the last page in the fixup page table.
3650 *
3651 */
3652ULONG Pe2Lx::addPageFixupEntry(BOOL fLast/* = FALSE*/)
3653{
3654 /* enough memory? */
3655 if (cFixupPTEntries >= cFPTEAllocated)
3656 {
3657 if (cFPTEAllocated == 0UL)
3658 { /* first call */
3659 ULONG cPages = getCountOfPages();
3660 if (cPages == 0UL && !fLast)
3661 return ERROR_INTERNAL_PROCESSING_ERROR;
3662
3663 paulFixupPageTable = (PULONG)malloc((size_t)(cPages + 1UL) * sizeof(ULONG));
3664 if (paulFixupPageTable != NULL)
3665 cFPTEAllocated = cPages + 1UL;
3666 else
3667 return ERROR_NOT_ENOUGH_MEMORY;
3668 }
3669 else
3670 { /* hmm - algorithm for determin array size incorrect? */
3671 printErr(("More fixup pages than calculated!\n"));
3672 return ERROR_BAD_EXE_FORMAT;
3673 }
3674 }
3675
3676 /* add new entry */
3677 paulFixupPageTable[cFixupPTEntries++] = offCurFixupRec;
3678 if (fLast)
3679 { /* final entry */
3680 /* Error check */
3681 if (pvCrossPageFixup != NULL)
3682 {
3683 printErr(("Cross page fixup when fLast is set!\n"));
3684 return ERROR_INTERNAL_PROCESSING_ERROR;
3685 }
3686 }
3687 else
3688 { /* just another entry */
3689 /* cross page fixup? */
3690 if (pvCrossPageFixup != NULL)
3691 {
3692 AllocateMoreMemory(offCurFixupRec + cbCrossPageFixup > cbFRAllocated,
3693 pFixupRecords, PVOID, cbFRAllocated, PAGESIZE, PAGESIZE)
3694
3695 memcpy(&((PCHAR)pFixupRecords)[offCurFixupRec],
3696 pvCrossPageFixup, cbCrossPageFixup);
3697 offCurFixupRec += cbCrossPageFixup;
3698 free(pvCrossPageFixup);
3699 pvCrossPageFixup = NULL;
3700 }
3701 }
3702 return NO_ERROR;
3703}
3704
3705
3706/**
3707 * Add 32-bit offset fixup.
3708 * @returns NO_ERROR
3709 * ERROR_NOT_ENOUGH_MEMORY
3710 * ERROR_BAD_EXE_FORMAT
3711 * @param offSource Source offset into the current page.
3712 * @param ulTarget Target Pointer.
3713 * @sketch IF not enough memory THEN allocate some more memory.
3714 * Find target object and offset into target object for the given target address (ulTarget).
3715 * Fill in fixup record.
3716 * Increment the size of the fixup records array (offCurFixupRec).
3717 * IF cross page fixup THEN
3718 * BEGIN
3719 * Allocate memory for the cross page fixup record.
3720 * Copy the fixup record we just created into the memory of the cross page fixup record..
3721 * Substract the size of a Page from the source offset (r32_soff) in the cross page fixup record.
3722 * END
3723 * End successfully.
3724 * @status completely implemented.
3725 * @author knut st. osmundsen
3726 * @remark Internal Fixup Record format (from Linear eXecutable Module Format,lxspec.inf, Rev.8):
3727 *
3728 * ÚÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄ¿
3729 * 00h ³ SRC ³FLAGS³SRCOFF/CNT*³
3730 * ÃÄÄÄÄÄÁÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄ¿
3731 * 03h/04h ³ OBJECT * ³ TRGOFF * @ ³
3732 * ÃÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄŽ
3733 * ³ SRCOFF1 @ ³ . . . ³ SRCOFFn @ ³
3734 * ÀÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÙ
3735 *
3736 * * These fields are variable size.
3737 * @ These fields are optional.
3738 *
3739 * Internal Fixup Record
3740 *
3741 * OBJECT = D[B|W] Target object number. This field is an index into the current
3742 * module's Object Table to specify the target Object. It is a Byte value when the
3743 * '16-bit Object Number/Module Ordinal Flag' bit in the target flags field is
3744 * clear and a Word value when the bit is set.
3745 *
3746 * TRGOFF = D[W|D] Target offset. This field is an offset into the specified target
3747 * Object. It is not present when the Source Type specifies a 16-bit Selector fixup.
3748 * It is a Word value when the '32-bit Target Offset Flag' bit in the target flags
3749 * field is clear and a Dword value when the bit is set.
3750 * ---------------------
3751 * This code got a bit dirty while trying to optimize memory usage.
3752 */
3753ULONG Pe2Lx::add32OffsetFixup(WORD offSource, ULONG ulTarget)
3754{
3755 struct r32_rlc *prlc;
3756 ULONG iObj; /* target object. */
3757 ULONG cbFixup; /* size of the fixup record. */
3758
3759 /* enough memory? */
3760 AllocateMoreMemory(offCurFixupRec + RINTSIZE32 > cbFRAllocated,
3761 pFixupRecords, PVOID, cbFRAllocated, PAGESIZE, PAGESIZE)
3762
3763 /* target object and offset */
3764 if (ulTarget >= ulImageBase)
3765 {
3766 ulTarget -= ulImageBase; /* ulTarget is now an RVA */
3767 iObj = 0UL;
3768 while (iObj < cObjects
3769 && ulTarget >= (iObj + 1 < cObjects ? paObjects[iObj+1].ulRVA
3770 : ALIGN(paObjects[iObj].cbVirtual, PAGESIZE) + paObjects[iObj].ulRVA)
3771 )
3772 iObj++;
3773 if (iObj < cObjects)
3774 {
3775 if (!fAllInOneObject)
3776 {
3777 ulTarget -= paObjects[iObj].ulRVA;
3778 iObj++; /* one based object number. */
3779 }
3780 else
3781 iObj = 1UL;
3782 }
3783 else
3784 {
3785 printErr(("Invalid target RVA, 0x%08x.\n", ulTarget));
3786 return ERROR_BAD_EXE_FORMAT;
3787 }
3788 }
3789 else
3790 {
3791 printErr(("Invalid target address, 0x%08x.\n", ulTarget));
3792 return ERROR_BAD_EXE_FORMAT;
3793 }
3794 /* ulTarget is now an offset into the target object. */
3795
3796 /* fill in fixup record */
3797 cbFixup = 7UL;
3798 prlc = (struct r32_rlc *)((ULONG)pFixupRecords + offCurFixupRec);
3799 prlc->nr_stype = NROFF32;
3800 prlc->nr_flags = NRRINT;
3801 if (iObj > 255UL)
3802 {
3803 prlc->nr_flags |= NR16OBJMOD;
3804 cbFixup++;
3805 }
3806 if (ulTarget > 65535UL)
3807 {
3808 prlc->nr_flags |= NR32BITOFF;
3809 cbFixup += 2;
3810 }
3811
3812 prlc->r32_soff = (USHORT)offSource;
3813 prlc->r32_objmod = (USHORT)iObj;
3814 if (prlc->nr_flags & NR16OBJMOD)
3815 prlc->r32_target.intref.offset32 = ulTarget;
3816 else
3817 ((struct r32_rlc*)((ULONG)prlc - 1))->r32_target.intref.offset32 = ulTarget;
3818
3819 /* commit fixup */
3820 offCurFixupRec += cbFixup;
3821
3822 /* cross page fixup? */
3823 if (offSource > PAGESIZE - 4UL)
3824 { /* cross page fixup! */
3825 if (pvCrossPageFixup != NULL)
3826 {
3827 printWar(("A cross page fixup allready exists!\n"));
3828 free(pvCrossPageFixup);
3829 }
3830 pvCrossPageFixup = malloc((size_t)cbFixup);
3831 if (pvCrossPageFixup != NULL)
3832 {
3833 memcpy(pvCrossPageFixup, prlc, (size_t)cbFixup);
3834 cbCrossPageFixup = cbFixup;
3835 ((struct r32_rlc *)pvCrossPageFixup)->r32_soff -= (USHORT)PAGESIZE;
3836 }
3837 else
3838 return ERROR_NOT_ENOUGH_MEMORY;
3839 }
3840
3841 return NO_ERROR;
3842}
3843
3844
3845/**
3846 * Add 32-bit ordinal import fixup.
3847 * @returns NO_ERROR
3848 * ERROR_NOT_ENOUGH_MEMORY
3849 * @param offSource Offset of the fixup reltaive to the start of the page.
3850 * @param ulModuleOrdinal Module ordinal. Ordinal into the import module name table. (1 based!)
3851 * @param ulFunctionOrdinal Function ordinal. Number of the export which is to be imported from
3852 * the module given by ulModuleOrdinal.
3853 * @param pszModuleName The name of the module or NULL. For custombuild only.
3854 * @sketch IF not enough memory for the fixup THEN (try) allocate more memory
3855 * Fill in fixup record.
3856 * Increment the size of the fixup records array (offCurFixupRec).
3857 * IF cross page fixup THEN
3858 * BEGIN
3859 * Allocate memory for the cross page fixup record.
3860 * Copy the fixup record we just created into the memory of the cross page fixup record..
3861 * Substract the size of a Page from the source offset (r32_soff) in the cross page fixup record.
3862 * END
3863 * End successfully.
3864 * @status completely implemented.
3865 * @author knut st. osmundsen
3866 * @remark Internal Fixup Record format (from Linear eXecutable Module Format,lxspec.inf, Rev.8):
3867 * ÚÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄ¿
3868 * 00h ³ SRC ³FLAGS³SRCOFF/CNT*³
3869 * ÃÄÄÄÄÄÁÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
3870 * 03h/04h ³ MOD ORD# *³IMPORT ORD*³ ADDITIVE * @ ³
3871 * ÃÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÙ
3872 * ³ SRCOFF1 @ ³ . . . ³ SRCOFFn @ ³
3873 * ÀÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÙ
3874 *
3875 * * These fields are variable size.
3876 * @ These fields are optional.
3877 *
3878 * Import by Ordinal Fixup Record
3879 *
3880 * MOD ORD # = D[B|W] Ordinal index into the Import Module Name Table. This value
3881 * is an ordered index in to the Import Module Name Table for the module containing
3882 * the procedure entry point. It is a Byte value when the '16-bit Object Number/Module
3883 * Ordinal' Flag bit in the target flags field is clear and a Word value when the bit
3884 * is set. The loader creates a table of pointers with each pointer in the table
3885 * corresponds to the modules named in the Import Module Name Table. This value is used
3886 * by the loader to index into this table created by the loader to locate the referenced module.
3887 *
3888 * IMPORT ORD = D[B|W|D] Imported ordinal number. This is the imported procedure's
3889 * ordinal number. It is a Byte value when the '8-bit Ordinal' bit in the target flags
3890 * field is set. Otherwise it is a Word value when the '32-bit Target Offset Flag' bit
3891 * in the target flags field is clear and a Dword value when the bit is set.
3892 *
3893 * ADDITIVE = D[W|D] Additive fixup value. This field exists in the fixup record only
3894 * when the 'Additive Fixup Flag' bit in the target flags field is set. When the
3895 * 'Additive Fixup Flag' is clear the fixup record does not contain this field and
3896 * is immediately followed by the next fixup record (or by the source offset list
3897 * for this fixup record). This value is added to the address derived from the target
3898 * entry point. This field is a Word value when the '32-bit Additive Flag' bit in the
3899 * target flags field is clear and a Dword value when the bit is set.
3900 *
3901 * ---------------------
3902 * This code got a bit dirty while trying to optimize memory usage.
3903 *
3904 */
3905ULONG Pe2Lx::add32OrdImportFixup(WORD offSource, ULONG ulModuleOrdinal, ULONG ulFunctionOrdinal, PCSZ pszModuleName)
3906{
3907 struct r32_rlc *prlc;
3908 ULONG cbFixup; /* size of the fixup record. */
3909
3910 #ifndef RING0
3911 if (pszModuleName != NULL && *pszModuleName && hasCustomDll() && !isCustomDllExcluded(pszModuleName))
3912 {
3913 /* Search for "DLL.EXPORT" in the translation file. */
3914 char szSearchString[256];
3915 sprintf(szSearchString, "%s.%d ", pszModuleName, ulFunctionOrdinal);
3916 const char * pszFound = strstr(options.pszCustomExports, szSearchString);
3917 if (pszFound)
3918 {
3919 /* Following the DLL.EXPORT is a @ordinal. */
3920 while (*pszFound != '@')
3921 pszFound++;
3922 return add32OrdImportFixup(offSource, ulModuleOrdinal, atoi(++pszFound), NULL);
3923 }
3924 else
3925 {
3926 printf("Error: Export %s not found in table.\n\n", szSearchString);
3927 return ERROR_MOD_NOT_FOUND;
3928 }
3929 }
3930 #else
3931 NOREF(pszModuleName);
3932 #endif
3933
3934 /* enough memory? */
3935 AllocateMoreMemory(offCurFixupRec + 10 > cbFRAllocated /* 10 is max size */,
3936 pFixupRecords, PVOID, cbFRAllocated, PAGESIZE, PAGESIZE)
3937
3938 /* fill in fixup record */
3939 cbFixup = 7UL;
3940 prlc = (struct r32_rlc *)((ULONG)pFixupRecords + offCurFixupRec);
3941 prlc->nr_stype = NROFF32;
3942 prlc->nr_flags = NRRORD;
3943 if (ulModuleOrdinal > 255UL)
3944 {
3945 prlc->nr_flags |= NR16OBJMOD;
3946 cbFixup++;
3947 }
3948 #if 0 /* lxdump.exe (from Hacker's View release 5.66) don't support this. */
3949 if (ulFunctionOrdinal < 256UL)
3950 {
3951 prlc->nr_flags |= NR8BITORD;
3952 cbFixup--;
3953 }
3954 #endif
3955 else if (ulFunctionOrdinal > 65535UL)
3956 {
3957 prlc->nr_flags |= NR32BITOFF;
3958 cbFixup += 2;
3959 }
3960 prlc->r32_soff = (USHORT)offSource;
3961 prlc->r32_objmod = (USHORT)ulModuleOrdinal;
3962 if (prlc->nr_flags & NR16OBJMOD)
3963 prlc->r32_target.intref.offset32 = ulFunctionOrdinal;
3964 else
3965 ((struct r32_rlc*)((ULONG)prlc - 1))->r32_target.intref.offset32 = ulFunctionOrdinal;
3966
3967 /* commit fixup */
3968 offCurFixupRec += cbFixup;
3969
3970 /* cross page fixup? */
3971 if (offSource > PAGESIZE - 4UL)
3972 { /* cross page fixup! */
3973 if (pvCrossPageFixup != NULL)
3974 {
3975 printWar(("A cross page fixup allready exists!\n"));
3976 free(pvCrossPageFixup);
3977 }
3978 pvCrossPageFixup = malloc((size_t)cbFixup);
3979 if (pvCrossPageFixup != NULL)
3980 {
3981 memcpy(pvCrossPageFixup, prlc, (size_t)cbFixup);
3982 cbCrossPageFixup = cbFixup;
3983 ((struct r32_rlc *)pvCrossPageFixup)->r32_soff -= (USHORT)PAGESIZE;
3984 }
3985 else
3986 return ERROR_NOT_ENOUGH_MEMORY;
3987 }
3988
3989 printInfA(("offset=0x%03x modordinal=%d fnord=%4d cbFixup=%d %s\n",
3990 offSource, ulModuleOrdinal, ulFunctionOrdinal, cbFixup, pvCrossPageFixup ? "crosspage" : ""));
3991
3992 return NO_ERROR;
3993}
3994
3995
3996/**
3997 *
3998 * @returns NO_ERROR on success. Errorcode on error.
3999 * @param offSource Fixup offset relative to page.
4000 * @param ulModuleOrdinal Module ordinal in the import module name table (1 based!)
4001 * @param pszFnName Pointer to a readonly function name for the imported function.
4002 * @param pszModuleName The name of the module or NULL. For custombuild only.
4003 * @sketch IF not enough memory for the fixup THEN (try) allocate more memory
4004 * Add function name to the import procedure name table.
4005 * Fill in fixup record.
4006 * Increment the size of the fixup records array (offCurFixupRec).
4007 * IF cross page fixup THEN
4008 * BEGIN
4009 * Allocate memory for the cross page fixup record.
4010 * Copy the fixup record we just created into the memory of the cross page fixup record..
4011 * Substract the size of a Page from the source offset (r32_soff) in the cross page fixup record.
4012 * END
4013 * End successfully.
4014 * @status completely implemented.
4015 * @author knut st. osmundsen
4016 * @remark Internal Fixup Record format (from Linear eXecutable Module Format,lxspec.inf, Rev.8):
4017 * ÚÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄ¿
4018 * 00h ³ SRC ³FLAGS³SRCOFF/CNT*³
4019 * ÃÄÄÄÄÄÁÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
4020 * 03h/04h ³ MOD ORD# *³ PROCEDURE NAME OFFSET*³ ADDITIVE * @ ³
4021 * ÃÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
4022 * ³ SRCOFF1 @ ³ . . . ³ SRCOFFn @ ³
4023 * ÀÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÙ
4024 *
4025 * * These fields are variable size.
4026 * @ These fields are optional.
4027 *
4028 * Import by Name Fixup Record
4029 *
4030 * MOD ORD # = D[B|W] Ordinal index into the Import Module Name Table. This value is
4031 * an ordered index in to the Import Module Name Table for the module containing the
4032 * procedure entry point. It is a Byte value when the '16-bit Object Number/Module Ordinal'
4033 * Flag bit in the target flags field is clear and a Word value when the bit is set. The
4034 * loader creates a table of pointers with each pointer in the table corresponds to the
4035 * modules named in the Import Module Name Table. This value is used by the loader to
4036 * index into this table created by the loader to locate the referenced module.
4037 *
4038 * PROCEDURE NAME OFFSET = D[W|D] Offset into the Import Procedure Name Table. This
4039 * field is an offset into the Import Procedure Name Table. It is a Word value when
4040 * the '32-bit Target Offset Flag' bit in the target flags field is clear and a Dword
4041 * value when the bit is set.
4042 *
4043 * ADDITIVE = D[W|D] Additive fixup value. This field exists in the fixup record only
4044 * when the 'Additive Fixup Flag' bit in the target flags field is set. When the
4045 * 'Additive Fixup Flag' is clear the fixup record does not contain this field and is
4046 * immediately followed by the next fixup record (or by the source offset list for this
4047 * fixup record). This value is added to the address derived from the target entry point.
4048 * This field is a Word value when the '32-bit Additive Flag' bit in the target flags
4049 * field is clear and a Dword value when the bit is set.
4050 *
4051 * ---------------------
4052 * This code got a bit dirty while trying to optimize memory usage.
4053 *
4054 */
4055ULONG Pe2Lx::add32NameImportFixup(WORD offSource, ULONG ulModuleOrdinal, PCSZ pszFnName, PCSZ pszModuleName)
4056{
4057 APIRET rc;
4058 struct r32_rlc *prlc;
4059 ULONG cbFixup; /* size of the fixup record. */
4060 ULONG offFnName;
4061
4062 #ifndef RING0
4063 if (pszModuleName != NULL && *pszModuleName && hasCustomDll() && !isCustomDllExcluded(pszModuleName))
4064 {
4065 /* Search for "DLL.EXPORT" in the translation file. */
4066 char szSearchString[256];
4067 sprintf(szSearchString, "%s.%s ", pszModuleName, pszFnName);
4068 const char * pszFound = strstr(options.pszCustomExports, szSearchString);
4069 if (pszFound)
4070 {
4071 /* Following the DLL.EXPORT is a @ordinal. */
4072 while (*pszFound != '@')
4073 pszFound++;
4074 return add32OrdImportFixup(offSource, ulModuleOrdinal, atoi(++pszFound), NULL);
4075 }
4076 else
4077 {
4078 printf("Error: Export %s not found in table.\n\n", szSearchString);
4079 return ERROR_MOD_NOT_FOUND;
4080 }
4081 }
4082 #else
4083 NOREF(pszModuleName);
4084 #endif
4085
4086 /* enough memory? */
4087 AllocateMoreMemory(offCurFixupRec + 10 > cbFRAllocated /* 10 is max size */,
4088 pFixupRecords, PVOID, cbFRAllocated, PAGESIZE, PAGESIZE)
4089
4090 rc = addImportFunctionName(pszFnName, (PULONG)SSToDS(&offFnName));
4091 if (rc != NO_ERROR)
4092 return rc;
4093
4094 /* fill in fixup record */
4095 cbFixup = 7UL;
4096 prlc = (struct r32_rlc *)((ULONG)pFixupRecords + offCurFixupRec);
4097 prlc->nr_stype = NROFF32;
4098 prlc->nr_flags = NRRNAM;
4099 if (ulModuleOrdinal > 255UL)
4100 {
4101 prlc->nr_flags |= NR16OBJMOD;
4102 cbFixup++;
4103 }
4104 #if 0 /* lxdump.exe (from Hacker's View release 5.66) don't support this. */
4105 if (offFnName < 256UL)
4106 {
4107 prlc->nr_flags |= NR8BITORD;
4108 cbFixup--;
4109 }
4110 #endif
4111 else if (offFnName > 65535UL)
4112 {
4113 prlc->nr_flags |= NR32BITOFF;
4114 cbFixup += 2;
4115 }
4116 prlc->r32_soff = (USHORT)offSource;
4117 prlc->r32_objmod = (USHORT)ulModuleOrdinal;
4118 if (prlc->nr_flags & NR16OBJMOD)
4119 prlc->r32_target.intref.offset32 = offFnName;
4120 else
4121 ((struct r32_rlc*)((ULONG)prlc - 1))->r32_target.intref.offset32 = offFnName;
4122
4123 /* commit fixup */
4124 offCurFixupRec += cbFixup;
4125
4126 /* cross page fixup? */
4127 if (offSource > PAGESIZE - 4UL)
4128 { /* cross page fixup! */
4129 if (pvCrossPageFixup != NULL)
4130 {
4131 printWar(("A cross page fixup allready exists!\n"));
4132 free(pvCrossPageFixup);
4133 }
4134 pvCrossPageFixup = malloc((size_t)cbFixup);
4135 if (pvCrossPageFixup != NULL)
4136 {
4137 memcpy(pvCrossPageFixup, prlc, (size_t)cbFixup);
4138 cbCrossPageFixup = cbFixup;
4139 ((struct r32_rlc *)pvCrossPageFixup)->r32_soff -= (USHORT)PAGESIZE;
4140 }
4141 else
4142 return ERROR_NOT_ENOUGH_MEMORY;
4143 }
4144
4145 printInfA(("offset=0x%03x modordinal=%d fnname=%s cbFixup=%d %s\n",
4146 offSource, ulModuleOrdinal, pszFnName, cbFixup, pvCrossPageFixup ? "crosspage" : ""));
4147 return NO_ERROR;
4148}
4149
4150
4151/**
4152 * Adds a modulename and returns the module ordinal.
4153 * If the module allready exists in the import module table then return the module ordinal only.
4154 * @returns NO_ERROR
4155 * ERROR_INVALID_PARAMETER
4156 * ERROR_NOT_ENOUGH_MEMORY
4157 * @param pszModuleName Pointer to readonly string containing the modulename which is to be added.
4158 * @param pulModuleOrdinal Pointer to an ULONG which will hold the module ordinal value upon successfull return.
4159 * @sketch validate input (pulModuleOrdinal)
4160 * get/make Odin32 modulename (lie-list)
4161 * IF modulename length > 127 THEN truncate it.
4162 * IF module allready exists in the import module table THEN return successfully.
4163 * IF not enough memory for modulename THEN (try) allocate some more.
4164 * Set length and copy modulename.
4165 * Update offCurImpModuleName.
4166 * return successfully.
4167 * @status completely implemented.
4168 * @author knut st. osmundsen
4169 * @remark Module table format (from Linear eXecutable Module Format,lxspec.inf, Rev.8):
4170 * ÚÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄ¿
4171 * ³ LEN ³ ASCII STRING . . . ³
4172 * ÀÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÙ
4173 *
4174 * LEN = DB String Length. This defines the length of the string in bytes.
4175 * The length of each ascii name string is limited to 255 characters.
4176 * ASCII STRING = DB ASCII String. This is a variable length string with it's
4177 * length defined in bytes by the LEN field. The string is case
4178 * sensitive and is not null terminated.
4179 *
4180 * The end of the import module name table is not terminated by a special character,
4181 * it is followed directly by the import procedure name table.
4182 */
4183ULONG Pe2Lx::addModule(PCSZ pszModuleName, PULONG pulModuleOrdinal)
4184{
4185 ULONG cchModuleName;
4186 ULONG offModule;
4187
4188 #ifdef DEBUG
4189 /* validate input */
4190 if (pulModuleOrdinal < (PULONG)0x10000UL)
4191 {
4192 printErr(("Invalid (stack?) pointer passed in, 0x%08x\n", pulModuleOrdinal));
4193 return ERROR_INVALID_PARAMETER;
4194 }
4195 #endif
4196
4197 /* check lie-list - get Odin32 modulename */
4198 pszModuleName = queryOdin32ModuleName(pszModuleName);
4199
4200 /* length check */
4201 cchModuleName = strlen(pszModuleName);
4202 if (cchModuleName > 255UL) /* we've only got a byte to store the length in... */
4203 {
4204 printWar(("Modulename truncated! %s\n", pszModuleName));
4205 cchModuleName = 255;
4206 }
4207
4208 /* check if module allready exists in the list and find module ordinal*/
4209 *pulModuleOrdinal = 1UL;
4210 offModule = 0UL;
4211 while (offModule < offCurImpModuleName)
4212 {
4213 if (strnicmp(&pachImpModuleNames[offModule + 1], pszModuleName,
4214 (int)pachImpModuleNames[offModule]) == 0) /* case insensitive search - correct? */
4215 {
4216 return NO_ERROR;
4217 }
4218 offModule += 1 + pachImpModuleNames[offModule];
4219 (*pulModuleOrdinal)++;
4220 }
4221
4222 printInf(("Modulename: %s Ordinal: %d\n", pszModuleName, *pulModuleOrdinal));
4223
4224 /* check if there is enough memory */
4225 AllocateMoreMemory(offCurImpModuleName + 1 + cchModuleName > cchIMNAllocated,
4226 pachImpModuleNames, PCHAR, cchIMNAllocated,
4227 1 + cchModuleName, 1 + cchModuleName)
4228
4229 /* copy the modulename */
4230 pachImpModuleNames[offCurImpModuleName] = (CHAR)cchModuleName;
4231 memcpy(&pachImpModuleNames[offCurImpModuleName + 1], pszModuleName, (size_t)cchModuleName);
4232
4233 offCurImpModuleName += cchModuleName + 1;
4234
4235 return NO_ERROR;
4236}
4237
4238
4239/**
4240 * Adds a procedure name to the Import Procedure Table.
4241 * @returns NO_ERROR
4242 * ERROR_INVALID_PARAMETER
4243 * ERROR_NOT_ENOUGH_MEMORY
4244 * @param pszFnName Pointer to readonly procname string.
4245 * @param poffFnName Pointer to variable which will hold the proc name offset on return.
4246 * @sketch Validate pointer parameter poffFnName.
4247 * Determin function name length. (max length 127)
4248 * IF not enough memory for the function name THEN (try) allocate more memory
4249 * Add function name to the import procedure name table.
4250 * return successfully.
4251 * @status completely implemented.
4252 * @author knut st. osmundsen
4253 * @remark Resident Name Table format (from Linear eXecutable Module Format,lxspec.inf, Rev.8):
4254 *
4255 * The import procedure name table defines the procedure name strings imported by this module
4256 * through dynamic link references. These strings are referenced through the imported
4257 * relocation fixups. To determine the length of the import procedure name table add the
4258 * fixup section size to the fixup page table offset, this computes the offset to the end
4259 * of the fixup section, then subtract the import procedure name table offset. These values
4260 * are located in the linear EXE header. The import procedure name table is followed by the
4261 * data pages section. Since the data pages section is aligned on a 'page size' boundary,
4262 * padded space may exist between the last import name string and the first page in the
4263 * data pages section. If this padded space exists it will be zero filled. The strings
4264 * are CASE SENSITIVE and NOT NULL TERMINATED. Each name table entry has the following
4265 * format:
4266 *
4267 * ÚÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄ¿
4268 * 00h ³ LEN ³ ASCII STRING . . . ³
4269 * ÀÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÙ
4270 *
4271 * Import Procedure Name Table
4272 *
4273 * LEN = DB String Length. This defines the length of the string in bytes. The length
4274 * of each ascii name string is limited to 255 characters. The high bit in the LEN field
4275 * (bit 7) is defined as an Overload bit. This bit signifies that additional information
4276 * is contained in the linear EXE module and will be used in the future for parameter
4277 * type checking.
4278 *
4279 * ASCII STRING = DB ASCII String. This is a variable length string with it's length
4280 * defined in bytes by the LEN field. The string is case sensitive and is not null terminated.
4281 *
4282 * Note: The first entry in the import procedure name table must be a null entry. That is,
4283 * the LEN field should be zero followed an empty ASCII STRING (no bytes).
4284 *
4285 * ----
4286 *
4287 * 255 bytes long when bit 7 is Overload bit?. We'll continue truncating to 127 bytes.
4288 *
4289 */
4290ULONG Pe2Lx::addImportFunctionName(PCSZ pszFnName, PULONG poffFnName)
4291{
4292 #ifdef DEBUG
4293 /* validate parameters */
4294 if (poffFnName < (PULONG)0x10000UL)
4295 {
4296 printErr(("poffFnName is invalid!, 0x%08x\n", poffFnName));
4297 return ERROR_INVALID_PARAMETER;
4298 }
4299 #endif
4300
4301 ULONG cchFnName = strlen(pszFnName);
4302
4303 /* max function name length is 127 bytes */
4304 if (cchFnName > 127)
4305 {
4306 printWar(("function name truncated, %s", pszFnName));
4307 cchFnName = 127;
4308 }
4309
4310 AllocateMoreMemory(offCurImpFunctionName + cchFnName + 1 > cchIFNAllocated,
4311 pachImpFunctionNames, PCHAR, cchIFNAllocated, PAGESIZE, PAGESIZE)
4312
4313 /* check if first entry */
4314 if (offCurImpFunctionName == 0UL)
4315 { /* add null entry */
4316 pachImpFunctionNames[offCurImpFunctionName++] = '\0';
4317 }
4318
4319 /* add function name */
4320 pachImpFunctionNames[offCurImpFunctionName] = (CHAR)cchFnName;
4321 memcpy(&pachImpFunctionNames[offCurImpFunctionName+1], pszFnName, (size_t)cchFnName);
4322 *poffFnName = offCurImpFunctionName;
4323 offCurImpFunctionName += 1 + cchFnName;
4324
4325 return NO_ERROR;
4326}
4327
4328
4329/**
4330 * Releases unsused memory from the Fixup data structures.
4331 * @status completely implemented.
4332 * @author knut st. osmundsen
4333 */
4334VOID Pe2Lx::finalizeFixups()
4335{
4336 if (paulFixupPageTable != NULL && cFixupPTEntries < cFPTEAllocated)
4337 {
4338 PVOID pv = realloc(paulFixupPageTable, (size_t)cFixupPTEntries * sizeof(ULONG));
4339 if (pv != NULL)
4340 {
4341 paulFixupPageTable = (PULONG)pv;
4342 cFPTEAllocated = cFixupPTEntries;
4343 }
4344 }
4345
4346 if (pFixupRecords != NULL && offCurFixupRec < cbFRAllocated)
4347 {
4348 PVOID pv = realloc(pFixupRecords, offCurFixupRec);
4349 if (pv != NULL)
4350 {
4351 pFixupRecords = pv;
4352 cbFRAllocated = offCurFixupRec;
4353 }
4354 }
4355}
4356
4357
4358/**
4359 * Releases unsused memory from the Import data structures.
4360 * @status completely implemented.
4361 * @author knut st. osmundsen
4362 */
4363VOID Pe2Lx::finalizeImportNames()
4364{
4365 if (pachImpModuleNames != NULL && offCurImpModuleName < cchIMNAllocated)
4366 {
4367 PVOID pv = realloc(pachImpModuleNames, offCurImpModuleName);
4368 if (pv != NULL)
4369 {
4370 pachImpModuleNames = (PCHAR)pv;
4371 cchIMNAllocated = offCurImpModuleName;
4372 }
4373 }
4374
4375 if (pachImpFunctionNames != NULL && offCurImpFunctionName < cchIFNAllocated)
4376 {
4377 PVOID pv = realloc(pachImpFunctionNames, offCurImpFunctionName);
4378 if (pv != NULL)
4379 {
4380 pachImpFunctionNames = (PCHAR)pv;
4381 cchIFNAllocated = offCurImpFunctionName;
4382 }
4383 }
4384}
4385
4386
4387/**
4388 * Initiates the entry (export) related data members of this object.
4389 * Forwarders are concidered.
4390 * @returns NO_ERROR
4391 * @status completely implemented.
4392 * @author knut st. osmundsen
4393 */
4394ULONG Pe2Lx::initEntry()
4395{
4396 APIRET rc;
4397
4398 if (pEntryBundles != NULL)
4399 {
4400 free(pEntryBundles);
4401 pEntryBundles = NULL;
4402 }
4403 offCurEntryBundle = 0UL;
4404 offLastEntryBundle = 0UL;
4405 ulLastOrdinal = 0UL;
4406 cbEBAllocated = 0UL;
4407
4408 if (pachResNameTable)
4409 {
4410 free(pachResNameTable);
4411 pachResNameTable = NULL;
4412 }
4413 offCurResName = 0UL;
4414 cchRNTAllocated = 0UL;
4415
4416 /* If this is a second call to makeExports, the fForwarders flag may be set. */
4417 /* When it's set we'll have to clean up the fixup structures too. */
4418 if (fForwarders)
4419 {
4420 fForwarders = FALSE;
4421 rc = initFixups();
4422 fForwarders = TRUE;
4423 }
4424 else
4425 rc = NO_ERROR;
4426
4427 return rc;
4428}
4429
4430
4431/**
4432 * Adds a name/ordinal to the resident name table.
4433 * @returns NO_ERROR
4434 * ERROR_NOT_ENOUGH_MEMORY
4435 * @param ulOrdinal Ordinal number for this name.
4436 * @param pszName Pointer to read only name string. (Don't have to be zero-termitated)
4437 * @param cchName Numbers of chars to copy or ~0UL to copy until zero-termintaion.
4438 * @sketch IF cchName == ~0L THEN get name length.
4439 * IF name length > 127 THEN truncate name.
4440 * IF not enough memory THEN (try) allocate more memory.
4441 * Add name:
4442 * Set length.
4443 * Copy name
4444 * Set ordinal
4445 * Update offCurResName to point the next (unused) name entry.
4446 * return successfully.
4447 * @status completely implemented; tested.
4448 * @author knut st. osmundsen
4449 * @remark Resident Name Table format (from Linear eXecutable Module Format,lxspec.inf, Rev.8):
4450 *
4451 * The resident and non-resident name tables define the ASCII names and ordinal numbers for
4452 * exported entries in the module. In addition the first entry in the resident name table
4453 * contains the module name. These tables are used to translate a procedure name string into
4454 * an ordinal number by searching for a matching name string. The ordinal number is used to
4455 * locate the entry point information in the entry table. The resident name table is kept
4456 * resident in system memory while the module is loaded. It is intended to contain the
4457 * exported entry point names that are frequently dynamicaly linked to by name. Non-resident
4458 * names are not kept in memory and are read from the EXE file when a dynamic link reference
4459 * is made. Exported entry point names that are infrequently dynamicaly linked to by name or
4460 * are commonly referenced by ordinal number should be placed in the non-resident name table.
4461 * The trade off made for references by name is performance vs memory usage. Import references
4462 * by name require these tables to be searched to obtain the entry point ordinal number.
4463 * Import references by ordinal number provide the fastest lookup since the search of these
4464 * tables is not required.
4465 *
4466 * Installable File Systems, Physical Device Drivers, and Virtual Device Drivers are closed
4467 * after the file is loaded. Any refeference to the non-resident name table after this time
4468 * will fail. The strings are CASE SENSITIVE and are NOT NULL TERMINATED. Each name table entry
4469 * has the following format:
4470 *
4471 *
4472 * ÚÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄ¿
4473 * 00h ³ LEN ³ ASCII STRING . . . ³ ORDINAL # ³
4474 * ÀÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÙ
4475 *
4476 * Resident or Non-resident Name Table Entry
4477 *
4478 * LEN = DB String Length. This defines the length of the string in bytes. A zero length
4479 * indicates there are no more entries in table. The length of each ascii name string is
4480 * limited to 255 characters. The high bit in the LEN field (bit 7) is defined as an Overload
4481 * bit. This bit signifies that additional information is contained in the linear EXE module
4482 * and will be used in the future for parameter type checking.
4483 *
4484 * ASCII STRING = DB ASCII String. This is a variable length string with it's length defined
4485 * in bytes by the LEN field. The string is case case sensitive and is not null terminated.
4486 *
4487 * ORDINAL # = DW Ordinal number. The ordinal number in an ordered index into the entry table
4488 * for this entry point.
4489 *
4490 */
4491ULONG Pe2Lx::addResName(ULONG ulOrdinal, PCSZ pszName, ULONG cchName)
4492{
4493 /* IF cchName == ~0L THEN get name length. */
4494 if (cchName == ~0UL)
4495 cchName = strlen(pszName);
4496
4497 /* IF name length > 127 THEN truncate name. */
4498 if (cchName > 127)
4499 {
4500 printWar(("Resident name truncated! %s\n", pszName));
4501 cchName = 127;
4502 }
4503
4504 /* IF not enough memory THEN (try) allocate more memory. */
4505 AllocateMoreMemory(cchName + 1 + 2 + offCurResName > cchRNTAllocated,
4506 pachResNameTable, PCHAR, cchRNTAllocated, 2048, 1024)
4507
4508 /* Add name */
4509 pachResNameTable[offCurResName] = (CHAR)cchName;
4510 memcpy(&pachResNameTable[offCurResName + 1], pszName, (size_t)cchName);
4511 *(PUSHORT)&pachResNameTable[offCurResName + 1 + cchName] = (USHORT)ulOrdinal;
4512
4513 /* Update offCurResName to point the next (unused) name entry. */
4514 offCurResName += 1 + cchName + 2;
4515
4516 printInf(("Resident Name: %.*s ordinal:%d\n", cchName, pszName, ulOrdinal));
4517
4518 return NO_ERROR;
4519}
4520
4521
4522/**
4523 * Adds an entry to the entry table.
4524 * The way this is implemented, it is REQUIRED that the entries are added in strict
4525 * ascending order by ordinal.
4526 * @returns NO_ERROR
4527 * ERROR_NOT_ENOUGH_MEMORY
4528 * ERROR_INVALID_PARAMETER
4529 * @param ulOrdinal Ordinal number of the entry point.
4530 * @param ulRVA The RVA of the entry point.
4531 * @sketch Validate input. (ulOrdinal)
4532 * Find object and offObject corresponding to the entrypoint RVA.
4533 * IF no enough memory THEN (try) allocate more.
4534 * LOOP WHILE last ordinal + 1 != new ordinal
4535 * BEGIN
4536 * Add unused entry which skips to the new ordinal - 1.
4537 * Update offCurEntryBundle
4538 * Set offLastEntryBundle to offLastEntryBundle.
4539 * IF no enough memory THEN (try) allocate more.
4540 * END
4541 * IF offCurEntryBundle == offLastEntryBundle OR last bundle type != 32-bit entry
4542 * OR last bundle object != this object OR bundle is full THEN
4543 * BEGIN
4544 * Add an empty 32-bit bundle.
4545 * Set offLastEntryBundle to start of new 32-bit bundle.
4546 * Set offCurEntryBundle to end of of the new 32-bit bundle.
4547 * END
4548 * Add Flags (01h) and 32-bit offset.
4549 * Update offCurEntryBundle.
4550 * return successfully.
4551 * @status completely implemented.
4552 * @author knut st. osmundsen
4553 * @remark Entry Table format (from Linear eXecutable Module Format,lxspec.inf, Rev.8):
4554 * The entry table contains object and offset information that is used to resolve fixup
4555 * references to the entry points within this module. Not all entry points in the entry
4556 * table will be exported, some entry points will only be used within the module. An ordinal
4557 * number is used to index into the entry table. The entry table entries are numbered
4558 * starting from one. The list of entries are compressed into 'bundles', where possible. The
4559 * entries within each bundle are all the same size. A bundle starts with a count field which
4560 * indicates the number of entries in the bundle. The count is followed by a type field which
4561 * identifies the bundle format. This provides both a means for saving space as well as a
4562 * mechanism for extending the bundle types. The type field allows the definition of 256
4563 * bundle types. The following bundle types will initially be defined:
4564 * Unused Entry.
4565 * 16-bit Entry.
4566 * 286 Call Gate Entry.
4567 * 32-bit Entry.
4568 * Forwarder Entry.
4569 *
4570 * The bundled entry table has the following format:
4571 * ÚÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
4572 * 00h ³ CNT ³TYPE ³ BUNDLE INFO . . ³
4573 * ÀÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
4574 *
4575 * Entry Table
4576 *
4577 * CNT = DB Number of entries. This is the number of entries in this bundle. A zero
4578 * value for the number of entries identifies the end of the entry table. There is no
4579 * further bundle information when the number of entries is zero. In other words the
4580 * entry table is terminated by a single zero byte.
4581 *
4582 * TYPE = DB Bundle type. This defines the bundle type which determines the contents
4583 * of the BUNDLE INFO. The follow types are defined:
4584 * 00h = Unused Entry.
4585 * 01h = 16-bit Entry.
4586 * 02h = 286 Call Gate Entry.
4587 * 03h = 32-bit Entry.
4588 * 04h = Forwarder Entry.
4589 * 80h = Parameter Typing Information Present. This bit signifies that
4590 * additional information is contained in the linear EXE module
4591 * and will be used in the future for parameter type checking.
4592 *
4593 * The following is the format for each bundle type:
4594 *
4595 * Unused Entry:
4596 * ------------
4597 * ÚÄÄÄÄÄÂÄÄÄÄÄ¿
4598 * 00h ³ CNT ³TYPE ³
4599 * ÀÄÄÄÄÄÁÄÄÄÄÄÙ
4600 *
4601 * CNT = DB Number of entries. This is the number of unused entries to skip.
4602 *
4603 * TYPE = DB 0 (Unused Entry)
4604 *
4605 * 32-bit Entry:
4606 * ------------
4607 * ÚÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄ¿
4608 * 00h ³ CNT ³TYPE ³ OBJECT ³
4609 * ÃÄÄÄÄÄÅÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄ¿
4610 * 04h ³FLAGS³ OFFSET ³
4611 * ÃÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŽ
4612 * 09h ³ ... ³ . . . ³
4613 *
4614 *
4615 * CNT = DB Number of entries. This is the number of 32-bit entries in this bundle.
4616 * The flags and offset value are repeated this number of times.
4617 *
4618 * TYPE = DB 3 (32-bit Entry) The 32-bit Entry type will only be defined by the
4619 * linker when the offset in the object can not be specified by a 16-bit offset.
4620 *
4621 * OBJECT = DW Object number. This is the object number for the entries in this bundle.
4622 *
4623 * FLAGS = DB Entry flags. These are the flags for this entry point. They have the
4624 * following definition.
4625 * 01h = Exported entry flag.
4626 * F8h = Parameter dword count mask.
4627 *
4628 * OFFSET = DD Offset in object. This is the offset in the object for the entry point
4629 * defined at this ordinal number.
4630 *
4631 */
4632ULONG Pe2Lx::addEntry(ULONG ulOrdinal, ULONG ulRVA)
4633{
4634 APIRET rc;
4635 ULONG iObj;
4636 ULONG offObject;
4637 struct b32_bundle *pBundle;
4638 struct e32_entry *pEntry;
4639
4640 #ifdef DEBUG
4641 /* Validate input. (ulOrdinal) */
4642 if (ulOrdinal < ulLastOrdinal + 1UL || ulOrdinal > 65535UL)
4643 {
4644 printErr(("Invalid ordinal. ulOrdinal %d, ulLastOrdinal %d.\n", ulOrdinal, ulLastOrdinal));
4645 return ERROR_INVALID_PARAMETER;
4646 }
4647 #endif
4648
4649 /* Find object and offObject corresponding to the entrypoint RVA. */
4650 rc = queryObjectAndOffset(ulRVA, (PULONG)SSToDS(&iObj), (PULONG)SSToDS(&offObject));
4651 if (rc != NO_ERROR)
4652 return rc;
4653
4654 /* IF no enough memory THEN (try) allocate more. */
4655 AllocateMoreMemory(offCurEntryBundle + 4 + 2 + 5 > cbEBAllocated /* max memory uasage! Should detect more exact memory usage! */,
4656 pEntryBundles, struct b32_bundle *, cbEBAllocated , 512, 256)
4657
4658 /* Add unused entry to skip ordinals? */
4659 while (ulOrdinal > ulLastOrdinal + 1)
4660 {
4661 /* Add unused entry which skips to the new ordinal - 1.*/
4662 pBundle = (struct b32_bundle *)((ULONG)pEntryBundles + offCurEntryBundle);
4663 pBundle->b32_cnt = (ulOrdinal - ulLastOrdinal - 1) < 0x100 ?
4664 (UCHAR)(ulOrdinal - ulLastOrdinal - 1) : (UCHAR)0xff;
4665 pBundle->b32_type = EMPTY;
4666 ulLastOrdinal += pBundle->b32_cnt;
4667
4668 /* Update offCurEntryBundle and offLastEntryBundle */
4669 offLastEntryBundle = offCurEntryBundle += 2UL;
4670
4671 /* IF no enough memory THEN (try) allocate more. */
4672 AllocateMoreMemory(offCurEntryBundle + 4 + 2 + 5 > cbEBAllocated /* max memory uasage! Should detect more exact memory usage! */,
4673 pEntryBundles, struct b32_bundle *, cbEBAllocated , 512, 256)
4674 }
4675
4676 /* new entry32 bundle? */
4677 pBundle = (struct b32_bundle *)((ULONG)pEntryBundles + offLastEntryBundle);
4678 if (offCurEntryBundle == offLastEntryBundle || pBundle->b32_type != ENTRY32
4679 || pBundle->b32_obj != iObj || pBundle->b32_cnt == 255)
4680 {
4681 /* Add an empty 32-bit bundle. */
4682 pBundle = (struct b32_bundle *)((ULONG)pEntryBundles + offCurEntryBundle);
4683 pBundle->b32_cnt = 0;
4684 pBundle->b32_type = ENTRY32;
4685 pBundle->b32_obj = (USHORT)iObj;
4686 /* Set offLastEntryBundle to start of new 32-bit bundle. */
4687 offLastEntryBundle = offCurEntryBundle;
4688 /* Set offCurEntryBundle to end of of the new 32-bit bundle. */
4689 offCurEntryBundle += sizeof(struct b32_bundle);
4690 }
4691
4692 /* Add Flags (01h) and 32-bit offset. */
4693 pEntry = (struct e32_entry *)((ULONG)pEntryBundles + offCurEntryBundle);
4694 pEntry->e32_flags = E32EXPORT;
4695 pEntry->e32_variant.e32_offset.offset32 = offObject;
4696 pBundle->b32_cnt++;
4697
4698 /* Update offCurEntryBundle. */
4699 offCurEntryBundle += FIXENT32;
4700 ulLastOrdinal = ulOrdinal;
4701
4702 printInfA(("Export entry: ulOrdinal=%d ulRVA=%#5x iObj=%2d offObject=%#5x\n",
4703 ulOrdinal, ulRVA, iObj, offObject));
4704
4705 return NO_ERROR;
4706}
4707
4708
4709/**
4710 * Adds a forwarder entry.
4711 * The way this is implemented, it is REQUIRED that the entries are added in strict
4712 * ascending order by ordinal.
4713 * @returns NO_ERROR
4714 * ERROR_NOT_ENOUGH_MEMORY
4715 * ERROR_INVALID_PARAMETER
4716 * @param ulOrdinal Entry ordinal number.
4717 * @param pszDllName Pointer to string containing the dllname.
4718 * @param pszFnNameOrOrd Pointer to string containing either a function or an ordinal.
4719 * Note. Have currently not found any example of an ordinal...
4720 * That is just an assumption!
4721 * @sketch Set forwarder flag.
4722 * Validate input. (ulOrdinal and pointers)
4723 * IF no enough memory THEN (try) allocate more.
4724 * IF Function ordinal THEN convert it to an ordinal number.
4725 * Make sure kernel32 is the first imported module.
4726 * Add module name.
4727 * IF not forwarder to ordinal THEN Add name to imported procedure table.
4728 * IF last ordinal + 1 != new ordinal THEN
4729 * BEGIN
4730 * Add unused entry which skips to the new ordinal - 1.
4731 * Update offCurEntryBundle
4732 * Set offLastEntryBundle to offLastEntryBundle.
4733 * END
4734 * IF offCurEntryBundle == offLastEntryBundle OR last bundle type != forwarder entry
4735 * OR bundle is full THEN
4736 * BEGIN
4737 * Add an empty forwarder bundle.
4738 * Set offLastEntryBundle to start of the new forwarder bundle.
4739 * Set offCurEntryBundle to end of of the new forwarder bundle.
4740 * END
4741 * Add Flags, module ordinal and name offset/ordinal number.
4742 * Update offCurEntryBundle.
4743 * return successfully.
4744 * @status completely implemented.
4745 * @author knut st. osmundsen
4746 * @remark Entry Table format (from Linear eXecutable Module Format,lxspec.inf, Rev.8):
4747 *
4748 * Forwarder Entry:
4749 * ---------------
4750 * ÚÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄ¿
4751 * 00h ³ CNT ³TYPE ³ RESERVED ³
4752 * ÃÄÄÄÄÄÅÄÄÄÄÄÁÄÄÄÄÄÂÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
4753 * 04h ³FLAGS³ MOD ORD# ³ OFFSET / ORDNUM ³
4754 * ÃÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŽ
4755 * 09h ³ ... ³ ... ³ ... ³
4756 *
4757 *
4758 * CNT = DB Number of entries. This is the number of forwarder entries in this bundle.
4759 * The FLAGS, MOD ORD#, and OFFSET/ORDNUM values are repeated this number of times.
4760 *
4761 * TYPE = DB 4 (Forwarder Entry)
4762 *
4763 * RESERVED = DW 0 This field is reserved for future use.
4764 *
4765 * FLAGS = DB Forwarder flags. These are the flags for this entry point. They have the
4766 * following definition.
4767 * 01h = Import by ordinal.
4768 * F7h = Reserved for future use; should be zero.
4769 *
4770 * MOD ORD# = DW Module Ordinal Number This is the index into the Import Module Name Table
4771 * for this forwarder.
4772 *
4773 * OFFSET / ORDNUM = DD Procedure Name Offset or Import Ordinal Number If the FLAGS field
4774 * indicates import by ordinal, then this field is the ordinal number into the Entry Table
4775 * of the target module, otherwise this field is the offset into the Procedure Names Table
4776 * of the (?)target(?) module.
4777 *
4778 * A Forwarder entry (type = 4) is an entry point whose value is an imported reference. When a
4779 * load time fixup occurs whose target is a forwarder, the loader obtains the address imported
4780 * by the forwarder and uses that imported address to resolve the fixup.
4781 *
4782 * A forwarder may refer to an entry point in another module which is itself a forwarder, so there
4783 * can be a chain of forwarders. The loader will traverse the chain until it finds a non-forwarded
4784 * entry point which terminates the chain , and use this to resolve the original fixup. Circular
4785 * chains are detected by the loader and result in a load time error. A maximum of 1024
4786 * forwarders is allowed in a chain; more than this results in a load time error.
4787 *
4788 * Forwarders are useful for merging and recombining API calls into different sets of libraries,
4789 * while maintaining compatibility with applications. For example, if one wanted to combine
4790 * MONCALLS, MOUCALLS, and VIOCALLS into a single libraries, one could provide entry points
4791 * for the three libraries that are forwarders pointing to the common implementation.
4792 *
4793 * ---------------
4794 *
4795 * Forwarder makes some minor difficulties concerning function names.
4796 * We then have to
4797 * 1) Allways convert entries before imports (fixups).
4798 * 2) When forwarders are present makeFixups can't be called without calling makeExports first.
4799 * 3) initEntries will clean up import variables too if fForwarders is set.
4800 */
4801ULONG Pe2Lx::addForwarderEntry(ULONG ulOrdinal, PCSZ pszDllName, PCSZ pszFnNameOrOrd)
4802{
4803 APIRET rc;
4804 ULONG ulFnOrdinal; /* function ordinal or function offset into import procdure table.
4805 * The high bit is set when it is an ordinal value. (remember to mask it off!)
4806 * The high bit is clear when it is an offset. */
4807 ULONG ulModuleOrdinal; /* Module ordinal */
4808 struct b32_bundle *pBundle; /* pointer to current (offLast...) entry bundle. */
4809 struct e32_entry *pEntry; /* pointer to new entry (new entry in the array imediately following the bundle) . */
4810 PCSZ psz; /* temporary string pointer. */
4811
4812 /* Set forwarder flag. */
4813 fForwarders = TRUE;
4814
4815 /* Validate input. (ulOrdinal and pointers) */
4816 if (ulOrdinal < ulLastOrdinal + 1UL || ulOrdinal > 65535UL)
4817 {
4818 printErr(("Invalid ordinal. ulOrdinal %d, ulLastOrdinal %d.\n", ulOrdinal, ulLastOrdinal));
4819 return ERROR_INVALID_PARAMETER;
4820 }
4821 #ifdef DEBUG
4822 if (pszDllName < (PCSZ)0x10000UL || pszFnNameOrOrd < (PCSZ)0x10000UL)
4823 return ERROR_INVALID_PARAMETER;
4824 #endif
4825
4826 /* IF no enough memory THEN (try) allocate more. */
4827 AllocateMoreMemory(offCurEntryBundle + 4 + 2 + 7 > cbEBAllocated /* max memory uasage! Should detect more exact memory usage! */,
4828 pEntryBundles, struct b32_bundle *, cbEBAllocated , 512, 256)
4829
4830 /* IF Function ordinal THEN convert it to an ordinal number. */
4831 ulFnOrdinal = 0UL;
4832 psz = pszFnNameOrOrd;
4833 while (*psz != '\0' && *psz >= '0' && *psz <= '9')
4834 ulFnOrdinal = (ulFnOrdinal*10) + *psz - '0';
4835 if (*psz == '\0')
4836 ulFnOrdinal |= 0x80000000UL; /* ordinal flag */
4837 else
4838 ulFnOrdinal = 0; /* not ordinal! */
4839
4840 /* Make sure kernel32 is the first imported module */
4841 if (offCurImpModuleName == 0)
4842 {
4843 rc = addModule("KERNEL32.DLL", (PULONG)SSToDS(&ulModuleOrdinal));
4844 if (rc != NO_ERROR)
4845 return rc;
4846 }
4847
4848 /* Add module name. */
4849 rc = addModule(pszDllName, (PULONG)SSToDS(&ulModuleOrdinal));
4850 if (rc != NO_ERROR)
4851 return rc;
4852
4853 /* IF not forwarder to ordinal THEN Add name to imported procedure table. */
4854 if (!(ulFnOrdinal & 0x80000000UL))
4855 {
4856 rc = addImportFunctionName(pszFnNameOrOrd, (PULONG)SSToDS(&ulFnOrdinal));
4857 if (rc != NO_ERROR)
4858 return rc;
4859 }
4860
4861 /* Add unused entry to skip ordinals? */
4862 while (ulOrdinal > ulLastOrdinal + 1)
4863 {
4864 /* Add unused entry which skips to the new ordinal - 1.*/
4865 pBundle = (struct b32_bundle *)((ULONG)pEntryBundles + offCurEntryBundle);
4866 pBundle->b32_cnt = (ulOrdinal - ulLastOrdinal - 1) < 0x100 ?
4867 (UCHAR)(ulOrdinal - ulLastOrdinal - 1) : (UCHAR)0xff;
4868 pBundle->b32_type = EMPTY;
4869 ulLastOrdinal += pBundle->b32_cnt;
4870
4871 /* Update offCurEntryBundle and offLastEntryBundle */
4872 offLastEntryBundle = offCurEntryBundle += 2UL;
4873
4874 /* IF no enough memory THEN (try) allocate more. */
4875 AllocateMoreMemory(offCurEntryBundle + 4 + 2 + 7 > cbEBAllocated /* max memory uasage! Should detect more exact memory usage! */,
4876 pEntryBundles, struct b32_bundle *, cbEBAllocated , 512, 256)
4877 }
4878
4879 /* new forwarder bundle? */
4880 pBundle = (struct b32_bundle *)((ULONG)pEntryBundles + offLastEntryBundle);
4881 if (offCurEntryBundle == offLastEntryBundle || pBundle->b32_type != ENTRYFWD
4882 || pBundle->b32_cnt == 255)
4883 {
4884 /* Add an empty 32-bit bundle. */
4885 pBundle = (struct b32_bundle *)((ULONG)pEntryBundles + offCurEntryBundle);
4886 pBundle->b32_cnt = 0;
4887 pBundle->b32_type = ENTRYFWD;
4888 pBundle->b32_obj = 0;
4889 /* Set offLastEntryBundle to start of the new forwarder bundle. */
4890 offLastEntryBundle = offCurEntryBundle;
4891 /* Set offCurEntryBundle to end of of the new forwarder bundle. */
4892 offCurEntryBundle += sizeof(struct b32_bundle);
4893 }
4894
4895 /* Add Flags, module ordinal and name offset/ordinal number. */
4896 pEntry = (struct e32_entry *)((ULONG)pEntryBundles + offCurEntryBundle);
4897 pEntry->e32_flags = (UCHAR)(ulFnOrdinal & 0x80000000UL ? FWD_ORDINAL : 0);
4898 pEntry->e32_variant.e32_fwd.modord = (USHORT)ulModuleOrdinal;
4899 pEntry->e32_variant.e32_fwd.value = ulFnOrdinal & 0x7fffffffUL;
4900 pBundle->b32_cnt++;
4901
4902 /* Update offCurEntryBundle. */
4903 offCurEntryBundle += FWDENT;
4904 ulLastOrdinal = ulOrdinal;
4905
4906 printInfA(("Forwarder Export entry: ulOrdinal=%d pszDllName=%s pszFnNameOrOrd=%s\n",
4907 ulOrdinal, pszDllName, pszFnNameOrOrd));
4908
4909 return NO_ERROR;
4910}
4911
4912
4913/**
4914 * Adds the closing entry bundle.
4915 * @returns NO_ERROR
4916 * ERROR_NOT_ENOUGH_MEMORY
4917 * @sketch IF no enough memory THEN (try) allocate more.
4918 * fill in final bundle. (cnt=0 only)
4919 * Update off*.
4920 * return successfully.
4921 * @status completely implemented; tested.
4922 * @author knut st. osmundsen
4923 * @remark Should only be called to close a sequence of addEntry and addForwarderEntry calls.
4924 */
4925ULONG Pe2Lx::addLastEntry()
4926{
4927 struct b32_bundle *pBundle; /* pointer to current (offLast...) entry bundle. */
4928
4929 /* IF no enough memory THEN (try) allocate more. */
4930 /* table is terminated by a single '\0' byte according to the docs. */
4931 AllocateMoreMemory(offCurEntryBundle + 1 > cbEBAllocated,
4932 pEntryBundles, struct b32_bundle *, cbEBAllocated, 1, 1)
4933
4934 /* fill in final bundle (cnt = 0!) */
4935 pBundle = (struct b32_bundle *)((ULONG)pEntryBundles + offCurEntryBundle);
4936 pBundle->b32_cnt = 0;
4937
4938 /* Update offLastEntryBundle and offLastEntryBundle. */
4939 offLastEntryBundle = offCurEntryBundle += 1;
4940
4941 return NO_ERROR;
4942}
4943
4944
4945/**
4946 * Releases unsused memory from the Export data structures.
4947 * @status completely implemented; tested
4948 * @author knut st. osmundsen
4949 */
4950VOID Pe2Lx::finalizeExports()
4951{
4952 if (pEntryBundles != NULL && offCurEntryBundle < cbEBAllocated)
4953 {
4954 PVOID pv = realloc(pEntryBundles, offCurEntryBundle);
4955 if (pv != NULL)
4956 {
4957 pEntryBundles = (struct b32_bundle*)pv;
4958 cbEBAllocated = offCurEntryBundle;
4959 }
4960 }
4961
4962 if (pachResNameTable != NULL && offCurResName < cchRNTAllocated)
4963 {
4964 PVOID pv = realloc(pachResNameTable, offCurResName);
4965 if (pv != NULL)
4966 {
4967 pachResNameTable = (PCHAR)pv;
4968 cchRNTAllocated = offCurEntryBundle;
4969 }
4970 }
4971}
4972
4973
4974/**
4975 * Gets the number of pages in the virtual lx file.
4976 * @returns Number of pages. (0UL is a valid return!)
4977 * @status completely implemented; tested.
4978 * @author knut st. osmundsen
4979 * @remark fAllInOneObject should be established before this function is called!
4980 */
4981ULONG Pe2Lx::getCountOfPages()
4982{
4983 ULONG cPages = 0UL;
4984 ULONG iObj;
4985
4986 for (iObj = 0; iObj < cObjects; iObj++)
4987 {
4988 if (fAllInOneObject && iObj + 1 < cObjects)
4989 cPages += ALIGN(paObjects[iObj+1].ulRVA - paObjects[iObj].ulRVA, PAGESIZE) >> PAGESHIFT;
4990 else
4991 cPages += ALIGN(paObjects[iObj].cbVirtual, PAGESIZE) >> PAGESHIFT;
4992 }
4993
4994 return cPages;
4995}
4996
4997
4998/**
4999 * Gets the object number (1 based!) and offset into that object.
5000 * @returns NO_ERROR
5001 * ERROR_INVALID_PARAMETER
5002 * @param ulRVA
5003 * @param pulObject Pointer to variable which will hold the object number upon return. (1 based)
5004 * @param poffObject Pointer to variabel which will hold the object offset upon return.
5005 * @sketch Validate input pointers.
5006 * find object. (be aware of fAllInOneObject!)
5007 * IF object not found THEN return error invalid parameter.
5008 * Set output parameters.
5009 * return successfully.
5010 * @status completely implemented; tested.
5011 * @author knut st. osmundsen
5012 * @remark ulRVA points within a valid (LX term) page area.
5013 */
5014ULONG Pe2Lx::queryObjectAndOffset(ULONG ulRVA, PULONG pulObject, PULONG poffObject)
5015{
5016 ULONG iObj;
5017
5018 #ifdef DEBUG
5019 /* validate passed in pointers. */
5020 if (pulObject < (PULONG)0x10000UL)
5021 {
5022 printErr(("Invalid parameter pulObject.\n"));
5023 return ERROR_INVALID_PARAMETER;
5024 }
5025 if (poffObject < (PULONG)0x10000UL)
5026 {
5027 printErr(("Invalid parameter poffObject.\n"));
5028 return ERROR_INVALID_PARAMETER;
5029 }
5030 #endif
5031
5032 /* find object */
5033 if (!fAllInOneObject)
5034 {
5035 iObj = 0;
5036 while (iObj < cObjects && paObjects[iObj].ulRVA + paObjects[iObj].cbVirtual <= ulRVA)
5037 iObj++;
5038
5039 if (iObj >= cObjects || paObjects[iObj].ulRVA > ulRVA)
5040 return ERROR_INVALID_PARAMETER;
5041 }
5042 else
5043 { /* one large object! */
5044 if (cObjects != 0 && ulRVA >= paObjects[0].ulRVA
5045 && ulRVA <= paObjects[cObjects-1].ulRVA + paObjects[cObjects-1].cbVirtual)
5046 iObj = 0;
5047 else
5048 return ERROR_INVALID_PARAMETER;
5049 }
5050
5051 /* set output */
5052 *poffObject = ulRVA - paObjects[iObj].ulRVA;
5053 *pulObject = iObj + 1;
5054
5055 return NO_ERROR;
5056}
5057
5058
5059/**
5060 * Reads a chunk of data at the spcified RVA.
5061 * @returns NO_ERROR on success.
5062 * ERROR_INVALID_PARAMETER
5063 * <Whatever rc ReadAt returns>
5064 * @param ulRVA RVA to read from. Within the filesize.
5065 * @param pvBuffer Pointer to output buffer. pvBuffer > 64KB
5066 * @param cbBuffer Number of bytes to read. 0 < cbBuffer > 256MB
5067 * @status completely implemented; tested.
5068 * @author knut st. osmundsen
5069 */
5070ULONG Pe2Lx::readAtRVA(ULONG ulRVA, PVOID pvBuffer, ULONG cbBuffer)
5071{
5072 #ifdef DEBUG
5073 if (ulRVA == ~0UL || (ULONG)pvBuffer < 0x10000UL || cbBuffer == 0UL || cbBuffer >= 0x10000000UL)
5074 return ERROR_INVALID_PARAMETER;
5075 #endif
5076
5077 ULONG iObj = 0;
5078 while (cbBuffer != 0UL)
5079 {
5080 while (iObj < cObjects
5081 && ulRVA >= (iObj + 1 < cObjects ? paObjects[iObj+1].ulRVA
5082 : paObjects[iObj].ulRVA + ALIGN(paObjects[iObj].cbVirtual, PAGESIZE))
5083 )
5084 iObj++;
5085 if (iObj >= cObjects)
5086 return ERROR_INVALID_PARAMETER;
5087
5088 /* ulRVA points at physical or virtual data? */
5089 if (ulRVA < paObjects[iObj].ulRVA + paObjects[iObj].cbPhysical)
5090 { /* physical data - read from file */
5091 APIRET rc;
5092 ULONG cbToRead = min(paObjects[iObj].ulRVA + paObjects[iObj].cbPhysical - ulRVA, cbBuffer);
5093 rc = ReadAt(hFile,
5094 ulRVA - paObjects[iObj].ulRVA + paObjects[iObj].offPEFile,
5095 pvBuffer,
5096 cbToRead
5097 );
5098 if (rc != NO_ERROR)
5099 return rc;
5100 ulRVA += cbToRead;
5101 cbBuffer -= cbToRead;
5102 pvBuffer = (void*)((unsigned)pvBuffer + cbToRead);
5103 }
5104 else
5105 { /* virtual data - memset(,0,) */
5106 ULONG cbToSet = (iObj + 1 < cObjects ? paObjects[iObj+1].ulRVA
5107 : paObjects[iObj].ulRVA + ALIGN(paObjects[iObj].cbVirtual, PAGESIZE))
5108 - ulRVA; /* calcs size of virtual data left in this object */
5109 cbToSet = min(cbToSet, cbBuffer);
5110
5111 memset(pvBuffer, 0, (size_t)cbToSet);
5112 ulRVA += cbToSet;
5113 cbBuffer -= cbToSet;
5114 pvBuffer = (void*)((unsigned)pvBuffer + cbToSet);
5115 }
5116 } /* while */
5117
5118 return NO_ERROR;
5119}
5120
5121
5122
5123/**
5124 * Check if the modulename exists in the lielist. If not the passed in modulename is returned.
5125 * @returns Pointer (readonly) to Odin32 modulename.
5126 * @param pszWin32ModuleName Win32 modulename.
5127 * @status completely implemented.
5128 * @author knut st. osmundsen
5129 * @remark static method.
5130 */
5131PCSZ Pe2Lx::queryOdin32ModuleName(PCSZ pszWin32ModuleName)
5132{
5133 #ifndef RING0
5134 if (hasCustomDll() && !isCustomDllExcluded(pszWin32ModuleName))
5135 return pszWin32ModuleName;
5136 #endif
5137
5138 int i = 0;
5139 while (paLieList[i].pszWin32Name != NULL)
5140 {
5141 if (stricmp(paLieList[i].pszWin32Name, pszWin32ModuleName) == 0)
5142 return paLieList[i].pszOdin32Name;
5143 i++;
5144 }
5145
5146 return pszWin32ModuleName;
5147}
5148
5149
5150#ifndef RING0
5151/**
5152 * Checks if this DLL is excluded from the custombuild dll or not.
5153 * @returns TRUE if excluded.
5154 * @returns FALSE not excluded.
5155 * @param pszModuleName DLL in question.
5156 */
5157BOOL Pe2Lx::isCustomDllExcluded(PCSZ pszModuleName)
5158{
5159 if (options.pszCustomDllExclude == NULL)
5160 return FALSE;
5161 if (!pszModuleName)
5162 return TRUE;
5163 const char *psz = strstr(options.pszCustomDllExclude, pszModuleName);
5164 return (psz && psz[-1] == ';' && psz[strlen(pszModuleName)] == ';');
5165}
5166#endif
5167
5168
5169
5170/**
5171 * Initiates the odin32path.
5172 * @returns Success indicator.
5173 * @sketch If allready inited ok Then do nothing return TRUE.
5174 *
5175 * Check if KERNEL32 is loaded using ldrFindModule.
5176 * If loaded then set path according to the smte_path and return.
5177 *
5178 * If the path is set to something then return TRUE. (ie. the following method is allready applied.)
5179 *
5180 * Use odinPath2 to locate the KERNEL32 module in the LIBPATHs. The
5181 * win32k loaders are temporarily disabled. Path is returned in
5182 * the ldrpFileNameBuf buffer.
5183 * If found the Then set path according to ldrpFileNameBuf and return
5184 *
5185 * Fail returning FALSE.
5186 * @status
5187 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
5188 * @remark
5189 */
5190BOOL Pe2Lx::initOdin32Path()
5191{
5192 #ifdef RING0
5193 APIRET rc;
5194 PMTE pMTE;
5195
5196
5197 if (sfnKernel32 != NULLHANDLE)
5198 return TRUE;
5199
5200 /*
5201 * Try find it using ldrFindModule.
5202 */
5203 pMTE = NULL;
5204 rc = ldrFindModule("KERNEL32", 8, CLASS_GLOBAL, (PPMTE)SSToDS(&pMTE));
5205 if (rc == NO_ERROR && pMTE != NULL && pMTE->mte_swapmte != NULL)
5206 {
5207 /*
5208 * We now take the smte_path. Start at the end and skip the filename,
5209 * and one directory up. We assume a fully qualified path is found in
5210 * smte_path.
5211 */
5212 if (pMTE->mte_swapmte->smte_path != NULL)//paranoia
5213 {
5214 sfnKernel32 = pMTE->mte_sfn;
5215 return setOdin32Path(pMTE->mte_swapmte->smte_path);
5216 }
5217 }
5218
5219
5220 /*
5221 * KERNEL32 isn't loaded. We'll only search the paths if
5222 */
5223 if (pszOdin32Path != NULL)
5224 return TRUE;
5225
5226
5227 /*
5228 * Try find it searching the LIBPATHs.
5229 *
5230 * For the time being:
5231 * We'll use odinPath2 to do this, but we'll have to
5232 * disable the win32k.sys overloading temporarily.
5233 */
5234 ldrlv_t lv = {0};
5235 ULONG ful = 0;
5236 ULONG ul;
5237
5238 ul = options.fNoLoader;
5239 options.fNoLoader = TRUE;
5240 lv.lv_class = CLASS_GLOBAL;
5241 rc = openPath2("KERNEL32", 8, (ldrlv_t*)SSToDS(&lv), (PULONG)SSToDS(&ful), 3, FALSE);
5242 options.fNoLoader = ul;
5243 if (rc == NO_ERROR)
5244 {
5245 /*
5246 * Set the odin32path according to the kernel32 path we've found.
5247 * (ldrOpen sets ldrpFileNameBuf to the fully qualified path of
5248 * the last opended filed, which in this case is kernel32.dll.)
5249 * We'll close the file handle first of course.
5250 */
5251 rc = setOdin32Path(ldrpFileNameBuf);
5252 ldrClose(lv.lv_sfn);
5253 return rc;
5254 }
5255
5256 #endif
5257 return FALSE;
5258}
5259
5260
5261
5262/**
5263 * Sets the Odin32Path to the given fully qualified filename of kernel32.
5264 * @returns Success indicator.
5265 * @param psz Fully qualified filename of kernel32 with path.
5266 * @sketch
5267 * @status
5268 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
5269 * @remark
5270 */
5271BOOL Pe2Lx::setOdin32Path(const char *psz)
5272{
5273 const char * psz2;
5274
5275 /*
5276 * We now take the psz. Start at the end and skip the filename,
5277 * and one directory up. We assume a fully qualified path.
5278 */
5279 psz2 = psz + strlen(psz) - 1;
5280 while (psz2 > psz && *psz2 != '\\' && *psz2 != '/' && *psz2 != ':')
5281 psz2--;
5282 psz2--;
5283 while (psz2 > psz && *psz2 != '\\' && *psz2 != '/' && *psz2 != ':')
5284 psz2--;
5285 if (psz2 > psz)
5286 {
5287 char *pszPath;
5288 /*
5289 * Free old path (if any) and allocate space for a new path.
5290 * Copy the path including the slash.
5291 * Remember the kernel32 filehandle (to be able to invalidate the path).
5292 */
5293 if (pszOdin32Path)
5294 rfree((void*)pszOdin32Path);
5295 if (*psz2 == ':') //in case someone installed odin in a root directory.
5296 psz2++;
5297 psz2++; //include the slash
5298 cchOdin32Path = psz2 - psz;
5299 pszPath = (char*)rmalloc((size_t)cchOdin32Path);
5300 if (pszPath == NULL) return FALSE;
5301 memcpy(pszPath, psz, (size_t)cchOdin32Path);
5302 pszPath[cchOdin32Path] = '\0';
5303 pszOdin32Path = pszPath;
5304
5305 return TRUE;
5306 }
5307
5308 return FALSE;
5309}
5310
5311
5312
5313
5314/**
5315 * Static method which dumps a set of nt headers.
5316 * @param pNtHdrs Pointer to nt headers.
5317 * @status Completed
5318 * @author knut st. osmundsen
5319 */
5320VOID Pe2Lx::dumpNtHeaders(PIMAGE_NT_HEADERS pNtHdrs)
5321{
5322 if (pNtHdrs >= (PIMAGE_NT_HEADERS)0x10000)
5323 {
5324 int i;
5325 WORD w;
5326
5327 printInf(("\nPE-headers - File header\n"));
5328 printInf(("Signature %.2s\n", &pNtHdrs->Signature));
5329 printInf(("Machine 0x%08x\n", pNtHdrs->FileHeader.Machine));
5330 switch (pNtHdrs->FileHeader.Machine)
5331 {
5332 case IMAGE_FILE_MACHINE_UNKNOWN: printInf((" IMAGE_FILE_MACHINE_UNKNOWN\n")); break;
5333 case IMAGE_FILE_MACHINE_I386: printInf((" IMAGE_FILE_MACHINE_I386\n")); break;
5334 case IMAGE_FILE_MACHINE_R3000: printInf((" IMAGE_FILE_MACHINE_R3000\n")); break;
5335 case IMAGE_FILE_MACHINE_R4000: printInf((" IMAGE_FILE_MACHINE_R4000\n")); break;
5336 case IMAGE_FILE_MACHINE_R10000: printInf((" IMAGE_FILE_MACHINE_R10000\n")); break;
5337 case IMAGE_FILE_MACHINE_ALPHA: printInf((" IMAGE_FILE_MACHINE_ALPHA\n")); break;
5338 case IMAGE_FILE_MACHINE_POWERPC: printInf((" IMAGE_FILE_MACHINE_POWERPC\n")); break;
5339 default:
5340 printInf((" *unknown*\n"));
5341 }
5342 printInf(("NumberOfSections %d\n", pNtHdrs->FileHeader.NumberOfSections));
5343 printInf(("TimeDataStamp 0x%08x\n", pNtHdrs->FileHeader.TimeDateStamp));
5344 printInf(("PointerToSymbolTable 0x%08x\n", pNtHdrs->FileHeader.PointerToSymbolTable));
5345 printInf(("NumberOfSymbols %d\n", pNtHdrs->FileHeader.NumberOfSymbols));
5346 printInf(("SizeOfOptionalHeader %d\n", pNtHdrs->FileHeader.SizeOfOptionalHeader));
5347 printInf(("Characteristics 0x%04x\n", pNtHdrs->FileHeader.Characteristics));
5348 w = pNtHdrs->FileHeader.Characteristics;
5349 if ((w & IMAGE_FILE_RELOCS_STRIPPED) == IMAGE_FILE_RELOCS_STRIPPED)
5350 printInf((" IMAGE_FILE_RELOCS_STRIPPED\n"));
5351 if ((w & IMAGE_FILE_EXECUTABLE_IMAGE) == IMAGE_FILE_EXECUTABLE_IMAGE)
5352 printInf((" IMAGE_FILE_EXECUTABLE_IMAGE\n"));
5353 if ((w & IMAGE_FILE_LINE_NUMS_STRIPPED) == IMAGE_FILE_LINE_NUMS_STRIPPED)
5354 printInf((" IMAGE_FILE_LINE_NUMS_STRIPPED\n"));
5355 if ((w & IMAGE_FILE_LOCAL_SYMS_STRIPPED) == IMAGE_FILE_LOCAL_SYMS_STRIPPED)
5356 printInf((" IMAGE_FILE_LOCAL_SYMS_STRIPPED\n"));
5357 if ((w & 0x0010) == 0x0010)
5358 printInf((" IMAGE_FILE_AGGRESIVE_WS_TRIM\n"));
5359 if ((w & IMAGE_FILE_BYTES_REVERSED_LO) == IMAGE_FILE_BYTES_REVERSED_LO)
5360 printInf((" IMAGE_FILE_BYTES_REVERSED_LO\n"));
5361 if ((w & IMAGE_FILE_32BIT_MACHINE) == IMAGE_FILE_32BIT_MACHINE)
5362 printInf((" IMAGE_FILE_32BIT_MACHINE\n"));
5363 if ((w & IMAGE_FILE_DEBUG_STRIPPED) == IMAGE_FILE_DEBUG_STRIPPED)
5364 printInf((" IMAGE_FILE_DEBUG_STRIPPED\n"));
5365 if ((w & 0x0400) == 0x0400)
5366 printInf((" IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP\n"));
5367 if ((w & 0x0800) == 0x0800)
5368 printInf((" IMAGE_FILE_NET_RUN_FROM_SWAP\n"));
5369 if ((w & IMAGE_FILE_SYSTEM) == IMAGE_FILE_SYSTEM)
5370 printInf((" IMAGE_FILE_SYSTEM\n"));
5371 if ((w & IMAGE_FILE_DLL) == IMAGE_FILE_DLL)
5372 printInf((" IMAGE_FILE_DLL\n"));
5373 if ((w & 0x4000) == 0x4000)
5374 printInf((" IMAGE_FILE_UP_SYSTEM_ONLY\n"));
5375 if ((w & IMAGE_FILE_BYTES_REVERSED_HI) == IMAGE_FILE_BYTES_REVERSED_HI)
5376 printInf((" IMAGE_FILE_BYTES_REVERSED_HI\n"));
5377
5378 printInf(("\nPE-headers - Optional header\n"));
5379 printInf(("Magic 0x%04x\n", pNtHdrs->OptionalHeader.Magic));
5380 printInf(("MajorLinkerVersion %d\n", pNtHdrs->OptionalHeader.MajorLinkerVersion));
5381 printInf(("MinorLinkerVersion %d\n", pNtHdrs->OptionalHeader.MajorLinkerVersion));
5382 printInf(("SizeOfCode 0x%08x\n", pNtHdrs->OptionalHeader.SizeOfCode));
5383 printInf(("SizeOfInitializedData 0x%08x\n", pNtHdrs->OptionalHeader.SizeOfInitializedData));
5384 printInf(("SizeOfUninitializedData 0x%08x\n", pNtHdrs->OptionalHeader.SizeOfUninitializedData));
5385 printInf(("AddressOfEntryPoint 0x%08x\n", pNtHdrs->OptionalHeader.AddressOfEntryPoint));
5386 printInf(("BaseOfCode 0x%08x\n", pNtHdrs->OptionalHeader.BaseOfCode));
5387 printInf(("BaseOfData 0x%08x\n", pNtHdrs->OptionalHeader.BaseOfData));
5388 printInf(("ImageBase 0x%08x\n", pNtHdrs->OptionalHeader.ImageBase));
5389 printInf(("SectionAlignment 0x%08x\n", pNtHdrs->OptionalHeader.SectionAlignment));
5390 printInf(("FileAlignment 0x%08x\n", pNtHdrs->OptionalHeader.FileAlignment));
5391 printInf(("MajorOperatingSystemVersion %d\n", pNtHdrs->OptionalHeader.MajorOperatingSystemVersion));
5392 printInf(("MinorOperatingSystemVersion %d\n", pNtHdrs->OptionalHeader.MinorOperatingSystemVersion));
5393 printInf(("MajorImageVersion %d\n", pNtHdrs->OptionalHeader.MajorImageVersion));
5394 printInf(("MinorImageVersion %d\n", pNtHdrs->OptionalHeader.MinorImageVersion));
5395 printInf(("MajorSubsystemVersion %d\n", pNtHdrs->OptionalHeader.MajorSubsystemVersion));
5396 printInf(("MinorSubsystemVersion %d\n", pNtHdrs->OptionalHeader.MinorSubsystemVersion));
5397 printInf(("Win32VersionValue 0x%08x\n", pNtHdrs->OptionalHeader.Reserved1));
5398 printInf(("SizeOfImage 0x%08x\n", pNtHdrs->OptionalHeader.SizeOfImage));
5399 printInf(("SizeOfHeaders 0x%08x\n", pNtHdrs->OptionalHeader.SizeOfHeaders));
5400 printInf(("CheckSum 0x%08x\n", pNtHdrs->OptionalHeader.CheckSum));
5401 printInf(("Subsystem 0x%04x\n", pNtHdrs->OptionalHeader.Subsystem));
5402
5403 switch(pNtHdrs->OptionalHeader.Subsystem)
5404 {
5405 case IMAGE_SUBSYSTEM_UNKNOWN: printInf((" IMAGE_SUBSYSTEM_UNKNOWN\n")); break;
5406 case IMAGE_SUBSYSTEM_NATIVE: printInf((" IMAGE_SUBSYSTEM_NATIVE\n")); break;
5407 case IMAGE_SUBSYSTEM_WINDOWS_GUI: printInf((" IMAGE_SUBSYSTEM_WINDOWS_GUI\n")); break;
5408 case IMAGE_SUBSYSTEM_WINDOWS_CUI: printInf((" IMAGE_SUBSYSTEM_WINDOWS_CUI\n")); break;
5409 case IMAGE_SUBSYSTEM_OS2_CUI: printInf((" IMAGE_SUBSYSTEM_OS2_CUI\n")); break;
5410 case IMAGE_SUBSYSTEM_POSIX_CUI: printInf((" IMAGE_SUBSYSTEM_POSIX_CUI\n")); break;
5411 case 8: printInf((" IMAGE_SUBSYSTEM_NATIVE_WINDOWS\n")); break;
5412 case 9: printInf((" IMAGE_SUBSYSTEM_WINDOWS_CE_GUI\n")); break;
5413 default:
5414 printInf((" *unknown*"));
5415 }
5416 printInf(("DllCharacteristics 0x%04x\n", pNtHdrs->OptionalHeader.DllCharacteristics));
5417 printInf(("SizeOfStackReserve 0x%08x\n", pNtHdrs->OptionalHeader.SizeOfStackReserve));
5418 printInf(("SizeOfStackCommit 0x%08x\n", pNtHdrs->OptionalHeader.SizeOfStackCommit));
5419 printInf(("SizeOfHeapReserve 0x%08x\n", pNtHdrs->OptionalHeader.SizeOfHeapReserve));
5420 printInf(("SizeOfHeapCommit 0x%08x\n", pNtHdrs->OptionalHeader.SizeOfHeapCommit));
5421 printInf(("LoaderFlags 0x%08x\n", pNtHdrs->OptionalHeader.LoaderFlags));
5422 printInf(("NumberOfRvaAndSizes 0x%08x\n", pNtHdrs->OptionalHeader.NumberOfRvaAndSizes));
5423
5424 printInf(("\nPE-Headers - DataDirectory\n"));
5425 for (i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++)
5426 {
5427 char *pszName;
5428
5429 switch (i)
5430 {
5431 case IMAGE_DIRECTORY_ENTRY_EXPORT: pszName = "Export Directory (IMAGE_DIRECTORY_ENTRY_EXPORT)"; break;
5432 case IMAGE_DIRECTORY_ENTRY_IMPORT: pszName = "Import Directory (IMAGE_DIRECTORY_ENTRY_IMPORT)"; break;
5433 case IMAGE_DIRECTORY_ENTRY_RESOURCE: pszName = "Resource Directory (IMAGE_DIRECTORY_ENTRY_RESOURCE)"; break;
5434 case IMAGE_DIRECTORY_ENTRY_EXCEPTION: pszName = "Exception Directory (IMAGE_DIRECTORY_ENTRY_EXCEPTION)"; break;
5435 case IMAGE_DIRECTORY_ENTRY_SECURITY: pszName = "Security Directory (IMAGE_DIRECTORY_ENTRY_SECURITY)"; break;
5436 case IMAGE_DIRECTORY_ENTRY_BASERELOC: pszName = "Base Relocation Table (IMAGE_DIRECTORY_ENTRY_BASERELOC)"; break;
5437 case IMAGE_DIRECTORY_ENTRY_DEBUG: pszName = "Debug Directory (IMAGE_DIRECTORY_ENTRY_DEBUG)"; break;
5438 case IMAGE_DIRECTORY_ENTRY_COPYRIGHT: pszName = "Description String (IMAGE_DIRECTORY_ENTRY_COPYRIGHT)"; break;
5439 case IMAGE_DIRECTORY_ENTRY_GLOBALPTR: pszName = "Machine Value (MIPS GP) (IMAGE_DIRECTORY_ENTRY_GLOBALPTR)"; break;
5440 case IMAGE_DIRECTORY_ENTRY_TLS: pszName = "TLS Directory (IMAGE_DIRECTORY_ENTRY_TLS)"; break;
5441 case IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG: pszName = "Load Configuration Directory (IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG)"; break;
5442 case IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT:pszName = "Bound Import Directory in headers (IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT)"; break;
5443 case IMAGE_DIRECTORY_ENTRY_IAT: pszName = "Import Address Table (IMAGE_DIRECTORY_ENTRY_IAT)"; break;
5444 default:
5445 pszName = "unknown";
5446 }
5447
5448 printInf(("%2d %s\n", i, pszName));
5449 printInf((" Address 0x%08x\n", pNtHdrs->OptionalHeader.DataDirectory[i].VirtualAddress));
5450 printInf((" Size 0x%08x\n", pNtHdrs->OptionalHeader.DataDirectory[i].Size));
5451 }
5452 }
5453}
5454
5455
5456/**
5457 * Static method which dumps a section header.
5458 * @param pSection Pointer to a section header.
5459 * @status paritally implemented.
5460 * @author knut st. osmundsen
5461 * @remark Missing flags symbols!
5462 */
5463VOID Pe2Lx::dumpSectionHeader(PIMAGE_SECTION_HEADER pSection)
5464{
5465 if (pSection >= (PIMAGE_SECTION_HEADER)0x10000)
5466 {
5467 printInf(("\nSection Name: %.8s\n", pSection->Name));
5468 printInf(("Raw data size: 0x%08x\n", pSection->SizeOfRawData));
5469 printInf(("Virtual Address: 0x%08x\n", pSection->VirtualAddress));
5470 printInf(("Virtual Size: 0x%08x\n", pSection->Misc.VirtualSize));
5471 printInf(("Pointer to raw data: 0x%08x\n", pSection->PointerToRawData));
5472 printInf(("Section flags: 0x%08x\n", pSection->Characteristics));
5473 /* FIXME! display flags! */
5474 }
5475 else
5476 printInf(("dumpSectionHeader - invalid pointer specified! pSection=%#8x\n", pSection));
5477}
5478
5479
5480/**
5481 * Constructor.
5482 * @param hFile Filehandle.
5483 * @param cObjects Count of objects in the object array pointed to by paObjects.
5484 * @param paObjects Read-only pointer to object array.
5485 * @status completely implemented; tested.
5486 * @author knut st. osmundsen
5487 */
5488BufferedRVARead::BufferedRVARead(SFN hFile, ULONG cObjects, PCLXOBJECT paObjects)
5489 : hFile(hFile), cObjects(cObjects), paObjects(paObjects), ulRVA(~0UL)
5490{
5491}
5492
5493#if 0 /* made inline! */
5494/**
5495 * Reads a chunk of data at the spcified RVA.
5496 * @returns NO_ERROR on success.
5497 * ERROR_INVALID_PARAMETER
5498 * <Whatever rc ReadAt returns>
5499 * @param ulRVA RVA to read from. Within the filesize.
5500 * @param pvBuffer Pointer to output buffer. pvBuffer > 64KB
5501 * @param cbBuffer Number of bytes to read. 0 < cbBuffer > 256MB
5502 * @status completely implemented; tested.
5503 * @author knut st. osmundsen
5504 */
5505ULONG BufferedRVARead::readAtRVA(ULONG ulRVA, PVOID pvBuffer, ULONG cbBuffer)
5506{
5507 /*
5508 * five cases:
5509 * 1) entire area is within the buffer.
5510 * 2) start of area is within the buffer.
5511 * 3) end of area is within the buffer.
5512 * 4) the area is larger than the buffer, covering it.
5513 * 5) the area is outside the buffer.
5514 *
5515 * these are optimal: 1, 2, and 5.
5516 * The request is allways process from start to end. This will make case 3 and 4 less effecient.
5517 */
5518 #ifdef DEBUG
5519 if (ulRVA == ~0UL || (ULONG)pvBuffer < 0x10000UL || cbBuffer == 0UL || cbBuffer >= 0x10000000UL)
5520 return ERROR_INVALID_PARAMETER;
5521 #endif
5522
5523 do
5524 {
5525 if (ulRVA >= this->ulRVA && ulRVA < this->ulRVA + sizeof(achBuffer))
5526 { /* in buffer */
5527 register ULONG cbRead = sizeof(achBuffer) - (ulRVA - this->ulRVA);
5528 cbRead = min(cbRead, cbBuffer);
5529 memcpy(pvBuffer, &achBuffer[ulRVA - this->ulRVA], (size_t)cbRead);
5530 if (cbBuffer == cbRead)
5531 return NO_ERROR;
5532 cbBuffer -= cbRead;
5533 pvBuffer = (PVOID)((ULONG)pvBuffer + cbRead);
5534 ulRVA += cbRead;
5535 }
5536 else
5537 { /* not in buffer, then read it into the buffer! */
5538 APIRET rc = readToBuffer(ulRVA);
5539 if (rc != NO_ERROR)
5540 return rc;
5541 }
5542 } while (cbBuffer != 0UL);
5543
5544 return NO_ERROR;
5545}
5546#endif
5547
5548
5549/**
5550 * Reads a zero string into a heap block and returns it to the caller (thru ppsz).
5551 * @returns NO_ERROR
5552 * ERROR_INVALID_PARAMETER
5553 * ERROR_NOT_ENOUGH_MEMORY
5554 * Return code from ReadAt.
5555 * @param ulRVA RVA which the string is to be read from.
5556 * @param ppsz Pointer to a stringpointer. Output: This will hold pointer to a heapblock with the string.
5557 * @status completely implemented; tested.
5558 * @author knut st. osmundsen
5559 */
5560ULONG BufferedRVARead::dupString(ULONG ulRVA, PSZ *ppsz)
5561{
5562 #ifdef DEBUG
5563 if (ulRVA == ~0UL || ppsz == NULL)
5564 return ERROR_INVALID_PARAMETER;
5565 #endif
5566
5567 if (ppsz < (PSZ*)0x10000UL)
5568 {
5569 printErr(("Call to dupString with a unconverted stack pointer!.\n"));
5570 ppsz = (PSZ*)SSToDS(ppsz);
5571 }
5572
5573 *ppsz = NULL;
5574 ULONG cchAllocated = 0UL;
5575 ULONG offCurrent = 0UL;
5576 while (TRUE)
5577 {
5578 if (ulRVA >= this->ulRVA && ulRVA < this->ulRVA + sizeof(achBuffer))
5579 { /* in buffer */
5580 ULONG cchAlloc;
5581 PCHAR pch = (PCHAR)memchr(&achBuffer[ulRVA - this->ulRVA], '\0',
5582 sizeof(achBuffer) - (size_t)(ulRVA - this->ulRVA));
5583
5584 /* amout of memory to allocate */
5585 if (pch != NULL)
5586 cchAlloc = (ULONG)pch - (ULONG)&achBuffer[ulRVA - this->ulRVA] + 1;
5587 else
5588 cchAlloc = sizeof(achBuffer) - (ulRVA - this->ulRVA) + 42; /* 42 - think of a number... */
5589
5590 /* allocate (more) memory */
5591 if (*ppsz == NULL)
5592 *ppsz = (PSZ)malloc((size_t)cchAlloc);
5593 else
5594 {
5595 PVOID pv = realloc(*ppsz, (size_t)(cchAlloc + cchAllocated));
5596 if (pv == NULL)
5597 {
5598 free(*ppsz);
5599 *ppsz = NULL;
5600 return ERROR_NOT_ENOUGH_MEMORY;
5601 }
5602 *ppsz = (PSZ)pv;
5603 }
5604 cchAllocated += cchAlloc;
5605
5606 /* copy string data */
5607 if (pch != NULL)
5608 { /* final part of the string. */
5609 strcpy(&(*ppsz)[offCurrent], &achBuffer[ulRVA - this->ulRVA]);
5610 break;
5611 }
5612 /* more to come */
5613 memcpy(&(*ppsz)[offCurrent], &achBuffer[ulRVA - this->ulRVA], sizeof(achBuffer) - (size_t)(ulRVA - this->ulRVA));
5614 offCurrent += sizeof(achBuffer) - (ulRVA - this->ulRVA);
5615 ulRVA = ALIGN(ulRVA+1, sizeof(achBuffer));
5616 }
5617 else
5618 { /* not in buffer, then read it into the buffer! */
5619 APIRET rc = readToBuffer(ulRVA);
5620 if (rc != NO_ERROR)
5621 return rc;
5622 }
5623 }
5624
5625 return NO_ERROR;
5626}
5627
5628
5629/**
5630 * Assignment operator.
5631 * @returns Reference to this BufferedRVARead object.
5632 * @param SrcObj The object on the right side of the operator.
5633 * @status completely implemented.
5634 * @author knut st. osmundsen
5635 */
5636BufferedRVARead & BufferedRVARead::operator =(BufferedRVARead &SrcObj)
5637{
5638 hFile = SrcObj.hFile;
5639 cObjects = SrcObj.cObjects;
5640 paObjects = SrcObj.paObjects;
5641 ulRVA = SrcObj.ulRVA;
5642 if (ulRVA != ~0UL)
5643 memcpy(&achBuffer[0], &SrcObj.achBuffer[0], sizeof(achBuffer));
5644 return *this;
5645}
5646
5647
5648/**
5649 * Reads data to the buffer for a given RVA.
5650 * @returns NO_ERROR
5651 * ERROR_INVALID_PARAMETER
5652 * Return code from ReadAt.
5653 * @param ulRVA RVA to read at/near.
5654 * @status completely implemented; tested.
5655 * @author knut st. osmundsen
5656 */
5657ULONG BufferedRVARead::readToBuffer(ULONG ulRVA)
5658{
5659 ULONG ulRVARead;
5660
5661 /* where to read? */
5662 if (ulRVA != this->ulRVA + sizeof(achBuffer) || this->ulRVA == ~0UL)
5663 ulRVARead = this->ulRVA = ulRVA & ~(PAGESIZE-1UL); /* align on page boundrary - ASSUMES: buffersize >= PAGESIZE! */
5664 else
5665 ulRVARead = this->ulRVA += sizeof(achBuffer); /* immediately after current buffer */
5666
5667 ULONG cbLeftToRead = sizeof(achBuffer);
5668 ULONG iObj = 0;
5669 while (cbLeftToRead != 0UL)
5670 {
5671 while (iObj < cObjects
5672 && ulRVARead >= (iObj + 1 < cObjects ? paObjects[iObj+1].ulRVA
5673 : paObjects[iObj].ulRVA + ALIGN(paObjects[iObj].cbVirtual, PAGESIZE))
5674 )
5675 iObj++;
5676 if (iObj >= cObjects)
5677 {
5678 this->ulRVA = ~0UL;
5679 return ERROR_INVALID_PARAMETER;
5680 }
5681
5682 /* ulRVARead points at physical or virtual data? */
5683 if (ulRVARead < paObjects[iObj].ulRVA + paObjects[iObj].cbPhysical)
5684 { /* physical data - read from file */
5685 APIRET rc;
5686 ULONG cbToRead = min(paObjects[iObj].ulRVA + paObjects[iObj].cbPhysical - ulRVARead, cbLeftToRead);
5687 rc = ReadAt(hFile,
5688 ulRVARead - paObjects[iObj].ulRVA + paObjects[iObj].offPEFile,
5689 &achBuffer[sizeof(achBuffer)-cbLeftToRead],
5690 cbToRead
5691 );
5692 if (rc != NO_ERROR)
5693 {
5694 this->ulRVA = ~0UL;
5695 return rc;
5696 }
5697 cbLeftToRead -= cbToRead;
5698 ulRVARead += cbToRead;
5699 }
5700 else
5701 { /* virtual data - memset(,0,) */
5702 ULONG cbToSet = (iObj + 1 < cObjects ? paObjects[iObj+1].ulRVA
5703 : paObjects[iObj].ulRVA + ALIGN(paObjects[iObj].cbVirtual, PAGESIZE))
5704 - ulRVARead; /* calcs size of virtual data left in this object */
5705 cbToSet = min(cbToSet, cbLeftToRead);
5706
5707 memset(&achBuffer[sizeof(achBuffer)-cbLeftToRead], 0, (size_t)cbToSet);
5708 cbLeftToRead -= cbToSet;
5709 ulRVARead += cbToSet;
5710 }
5711 }
5712
5713 return NO_ERROR;
5714}
5715
5716
5717/* end of file */
Note: See TracBrowser for help on using the repository browser.