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

Last change on this file since 5655 was 5328, checked in by bird, 24 years ago

Use VIO Console for CUI applications.

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