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

Last change on this file since 1875 was 1875, checked in by bird, 26 years ago

Made sure Kernel32 is the first entry in the import module name table.

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