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

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

Another bug - empty baserelocation chunk.

File size: 170.3 KB
Line 
1/* $Id: pe2lx.cpp,v 1.10 1999-11-16 17:09:31 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 * Initiate the import variables (if any imports):
1711 * Loop thru the import descriptiors looking for the lowest FirstThunk RVA. (ulRVAOrgFirstThunk and ulRVAFirstThunk)
1712 * When found read the module name and add it. (ulModuleOrdinal)
1713 * Initiate base relocations by reading the first Base Relocation.
1714 * Initiate iObj to 0UL, ulRVAPage to the RVA for the first object (which is allways 0UL!).
1715 *
1716 * LOOP thru all objects as long as all processing is successful
1717 * BEGIN
1718 * Add a new page table entry.
1719 * IF Page with TIBFix THEN add import fixup for RegisterEXE/DLL call.
1720 * IF Import fixups on current page THEN
1721 * BEGIN
1722 * LOOP while no processing errors and more imports on this page
1723 * BEGIN
1724 * Read Thunk
1725 * IF not end of thunk array THEN
1726 * BEGIN
1727 * IF ordinal import THEN add ordinal import fixup
1728 * ELSE IF valid RVA THEN
1729 * get name and add name import fixup
1730 * ELSE
1731 * complain and fail.
1732 * Next Thunk array element (ulRVAFirstThunk and ulRVAOrgFirstThunk)
1733 * END
1734 * ELSE
1735 * BEGIN
1736 * LOOP thru ImportDescriptors and find the following FirstThunk array. (ulRVAOrgFirstThunk and ulRVAFirstThunk)
1737 * IF found THEN read the module name and add it. (ulModuleOrdinal)
1738 * ELSE Disable Import Processing.
1739 * END
1740 * END
1741 * END
1742 * IF BaseRelocation chunk for current page THEN
1743 * BEGIN
1744 * LOOP thru all relocation in this chunk.
1745 * BEGIN
1746 * Get relocation type/offset.
1747 * Get target.
1748 * IF BASED_HIGHLOW fixup THEN add it ELSE ignore it.
1749 * END
1750 * Read next relocation chunk header - if any.
1751 * END
1752 * Next page in object or next object. (ulRVAPage and iObj)
1753 * END
1754 * IF success THEN add final page table entry.
1755 * delete reader objects.
1756 * IF success THEN release unused memory in fixup and import structures.
1757 * return errorcode.
1758 *
1759 * @status completely
1760 * @author knut st. osmundsen
1761 * @remark stack usage: 26*4 + 5*4 = 124 bytes
1762 * heap usage: 5 blocks   (4096 + 4*4) bytes = 20110 bytes
1763 * See bottom of addForwarderEntry remark!
1764 *
1765 * BTW. This piece of code remindes me about cobol programming - large and clumsy.
1766 * (I have not programmed cobol, but have read and debugged it.)
1767 */
1768ULONG Pe2Lx::makeFixups()
1769{
1770 BOOL fImports; /* fImport is set when a valid import directory is present. */
1771 ULONG ulRVAImportDesc; /* RVA of the first import descriptor. */
1772 IMAGE_IMPORT_DESCRIPTOR ImportDesc; /* Import descriptor struct used while reading. */
1773 BufferedRVARead *pImportReader; /* Buffered reader import descriptors reads. */
1774 BufferedRVARead *pImpNameReader; /* Buffered reader for names reads; ie. function and module names. */
1775 BufferedRVARead *pImpThunkReader; /* Buffered reader for thunk reads; ie. reading from the OrgiginalFirstThunk array. */
1776 ULONG ulModuleOrdinal; /* Module ordinal. Valid as long as fImport is set. */
1777 ULONG ulRVAFirstThunk; /* Current first thunk array RVA. Points at current entry. */
1778 ULONG ulRVAOrgFirstThunk; /* Current original first thunk array RVA. Points at current entry. */
1779
1780 BOOL fBaseRelocs; /* fBaseReloc is set when a valid base reloc directory is present. */
1781 ULONG ulRVABaseReloc; /* RVA of the current base relocation chunk. (Not the first!) */
1782 LONG cbBaseRelocs; /* Count of bytes left of base relocation. Used to determin eof baserelocs. */
1783 IMAGE_BASE_RELOCATION BaseReloc; /* Base Relocation struct which is used while reading. */
1784 BufferedRVARead *pPageReader; /* Buffered reader for page reads; ie. getting the target address. */
1785 BufferedRVARead *pRelocReader; /* Buffered reader for relocation reads; ie getting the type/offset word. */
1786
1787 ULONG ulRVAPage; /* RVA for the current page. */
1788 ULONG ul; /* temporary unsigned long variable. Many uses. */
1789 PSZ psz; /* temporary string pointer. Used for modulenames and functionnames. */
1790 ULONG iObj; /* Object iterator. (Index into paObjects) */
1791 APIRET rc; /* return code. */
1792
1793 /* Test if valid fixup data pointers - return if vaild */
1794 if (pFixupRecords != NULL && paulFixupPageTable != NULL)
1795 return NO_ERROR;
1796
1797 /* initiate data members of this object */
1798 rc = initFixups();
1799 if (rc != NO_ERROR)
1800 return rc;
1801
1802 /* Check that the NtHdr is valid. */
1803 rc = loadNtHeaders();
1804 if (rc != NO_ERROR)
1805 return rc;
1806
1807 /* if there are forwarder entries present, we'll have to make them first. */
1808 if (fForwarders && pEntryBundles == NULL)
1809 {
1810 rc = makeExports();
1811 if (rc != NO_ERROR)
1812 return rc;
1813 }
1814
1815 /* Check if empty import directory. */
1816 fImports = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size > 0UL
1817 &&
1818 (ulRVAImportDesc = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress) > 0UL
1819 &&
1820 ulRVAImportDesc < pNtHdrs->OptionalHeader.SizeOfImage;
1821
1822 /* Check if empty base relocation directory. */
1823 fBaseRelocs = (cbBaseRelocs = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size) > 0UL
1824 &&
1825 (ulRVABaseReloc = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) > 0UL
1826 &&
1827 ulRVABaseReloc < pNtHdrs->OptionalHeader.SizeOfImage;
1828
1829 printInf(("\n"));
1830 printInf(("Make fixups, fBaseReloc=%s, fImports=%s\n",
1831 fBaseRelocs ? "true" : "false",
1832 fImports ? "true" : "false"));
1833 printInf(("\n"));
1834
1835 /* create reader buffers */
1836 if (fBaseRelocs)
1837 {
1838 pPageReader = new BufferedRVARead(hFile, cObjects, paObjects);
1839 pRelocReader = new BufferedRVARead(hFile, cObjects, paObjects);
1840 if (pPageReader == NULL || pRelocReader == NULL)
1841 rc = ERROR_NOT_ENOUGH_MEMORY;
1842 }
1843 else
1844 pRelocReader = pPageReader = NULL;
1845 if (fImports)
1846 {
1847 pImportReader = new BufferedRVARead(hFile, cObjects, paObjects);
1848 pImpNameReader = new BufferedRVARead(hFile, cObjects, paObjects);
1849 pImpThunkReader = new BufferedRVARead(hFile, cObjects, paObjects);
1850 if (pImportReader == NULL || pImpNameReader == NULL || pImpThunkReader == NULL)
1851 rc = ERROR_NOT_ENOUGH_MEMORY;
1852 }
1853 else
1854 pImpThunkReader = pImpNameReader = pImportReader = NULL;
1855
1856 /* check for errors */
1857 if (rc != NO_ERROR)
1858 { /* error: clean up and return! */
1859 if (pPageReader != NULL)
1860 delete pPageReader;
1861 if (pRelocReader != NULL)
1862 delete pRelocReader;
1863 if (pImportReader != NULL)
1864 delete pImportReader;
1865 if (pImpNameReader != NULL)
1866 delete pImpNameReader;
1867 if (pImpThunkReader != NULL)
1868 delete pImpThunkReader;
1869 return rc;
1870 }
1871
1872 /* initiate the import variables */
1873 if (fImports && rc == NO_ERROR)
1874 {
1875 rc = pImportReader->readAtRVA(ulRVAImportDesc, SSToDS(&ImportDesc), sizeof(ImportDesc));
1876 if (rc == NO_ERROR)
1877 {
1878 ul = 0;
1879 ulRVAFirstThunk = ~0UL;
1880 while (rc == NO_ERROR && ImportDesc.Name != 0UL && ImportDesc.FirstThunk != 0UL)
1881 {
1882 if ((ULONG)ImportDesc.FirstThunk < ulRVAFirstThunk || ulRVAFirstThunk == 0UL) /* 0 test: just in case... */
1883 {
1884 ulRVAFirstThunk = (ULONG)ImportDesc.FirstThunk;
1885 ulRVAOrgFirstThunk = (ULONG)ImportDesc.u.OriginalFirstThunk != 0UL ?
1886 (ULONG)ImportDesc.u.OriginalFirstThunk : (ULONG)ImportDesc.FirstThunk;
1887 ulModuleOrdinal = ImportDesc.Name;
1888 }
1889
1890 /* next */
1891 ul++;
1892 rc = pImportReader->readAtRVA(ulRVAImportDesc + ul * sizeof(ImportDesc), SSToDS(&ImportDesc), sizeof(ImportDesc));
1893 }
1894
1895 if (ulRVAFirstThunk != ~0UL)
1896 {
1897 rc = pImpNameReader->dupString(ulModuleOrdinal, (PSZ*)SSToDS(&psz));
1898 if (rc == NO_ERROR)
1899 rc = addModule(psz, (PULONG)SSToDS(&ulModuleOrdinal));
1900 free(psz);
1901 }
1902 else
1903 fImports = FALSE;
1904 }
1905 }
1906
1907 /* read start of the first basereloc chunk */
1908 if (fBaseRelocs)
1909 rc = pRelocReader->readAtRVA(ulRVABaseReloc, SSToDS(&BaseReloc), sizeof(BaseReloc));
1910
1911 /*
1912 * The Loop! Iterate thru all pages for all objects.
1913 */
1914 iObj = 0UL;
1915 if (iObj < cObjects)
1916 ulRVAPage = paObjects[iObj].ulRVA;
1917 while (iObj < cObjects && rc == NO_ERROR)
1918 {
1919 printInfA(("Page at RVA=0x%08x, object no.%d\n", ulRVAPage, iObj));
1920
1921 /* insert new fixup page and fixup record structs */
1922 rc = addPageFixupEntry();
1923 if (rc != NO_ERROR)
1924 break;
1925
1926 /* check for TibFix, add import fixup for it */
1927 if (paObjects[iObj].Misc.fTIBFixObject
1928 && ((paObjects[iObj].Misc.offTIBFix + paObjects[iObj].ulRVA) & ~(PAGESIZE-1UL)) == ulRVAPage)
1929 {
1930 rc = addModule("KERNEL32.DLL", (PULONG)SSToDS(&ul));
1931 if (rc == NO_ERROR)
1932 {
1933 printInfA(("TibFix import fixup\n"));
1934 rc = add32OrdImportFixup((WORD)((paObjects[iObj].Misc.offTIBFix + paObjects[iObj].ulRVA + TIBFIX_OFF_CALLADDRESS) & (PAGESIZE-1UL)),
1935 ul,
1936 pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL ?
1937 ORD_REGISTERPE2LXDLL : ORD_REGISTERPE2LXEXE);
1938 }
1939 if (rc != NO_ERROR)
1940 break;
1941 }
1942
1943
1944 /* check for imports at this page */
1945 if (fImports && ulRVAFirstThunk < ulRVAPage + PAGESIZE)
1946 {
1947 while (rc == NO_ERROR && ulRVAFirstThunk < ulRVAPage + PAGESIZE)
1948 {
1949 IMAGE_THUNK_DATA Thunk;
1950 rc = pImpThunkReader->readAtRVA(ulRVAOrgFirstThunk, SSToDS(&Thunk), sizeof(Thunk));
1951 if (rc != NO_ERROR)
1952 break;
1953 if (Thunk.u1.Ordinal != 0UL)
1954 {
1955 if (Thunk.u1.Ordinal & (ULONG)IMAGE_ORDINAL_FLAG)
1956 rc = add32OrdImportFixup((WORD)(ulRVAFirstThunk & (PAGESIZE-1)),
1957 ulModuleOrdinal, Thunk.u1.Ordinal & 0xffff);
1958 else if (Thunk.u1.Ordinal > 0UL && Thunk.u1.Ordinal < pNtHdrs->OptionalHeader.SizeOfImage)
1959 {
1960 rc = pImpNameReader->dupString(Thunk.u1.Ordinal + offsetof(IMAGE_IMPORT_BY_NAME, Name),
1961 (PSZ*)SSToDS(&psz));
1962 if (rc != NO_ERROR)
1963 break;
1964 rc = add32NameImportFixup((WORD)(ulRVAFirstThunk & (PAGESIZE-1)),
1965 ulModuleOrdinal, psz);
1966 free(psz);
1967 }
1968 else
1969 {
1970 printErr(("invalid value in thunk array, neither an ordinal value nor an valid RVA. 0x%08x\n", Thunk.u1.Ordinal));
1971 rc = ERROR_INVALID_ADDRESS;
1972 break;
1973 }
1974
1975 /* next */
1976 ulRVAFirstThunk += sizeof(IMAGE_THUNK_DATA);
1977 ulRVAOrgFirstThunk += sizeof(IMAGE_THUNK_DATA);
1978 }
1979 else
1980 { /* next module */
1981 rc = pImportReader->readAtRVA(ulRVAImportDesc, SSToDS(&ImportDesc), sizeof(ImportDesc));
1982 if (rc == NO_ERROR)
1983 {
1984 ULONG ulRVAFirstThunkPrev = ulRVAFirstThunk;
1985 ul = 0;
1986 ulRVAFirstThunk = ~0UL;
1987 while (rc == NO_ERROR && ImportDesc.Name != 0UL && ImportDesc.FirstThunk != 0UL)
1988 {
1989 if ((ULONG)ImportDesc.FirstThunk < ulRVAFirstThunk
1990 && (ULONG)ImportDesc.FirstThunk > ulRVAFirstThunkPrev)
1991 {
1992 ulRVAFirstThunk = (ULONG)ImportDesc.FirstThunk;
1993 ulRVAOrgFirstThunk = (ULONG)ImportDesc.u.OriginalFirstThunk != 0UL ?
1994 (ULONG)ImportDesc.u.OriginalFirstThunk : (ULONG)ImportDesc.FirstThunk;
1995 ulModuleOrdinal = ImportDesc.Name;
1996 }
1997
1998 /* next */
1999 ul++;
2000 rc = pImportReader->readAtRVA(ulRVAImportDesc + ul * sizeof(ImportDesc), SSToDS(&ImportDesc), sizeof(ImportDesc));
2001 }
2002
2003 if (ulRVAFirstThunk != ~0UL)
2004 { /* modulename */
2005 rc = pImpNameReader->dupString(ulModuleOrdinal, (PSZ*)SSToDS(&psz));
2006 if (rc == NO_ERROR)
2007 {
2008 rc = addModule(psz, (PULONG)SSToDS(&ulModuleOrdinal));
2009 free(psz);
2010 }
2011 }
2012 else
2013 fImports = FALSE;
2014 }
2015 }
2016 } /* while */
2017 if (rc != NO_ERROR)
2018 break;
2019 }
2020
2021
2022 /* check for fixups for this page. ASSUMES that fixups are sorted and that each chunk covers one page, no more no less. */
2023 if (fBaseRelocs && BaseReloc.VirtualAddress == ulRVAPage)
2024 {
2025 ULONG c = (BaseReloc.SizeOfBlock - sizeof(BaseReloc.SizeOfBlock) - sizeof(BaseReloc.VirtualAddress)) / sizeof(WORD); /* note that sizeof(BaseReloc) is 12 bytes! */
2026 PWORD pawoffFixup;
2027
2028 if (c != 0)
2029 {
2030 pawoffFixup = (PWORD)malloc((size_t)(c * sizeof(WORD)));
2031 if (pawoffFixup != NULL)
2032 rc = pRelocReader->readAtRVA(ulRVABaseReloc + offsetof(IMAGE_BASE_RELOCATION, TypeOffset),
2033 pawoffFixup, c * sizeof(WORD));
2034 else
2035 rc = ERROR_NOT_ENOUGH_MEMORY;
2036
2037 /* loop thru the baserelocation in this chunk. */
2038 for (ul = 0; ul < c && rc == NO_ERROR; ul++)
2039 {
2040 WORD woffFixup;
2041 ULONG ulTarget;
2042 /* Get relocation type/offset. */
2043 if (pawoffFixup != NULL)
2044 woffFixup = pawoffFixup[ul];
2045
2046 /* Get target. */
2047 rc = pPageReader->readAtRVA(BaseReloc.VirtualAddress + (woffFixup & 0x0FFF),
2048 SSToDS(&ulTarget), sizeof(ulTarget));
2049 if (rc == NO_ERROR)
2050 {
2051 switch (woffFixup >> 12)
2052 {
2053 case IMAGE_REL_BASED_HIGHLOW:
2054 rc = add32OffsetFixup((WORD)(woffFixup & 0x0FFF), ulTarget);
2055 printInfA(("Fixup: 0x%03x target 0x%08x (rc = %d) %s\n",
2056 (woffFixup & 0x0FFF), ulTarget, rc,
2057 pvCrossPageFixup ? "crosspage" : ""));
2058 break;
2059 case IMAGE_REL_BASED_ABSOLUTE: /* ignored! */
2060 break;
2061 default:
2062 printWar(("Unknown/unsupported fixup type!, 0x%1x\n", woffFixup >> 12));
2063 }
2064 }
2065 }
2066 }
2067
2068 /* cleanup */
2069 if (pawoffFixup != NULL)
2070 free(pawoffFixup);
2071
2072 /* break on error */
2073 if (rc != NO_ERROR)
2074 break;
2075
2076 /* read next descriptor if any */
2077 ulRVABaseReloc += BaseReloc.SizeOfBlock;
2078 cbBaseRelocs -= BaseReloc.SizeOfBlock;
2079 if (cbBaseRelocs > 0)
2080 {
2081 rc = pRelocReader->readAtRVA(ulRVABaseReloc, SSToDS(&BaseReloc), sizeof(BaseReloc));
2082 if (rc != NO_ERROR)
2083 break;
2084 }
2085 else
2086 fBaseRelocs = FALSE;
2087 }
2088
2089 /** next **/
2090 if (ulRVAPage + PAGESIZE >=
2091 (fAllInOneObject && iObj + 1 < cObjects ?
2092 paObjects[iObj + 1].ulRVA : paObjects[iObj].ulRVA + paObjects[iObj].cbVirtual)
2093 )
2094 { /* object++ */
2095 iObj++;
2096 if (iObj < cObjects)
2097 ulRVAPage = paObjects[iObj].ulRVA;
2098 }
2099 else /* page++ */
2100 ulRVAPage += PAGESIZE;
2101 Yield();
2102 } /* The Loop! */
2103
2104
2105 /* insert final fixup page struct */
2106 if (rc == NO_ERROR)
2107 rc = addPageFixupEntry(TRUE);
2108
2109 /* finished! - cleanup! */
2110 if (pPageReader != NULL)
2111 delete pPageReader;
2112 if (pRelocReader != NULL)
2113 delete pRelocReader;
2114 if (pImportReader != NULL)
2115 delete pImportReader;
2116 if (pImpNameReader != NULL)
2117 delete pImpNameReader;
2118 if (pImpThunkReader != NULL)
2119 delete pImpThunkReader;
2120
2121 /* Release unused memory in fixup and import structures. */
2122 if (rc == NO_ERROR)
2123 {
2124 finalizeImportNames();
2125 finalizeFixups();
2126 }
2127 return rc;
2128}
2129
2130
2131/**
2132 * Convert exports to LX entries and resident name table.
2133 * It also creates the modulename.
2134 * @returns Return code. (NO_ERROR)
2135 * @sketch IF valid pointers THEN - nothing to do - return successfully.
2136 * Check that the NtHdr is valid.
2137 * Init datastructues.
2138 * Add modulename to resident name table with ordinal 0.
2139 * IF empty export directory THEN finalizeExports and return successfully.
2140 * Create buffered readers.
2141 * Read Export Directory.
2142 * Convert Address of Functions to LX entry points:
2143 * LOOP thru all entries in the AddressOfFunctions array
2144 * BEGIN
2145 * Read entry. (ulRVA)
2146 * IF forwarder THEN add forwarder.
2147 * IF not forwarder THEN add entry.
2148 * END
2149 *
2150 * Convert function names to resident names (if any names of course).
2151 * LOOP thru all entries in the two parallell arrays AddressOfNames and AddressOfNameOrdinals
2152 * BEGIN
2153 * Read entries from both tables.
2154 * Read Name.
2155 * Add resident name.
2156 * END
2157 *
2158 * Add last entry.
2159 * Delete readers.
2160 * Finalize Exports.
2161 * return return code.
2162 *
2163 * @status completely implemented.
2164 * @author knut st. osmundsen
2165 */
2166ULONG Pe2Lx::makeExports()
2167{
2168 IMAGE_EXPORT_DIRECTORY ExpDir; /* Export directory struct used when reading the export directory. */
2169 BufferedRVARead *pFATFOTReader; /* Buffered reader for function address table and function ordinal table reads. */
2170 BufferedRVARead *pFNTReader; /* Buffered reader for function name table reads. */
2171 BufferedRVARead *pNameReader; /* Buffered reader for function name and forwarder 'dll.function' reads. */
2172 ULONG ulRVAExportDir;
2173 APIRET rc;
2174 PSZ psz;
2175
2176
2177 /* check if valid pointers - nothing to do - return successfully.*/
2178 if (pEntryBundles != NULL && pachResNameTable != NULL)
2179 return NO_ERROR;
2180
2181 /* Check that the NtHdr is valid. */
2182 rc = loadNtHeaders();
2183 if (rc != NO_ERROR)
2184 return rc;
2185
2186 /* Init datastructues. */
2187 rc = initEntry();
2188 if (rc != NO_ERROR)
2189 return rc;
2190
2191 /* Add modulename to resident name table with ordinal 0. */
2192 rc = addResName(0UL, pszModuleName, ~0UL);
2193 if (rc != NO_ERROR)
2194 return rc;
2195
2196 /* Check if empty export directory. */
2197 if (!(pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size > 0UL
2198 &&
2199 (ulRVAExportDir = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) > 0UL
2200 &&
2201 ulRVAExportDir < pNtHdrs->OptionalHeader.SizeOfImage))
2202 { /* no exports */
2203 finalizeExports();
2204 return rc;
2205 }
2206
2207 printInf(("\n"));
2208 printInf(("Make exports\n"));
2209 printInf(("\n"));
2210
2211 /* Create buffered readers. */
2212 pFATFOTReader = new BufferedRVARead(hFile, cObjects, paObjects);
2213 pFNTReader = new BufferedRVARead(hFile, cObjects, paObjects);
2214 pNameReader = new BufferedRVARead(hFile, cObjects, paObjects);
2215 if (pFATFOTReader != NULL && pFNTReader != NULL && pNameReader != NULL)
2216 {
2217 /* Read export directory. */
2218 rc = pFATFOTReader->readAtRVA(ulRVAExportDir, SSToDS(&ExpDir), sizeof(ExpDir));
2219 if (rc == NO_ERROR)
2220 {
2221 ULONG ulRVA;
2222 ULONG ul;
2223
2224 /* (try) optimize diskreads. */
2225 if ((ULONG)ExpDir.AddressOfFunctions < ulRVAExportDir + BUFFEREDRVAREADER_BUFFERSIZE)
2226 *pFNTReader = *pFATFOTReader;
2227 *pNameReader = *pFATFOTReader;
2228
2229 /* Convert Address of Functions to LX entry points. */
2230 for (ul = 0; ul < ExpDir.NumberOfFunctions && rc == NO_ERROR; ul++)
2231 {
2232 rc = pFATFOTReader->readAtRVA((ULONG)ExpDir.AddressOfFunctions + sizeof(ULONG)*ul,
2233 SSToDS(&ulRVA), sizeof(ulRVA));
2234 /* empty? */
2235 if (ulRVA != 0UL)
2236 {
2237 BOOL fForwarder = FALSE;
2238
2239 /* forwarder? ulRVA within export directory. */
2240 if (ulRVA > pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
2241 && ulRVA < pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
2242 + pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size
2243 )
2244 { /* forwarder!(?) */
2245 PSZ pszDll;
2246 PSZ pszFn;
2247 rc = pNameReader->dupString(ulRVA, (PSZ*)SSToDS(&pszDll));
2248 if (rc != NO_ERROR)
2249 break;
2250 pszFn = strchr(pszDll, '.');
2251 if (pszFn != NULL && strlen(pszDll) != 0 && strlen(pszFn) != 0)
2252 {
2253 *pszFn++ = '\0';
2254 rc = addForwarderEntry(ul + ExpDir.Base, pszDll, pszFn);
2255 fForwarder = TRUE;
2256 }
2257 free(pszDll);
2258 }
2259
2260 /* non-forwarder export? */
2261 if (!fForwarder)
2262 rc = addEntry(ul + ExpDir.Base, ulRVA);
2263 }
2264 } /* for loop - export --> entry */
2265 if (rc != NO_ERROR)
2266 printErr(("export --> entry loop failed! ul = %d rc = %d\n", ul, rc));
2267 Yield();
2268
2269 /* Convert function names to resident names. */
2270 if (rc == NO_ERROR && ExpDir.NumberOfNames > 0UL)
2271 {
2272 if ((ULONG)ExpDir.AddressOfNameOrdinals != 0UL && (ULONG)ExpDir.AddressOfNames != 0UL
2273 && (ULONG)ExpDir.AddressOfNameOrdinals < pNtHdrs->OptionalHeader.SizeOfImage
2274 && (ULONG)ExpDir.AddressOfNames < pNtHdrs->OptionalHeader.SizeOfImage
2275 )
2276 {
2277 WORD usOrdinal;
2278
2279 for (ul = 0; ul < ExpDir.NumberOfNames && rc == NO_ERROR; ul++)
2280 {
2281 rc = pFNTReader->readAtRVA((ULONG)ExpDir.AddressOfNames + ul * sizeof(ULONG),
2282 SSToDS(&ulRVA), sizeof(ulRVA));
2283 if (rc != NO_ERROR)
2284 break;
2285 rc = pFATFOTReader->readAtRVA((ULONG)ExpDir.AddressOfNameOrdinals + ul * sizeof(WORD),
2286 SSToDS(&usOrdinal), sizeof(usOrdinal));
2287 if (rc != NO_ERROR)
2288 break;
2289 usOrdinal += ExpDir.Base;
2290 rc = pNameReader->dupString(ulRVA, (PSZ*)SSToDS(&psz));
2291 if (rc != NO_ERROR)
2292 break;
2293 rc = addResName(usOrdinal, psz, ~0UL);
2294 free(psz);
2295 Yield();
2296 }
2297 if (rc != NO_ERROR)
2298 printErr(("FnNames --> ResNames loop failed! ul = %d rc = %d\n", ul, rc));
2299 }
2300 else
2301 {
2302 printErr(("NumberOfNames = %d but AddressOfNames = 0x%08x and AddressOfNameOrdinals = 0x%08x, invalid RVA(s)!\n",
2303 ExpDir.AddressOfNames, ExpDir.AddressOfNameOrdinals));
2304 rc = ERROR_BAD_EXE_FORMAT;
2305 } /* endifelse: 'Names' integrity check */
2306
2307 /* Add last entry. */
2308 if (rc == NO_ERROR)
2309 rc = addLastEntry();
2310
2311 } /* endif: name */
2312 }
2313 }
2314 else
2315 rc = ERROR_NOT_ENOUGH_MEMORY;
2316
2317 /* delete readers */
2318 if (pFATFOTReader != NULL)
2319 delete pFATFOTReader;
2320 if (pFNTReader != NULL)
2321 delete pFNTReader;
2322 if (pNameReader != NULL)
2323 delete pNameReader;
2324
2325 /* Release unused memory in export structures */
2326 if (rc == NO_ERROR)
2327 finalizeExports();
2328
2329 return rc;
2330}
2331
2332
2333/**
2334 * Load the NT headers from disk if they're not present.
2335 * Call this function to make sure that pNtHdrs is valid.
2336 * @returns Error code. (NO_ERROR == success)
2337 * @status Competely implemented; tested.
2338 * @author knut st. osmundsen
2339 * @remark Minor error: Don't read more datadirectory entries than defined in the header files.
2340 * This is not a problem since we'll only use some of the first ones.
2341 */
2342ULONG Pe2Lx::loadNtHeaders()
2343{
2344 APIRET rc;
2345 if (pNtHdrs != NULL)
2346 return NO_ERROR;
2347 pNtHdrs = (PIMAGE_NT_HEADERS)malloc(sizeof(IMAGE_NT_HEADERS));
2348 if (pNtHdrs == NULL)
2349 return ERROR_NOT_ENOUGH_MEMORY;
2350 rc = ReadAt(hFile, offNtHeaders, pNtHdrs, sizeof(IMAGE_NT_HEADERS));
2351 if (rc != NO_ERROR)
2352 {
2353 free(pNtHdrs);
2354 pNtHdrs = NULL;
2355 }
2356 return rc;
2357}
2358
2359
2360/**
2361 * Releases memory used by the pNtHdrs pointer.
2362 * @status completely implemented; tested.
2363 * @author knut st. osmundsen
2364 */
2365VOID Pe2Lx::releaseNtHeaders()
2366{
2367 if (pNtHdrs != NULL)
2368 {
2369 free(pNtHdrs);
2370 pNtHdrs = NULL;
2371 }
2372}
2373
2374
2375/**
2376 * Initiates the fixup data members of this object.
2377 * Called from makeFixup and initEntry().
2378 * Checks for forwarder stuff. If forwarders present, the import module and procdure name tables are not
2379 * freed - initEntry have done that.
2380 * @returns NO_ERROR.
2381 * @status completely implemented.
2382 * @author knut st. osmundsen
2383 */
2384ULONG Pe2Lx::initFixups()
2385{
2386 if (paulFixupPageTable != NULL)
2387 {
2388 free(paulFixupPageTable);
2389 paulFixupPageTable = NULL;
2390 }
2391 cFixupPTEntries = cFPTEAllocated = 0UL;
2392 if (pFixupRecords != NULL)
2393 {
2394 free(pFixupRecords);
2395 pFixupRecords = NULL;
2396 }
2397 offCurFixupRec = cbFRAllocated = 0UL;
2398 if (pvCrossPageFixup != NULL)
2399 {
2400 free(pvCrossPageFixup);
2401 pvCrossPageFixup = NULL;
2402 }
2403 cbCrossPageFixup = 0UL;
2404
2405 /* if there aren't forwarders we may safely free the Import Module/Procedure name tables */
2406 if (!fForwarders)
2407 {
2408 if (pachImpModuleNames != NULL)
2409 {
2410 free(pachImpModuleNames);
2411 pachImpModuleNames = NULL;
2412 }
2413 offCurImpModuleName = cchIMNAllocated = 0UL;
2414 if (pachImpFunctionNames != NULL)
2415 {
2416 free(pachImpFunctionNames);
2417 pachImpFunctionNames = NULL;
2418 }
2419 offCurImpFunctionName = cchIFNAllocated = 0UL;
2420 }
2421 return NO_ERROR;
2422}
2423
2424
2425/**
2426 * Adds a page fixup entry to the fixup page table array (paFixupPageTable).
2427 * @returns NO_ERROR on success. Errorcode on error.
2428 * @param fLast TRUE: last entry
2429 * FALSE: not last (default)
2430 * @sketch IF not enough memory THEN
2431 * BEGIN
2432 * IF no memory allocated THEN count pages and allocate memory for all pages (+1).
2433 * ELSE increase amount of memory according to fLast.
2434 * END
2435 *
2436 * Set offset of current entry to current Fixup Record Array offset.
2437 * IF last entry (fLast) THEN
2438 * IF Cross Page Fixup THEN error!
2439 * ELSE
2440 * IF Cross Page Fixup THEN check if enough memory and add it.
2441 * return successfully.
2442 *
2443 * @status Completely implemented; tested.
2444 * @author knut st. osmundsen
2445 * @remark Fixup Page Table format (from Linear eXecutable Module Format,lxspec.inf, Rev.8):
2446 *
2447 * The Fixup Page Table provides a simple mapping of a logical page number to an offset
2448 * into the Fixup Record Table for that page. This table is parallel to the Object Page
2449 * Table, except that there is one additional entry in this table to indicate the end of
2450 * the Fixup Record Table.
2451 * The format of each entry is:
2452 *
2453 * ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
2454 * Logical Page #1 ³ OFFSET FOR PAGE #1 ³
2455 * ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŽ
2456 * Logical Page #2 ³ OFFSET FOR PAGE #2 ³
2457 * ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
2458 * . . .
2459 * ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
2460 * Logical Page #n ³ OFFSET FOR PAGE #n ³
2461 * ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŽ
2462 * ³OFF TO END OF FIXUP REC³ This is equal to:
2463 * ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ Offset for page #n + Size
2464 * of fixups for page #n
2465 * Fixup Page Table
2466 *
2467 * OFFSET FOR PAGE # = DD Offset for fixup record for this page. This field specifies
2468 * the offset, from the beginning of the fixup record table, to the first fixup record
2469 * for this page.
2470 *
2471 * OFF TO END OF FIXUP REC = DD Offset to the end of the fixup records. This field
2472 * specifies the offset following the last fixup record in the fixup record table. This
2473 * is the last entry in the fixup page table. The fixup records are kept in order by
2474 * logical page in the fixup record table. This allows the end of each page's fixup
2475 * records is defined by the offset for the next logical page's fixup records. This last
2476 * entry provides support of this mechanism for the last page in the fixup page table.
2477 *
2478 */
2479ULONG Pe2Lx::addPageFixupEntry(BOOL fLast/* = FALSE*/)
2480{
2481 /* enough memory? */
2482 if (cFixupPTEntries >= cFPTEAllocated)
2483 {
2484 if (cFPTEAllocated == 0UL)
2485 { /* first call */
2486 ULONG cPages = getCountOfPages();
2487 if (cPages == 0UL && !fLast)
2488 return ERROR_INTERNAL_PROCESSING_ERROR;
2489
2490 paulFixupPageTable = (PULONG)malloc((size_t)(cPages + 1UL) * sizeof(ULONG));
2491 if (paulFixupPageTable != NULL)
2492 cFPTEAllocated = cPages + 1UL;
2493 else
2494 return ERROR_NOT_ENOUGH_MEMORY;
2495 }
2496 else
2497 { /* hmm - algorithm for determin array size incorrect? */
2498 printErr(("More fixup pages than calculated!\n"));
2499 return ERROR_BAD_EXE_FORMAT;
2500 }
2501 }
2502
2503 /* add new entry */
2504 paulFixupPageTable[cFixupPTEntries++] = offCurFixupRec;
2505 if (fLast)
2506 { /* final entry */
2507 /* Error check */
2508 if (pvCrossPageFixup != NULL)
2509 {
2510 printErr(("Cross page fixup when fLast is set!\n"));
2511 return ERROR_INTERNAL_PROCESSING_ERROR;
2512 }
2513 }
2514 else
2515 { /* just another entry */
2516 /* cross page fixup? */
2517 if (pvCrossPageFixup != NULL)
2518 {
2519 AllocateMoreMemory(offCurFixupRec + cbCrossPageFixup > cbFRAllocated,
2520 pFixupRecords, PVOID, cbFRAllocated, PAGESIZE, PAGESIZE)
2521
2522 memcpy(&((PCHAR)pFixupRecords)[offCurFixupRec],
2523 pvCrossPageFixup, cbCrossPageFixup);
2524 offCurFixupRec += cbCrossPageFixup;
2525 free(pvCrossPageFixup);
2526 pvCrossPageFixup = NULL;
2527 }
2528 }
2529 return NO_ERROR;
2530}
2531
2532
2533/**
2534 * Add 32-bit offset fixup.
2535 * @returns NO_ERROR
2536 * ERROR_NOT_ENOUGH_MEMORY
2537 * ERROR_BAD_EXE_FORMAT
2538 * @param offSource Source offset into the current page.
2539 * @param ulTarget Target Pointer.
2540 * @sketch IF not enough memory THEN allocate some more memory.
2541 * Find target object and offset into target object for the given target address (ulTarget).
2542 * Fill in fixup record.
2543 * Increment the size of the fixup records array (offCurFixupRec).
2544 * IF cross page fixup THEN
2545 * BEGIN
2546 * Allocate memory for the cross page fixup record.
2547 * Copy the fixup record we just created into the memory of the cross page fixup record..
2548 * Substract the size of a Page from the source offset (r32_soff) in the cross page fixup record.
2549 * END
2550 * End successfully.
2551 * @status completely implemented.
2552 * @author knut st. osmundsen
2553 * @remark Internal Fixup Record format (from Linear eXecutable Module Format,lxspec.inf, Rev.8):
2554 *
2555 * ÚÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄ¿
2556 * 00h ³ SRC ³FLAGS³SRCOFF/CNT*³
2557 * ÃÄÄÄÄÄÁÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄ¿
2558 * 03h/04h ³ OBJECT * ³ TRGOFF * @ ³
2559 * ÃÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄŽ
2560 * ³ SRCOFF1 @ ³ . . . ³ SRCOFFn @ ³
2561 * ÀÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÙ
2562 *
2563 * * These fields are variable size.
2564 * @ These fields are optional.
2565 *
2566 * Internal Fixup Record
2567 *
2568 * OBJECT = D[B|W] Target object number. This field is an index into the current
2569 * module's Object Table to specify the target Object. It is a Byte value when the
2570 * '16-bit Object Number/Module Ordinal Flag' bit in the target flags field is
2571 * clear and a Word value when the bit is set.
2572 *
2573 * TRGOFF = D[W|D] Target offset. This field is an offset into the specified target
2574 * Object. It is not present when the Source Type specifies a 16-bit Selector fixup.
2575 * It is a Word value when the '32-bit Target Offset Flag' bit in the target flags
2576 * field is clear and a Dword value when the bit is set.
2577 * ---------------------
2578 * This code got a bit dirty while trying to optimize memory usage.
2579 */
2580ULONG Pe2Lx::add32OffsetFixup(WORD offSource, ULONG ulTarget)
2581{
2582 struct r32_rlc *prlc;
2583 ULONG iObj; /* target object. */
2584 ULONG cbFixup; /* size of the fixup record. */
2585
2586 /* enough memory? */
2587 AllocateMoreMemory(offCurFixupRec + RINTSIZE32 > cbFRAllocated,
2588 pFixupRecords, PVOID, cbFRAllocated, PAGESIZE, PAGESIZE)
2589
2590 /* target object and offset */
2591 if (ulTarget >= ulImageBase)
2592 {
2593 ulTarget -= ulImageBase; /* ulTarget is now an RVA */
2594 iObj = 0UL;
2595 while (iObj < cObjects
2596 && ulTarget >= (iObj + 1 < cObjects ? paObjects[iObj+1].ulRVA
2597 : ALIGN(paObjects[iObj].cbVirtual, PAGESIZE) + paObjects[iObj].ulRVA)
2598 )
2599 iObj++;
2600 if (iObj < cObjects)
2601 {
2602 if (!fAllInOneObject)
2603 {
2604 ulTarget -= paObjects[iObj].ulRVA;
2605 iObj++; /* one based object number. */
2606 }
2607 else
2608 iObj = 1UL;
2609 }
2610 else
2611 {
2612 printErr(("Invalid target RVA, 0x%08x.\n", ulTarget));
2613 return ERROR_BAD_EXE_FORMAT;
2614 }
2615 }
2616 else
2617 {
2618 printErr(("Invalid target address, 0x%08x.\n", ulTarget));
2619 return ERROR_BAD_EXE_FORMAT;
2620 }
2621 /* ulTarget is now an offset into the target object. */
2622
2623 /* fill in fixup record */
2624 cbFixup = 7UL;
2625 prlc = (struct r32_rlc *)((ULONG)pFixupRecords + offCurFixupRec);
2626 prlc->nr_stype = NROFF32;
2627 prlc->nr_flags = NRRINT;
2628 if (iObj > 255UL)
2629 {
2630 prlc->nr_flags |= NR16OBJMOD;
2631 cbFixup++;
2632 }
2633 if (ulTarget > 65535UL)
2634 {
2635 prlc->nr_flags |= NR32BITOFF;
2636 cbFixup += 2;
2637 }
2638
2639 prlc->r32_soff = (USHORT)offSource;
2640 prlc->r32_objmod = (USHORT)iObj;
2641 if (prlc->nr_flags & NR16OBJMOD)
2642 prlc->r32_target.intref.offset32 = ulTarget;
2643 else
2644 ((struct r32_rlc*)((ULONG)prlc - 1))->r32_target.intref.offset32 = ulTarget;
2645
2646 /* commit fixup */
2647 offCurFixupRec += cbFixup;
2648
2649 /* cross page fixup? */
2650 if (offSource > PAGESIZE - 4UL)
2651 { /* cross page fixup! */
2652 if (pvCrossPageFixup != NULL)
2653 {
2654 printWar(("A cross page fixup allready exists!\n"));
2655 free(pvCrossPageFixup);
2656 }
2657 pvCrossPageFixup = malloc((size_t)cbFixup);
2658 if (pvCrossPageFixup != NULL)
2659 {
2660 memcpy(pvCrossPageFixup, prlc, (size_t)cbFixup);
2661 cbCrossPageFixup = cbFixup;
2662 ((struct r32_rlc *)pvCrossPageFixup)->r32_soff -= (USHORT)PAGESIZE;
2663 }
2664 else
2665 return ERROR_NOT_ENOUGH_MEMORY;
2666 }
2667
2668 return NO_ERROR;
2669}
2670
2671
2672/**
2673 * Add 32-bit ordinal import fixup.
2674 * @returns NO_ERROR
2675 * ERROR_NOT_ENOUGH_MEMORY
2676 * @param offSource Offset of the fixup reltaive to the start of the page.
2677 * @param ulModuleOrdinal Module ordinal. Ordinal into the import module name table. (1 based!)
2678 * @param ulFunctionOrdinal Function ordinal. Number of the export which is to be imported from
2679 * the module given by ulModuleOrdinal.
2680 * @sketch IF not enough memory for the fixup THEN (try) allocate more memory
2681 * Fill in fixup record.
2682 * Increment the size of the fixup records array (offCurFixupRec).
2683 * IF cross page fixup THEN
2684 * BEGIN
2685 * Allocate memory for the cross page fixup record.
2686 * Copy the fixup record we just created into the memory of the cross page fixup record..
2687 * Substract the size of a Page from the source offset (r32_soff) in the cross page fixup record.
2688 * END
2689 * End successfully.
2690 * @status completely implemented.
2691 * @author knut st. osmundsen
2692 * @remark Internal Fixup Record format (from Linear eXecutable Module Format,lxspec.inf, Rev.8):
2693 * ÚÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄ¿
2694 * 00h ³ SRC ³FLAGS³SRCOFF/CNT*³
2695 * ÃÄÄÄÄÄÁÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
2696 * 03h/04h ³ MOD ORD# *³IMPORT ORD*³ ADDITIVE * @ ³
2697 * ÃÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÙ
2698 * ³ SRCOFF1 @ ³ . . . ³ SRCOFFn @ ³
2699 * ÀÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÙ
2700 *
2701 * * These fields are variable size.
2702 * @ These fields are optional.
2703 *
2704 * Import by Ordinal Fixup Record
2705 *
2706 * MOD ORD # = D[B|W] Ordinal index into the Import Module Name Table. This value
2707 * is an ordered index in to the Import Module Name Table for the module containing
2708 * the procedure entry point. It is a Byte value when the '16-bit Object Number/Module
2709 * Ordinal' Flag bit in the target flags field is clear and a Word value when the bit
2710 * is set. The loader creates a table of pointers with each pointer in the table
2711 * corresponds to the modules named in the Import Module Name Table. This value is used
2712 * by the loader to index into this table created by the loader to locate the referenced module.
2713 *
2714 * IMPORT ORD = D[B|W|D] Imported ordinal number. This is the imported procedure's
2715 * ordinal number. It is a Byte value when the '8-bit Ordinal' bit in the target flags
2716 * field is set. Otherwise it is a Word value when the '32-bit Target Offset Flag' bit
2717 * in the target flags field is clear and a Dword value when the bit is set.
2718 *
2719 * ADDITIVE = D[W|D] Additive fixup value. This field exists in the fixup record only
2720 * when the 'Additive Fixup Flag' bit in the target flags field is set. When the
2721 * 'Additive Fixup Flag' is clear the fixup record does not contain this field and
2722 * is immediately followed by the next fixup record (or by the source offset list
2723 * for this fixup record). This value is added to the address derived from the target
2724 * entry point. This field is a Word value when the '32-bit Additive Flag' bit in the
2725 * target flags field is clear and a Dword value when the bit is set.
2726 *
2727 * ---------------------
2728 * This code got a bit dirty while trying to optimize memory usage.
2729 *
2730 */
2731ULONG Pe2Lx::add32OrdImportFixup(WORD offSource, ULONG ulModuleOrdinal, ULONG ulFunctionOrdinal)
2732{
2733 struct r32_rlc *prlc;
2734 ULONG cbFixup; /* size of the fixup record. */
2735
2736 /* enough memory? */
2737 AllocateMoreMemory(offCurFixupRec + 10 > cbFRAllocated /* 10 is max size */,
2738 pFixupRecords, PVOID, cbFRAllocated, PAGESIZE, PAGESIZE)
2739
2740 /* fill in fixup record */
2741 cbFixup = 7UL;
2742 prlc = (struct r32_rlc *)((ULONG)pFixupRecords + offCurFixupRec);
2743 prlc->nr_stype = NROFF32;
2744 prlc->nr_flags = NRRORD;
2745 if (ulModuleOrdinal > 255UL)
2746 {
2747 prlc->nr_flags |= NR16OBJMOD;
2748 cbFixup++;
2749 }
2750 #if 0 /* lxdump.exe (from Hacker's View release 5.66) don't support this. */
2751 if (ulFunctionOrdinal < 256UL)
2752 {
2753 prlc->nr_flags |= NR8BITORD;
2754 cbFixup--;
2755 }
2756 #endif
2757 else if (ulFunctionOrdinal > 65535UL)
2758 {
2759 prlc->nr_flags |= NR32BITOFF;
2760 cbFixup += 2;
2761 }
2762 prlc->r32_soff = (USHORT)offSource;
2763 prlc->r32_objmod = (USHORT)ulModuleOrdinal;
2764 if (prlc->nr_flags & NR16OBJMOD)
2765 prlc->r32_target.intref.offset32 = ulFunctionOrdinal;
2766 else
2767 ((struct r32_rlc*)((ULONG)prlc - 1))->r32_target.intref.offset32 = ulFunctionOrdinal;
2768
2769 /* commit fixup */
2770 offCurFixupRec += cbFixup;
2771
2772 /* cross page fixup? */
2773 if (offSource > PAGESIZE - 4UL)
2774 { /* cross page fixup! */
2775 if (pvCrossPageFixup != NULL)
2776 {
2777 printWar(("A cross page fixup allready exists!\n"));
2778 free(pvCrossPageFixup);
2779 }
2780 pvCrossPageFixup = malloc((size_t)cbFixup);
2781 if (pvCrossPageFixup != NULL)
2782 {
2783 memcpy(pvCrossPageFixup, prlc, (size_t)cbFixup);
2784 cbCrossPageFixup = cbFixup;
2785 ((struct r32_rlc *)pvCrossPageFixup)->r32_soff -= (USHORT)PAGESIZE;
2786 }
2787 else
2788 return ERROR_NOT_ENOUGH_MEMORY;
2789 }
2790
2791 printInfA(("offset=0x%03x modordinal=%d fnord=%4d cbFixup=%d %s\n",
2792 offSource, ulModuleOrdinal, ulFunctionOrdinal, cbFixup, pvCrossPageFixup ? "crosspage" : ""));
2793
2794 return NO_ERROR;
2795}
2796
2797
2798/**
2799 *
2800 * @returns NO_ERROR on success. Errorcode on error.
2801 * @param offSource Fixup offset relative to page.
2802 * @param ulModuleOrdinal Module ordinal in the import module name table (1 based!)
2803 * @param pszFnName Pointer to a readonly function name for the imported function.
2804 * @sketch IF not enough memory for the fixup THEN (try) allocate more memory
2805 * Add function name to the import procedure name table.
2806 * Fill in fixup record.
2807 * Increment the size of the fixup records array (offCurFixupRec).
2808 * IF cross page fixup THEN
2809 * BEGIN
2810 * Allocate memory for the cross page fixup record.
2811 * Copy the fixup record we just created into the memory of the cross page fixup record..
2812 * Substract the size of a Page from the source offset (r32_soff) in the cross page fixup record.
2813 * END
2814 * End successfully.
2815 * @status completely implemented.
2816 * @author knut st. osmundsen
2817 * @remark Internal Fixup Record format (from Linear eXecutable Module Format,lxspec.inf, Rev.8):
2818 * ÚÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄ¿
2819 * 00h ³ SRC ³FLAGS³SRCOFF/CNT*³
2820 * ÃÄÄÄÄÄÁÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
2821 * 03h/04h ³ MOD ORD# *³ PROCEDURE NAME OFFSET*³ ADDITIVE * @ ³
2822 * ÃÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
2823 * ³ SRCOFF1 @ ³ . . . ³ SRCOFFn @ ³
2824 * ÀÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÙ
2825 *
2826 * * These fields are variable size.
2827 * @ These fields are optional.
2828 *
2829 * Import by Name Fixup Record
2830 *
2831 * MOD ORD # = D[B|W] Ordinal index into the Import Module Name Table. This value is
2832 * an ordered index in to the Import Module Name Table for the module containing the
2833 * procedure entry point. It is a Byte value when the '16-bit Object Number/Module Ordinal'
2834 * Flag bit in the target flags field is clear and a Word value when the bit is set. The
2835 * loader creates a table of pointers with each pointer in the table corresponds to the
2836 * modules named in the Import Module Name Table. This value is used by the loader to
2837 * index into this table created by the loader to locate the referenced module.
2838 *
2839 * PROCEDURE NAME OFFSET = D[W|D] Offset into the Import Procedure Name Table. This
2840 * field is an offset into the Import Procedure Name Table. It is a Word value when
2841 * the '32-bit Target Offset Flag' bit in the target flags field is clear and a Dword
2842 * value when the bit is set.
2843 *
2844 * ADDITIVE = D[W|D] Additive fixup value. This field exists in the fixup record only
2845 * when the 'Additive Fixup Flag' bit in the target flags field is set. When the
2846 * 'Additive Fixup Flag' is clear the fixup record does not contain this field and is
2847 * immediately followed by the next fixup record (or by the source offset list for this
2848 * fixup record). This value is added to the address derived from the target entry point.
2849 * This field is a Word value when the '32-bit Additive Flag' bit in the target flags
2850 * field is clear and a Dword value when the bit is set.
2851 *
2852 * ---------------------
2853 * This code got a bit dirty while trying to optimize memory usage.
2854 *
2855 */
2856ULONG Pe2Lx::add32NameImportFixup(WORD offSource, ULONG ulModuleOrdinal, PCSZ pszFnName)
2857{
2858 APIRET rc;
2859 struct r32_rlc *prlc;
2860 ULONG cbFixup; /* size of the fixup record. */
2861 ULONG offFnName;
2862
2863 /* enough memory? */
2864 AllocateMoreMemory(offCurFixupRec + 10 > cbFRAllocated /* 10 is max size */,
2865 pFixupRecords, PVOID, cbFRAllocated, PAGESIZE, PAGESIZE)
2866
2867 rc = addImportFunctionName(pszFnName, (PULONG)SSToDS(&offFnName));
2868 if (rc != NO_ERROR)
2869 return rc;
2870
2871 /* fill in fixup record */
2872 cbFixup = 7UL;
2873 prlc = (struct r32_rlc *)((ULONG)pFixupRecords + offCurFixupRec);
2874 prlc->nr_stype = NROFF32;
2875 prlc->nr_flags = NRRNAM;
2876 if (ulModuleOrdinal > 255UL)
2877 {
2878 prlc->nr_flags |= NR16OBJMOD;
2879 cbFixup++;
2880 }
2881 #if 0 /* lxdump.exe (from Hacker's View release 5.66) don't support this. */
2882 if (offFnName < 256UL)
2883 {
2884 prlc->nr_flags |= NR8BITORD;
2885 cbFixup--;
2886 }
2887 #endif
2888 else if (offFnName > 65535UL)
2889 {
2890 prlc->nr_flags |= NR32BITOFF;
2891 cbFixup += 2;
2892 }
2893 prlc->r32_soff = (USHORT)offSource;
2894 prlc->r32_objmod = (USHORT)ulModuleOrdinal;
2895 if (prlc->nr_flags & NR16OBJMOD)
2896 prlc->r32_target.intref.offset32 = offFnName;
2897 else
2898 ((struct r32_rlc*)((ULONG)prlc - 1))->r32_target.intref.offset32 = offFnName;
2899
2900 /* commit fixup */
2901 offCurFixupRec += cbFixup;
2902
2903 /* cross page fixup? */
2904 if (offSource > PAGESIZE - 4UL)
2905 { /* cross page fixup! */
2906 if (pvCrossPageFixup != NULL)
2907 {
2908 printWar(("A cross page fixup allready exists!\n"));
2909 free(pvCrossPageFixup);
2910 }
2911 pvCrossPageFixup = malloc((size_t)cbFixup);
2912 if (pvCrossPageFixup != NULL)
2913 {
2914 memcpy(pvCrossPageFixup, prlc, (size_t)cbFixup);
2915 cbCrossPageFixup = cbFixup;
2916 ((struct r32_rlc *)pvCrossPageFixup)->r32_soff -= (USHORT)PAGESIZE;
2917 }
2918 else
2919 return ERROR_NOT_ENOUGH_MEMORY;
2920 }
2921
2922 printInfA(("offset=0x%03x modordinal=%d fnname=%s cbFixup=%d %s\n",
2923 offSource, ulModuleOrdinal, pszFnName, cbFixup, pvCrossPageFixup ? "crosspage" : ""));
2924 return NO_ERROR;
2925}
2926
2927
2928/**
2929 * Adds a modulename and returns the module ordinal.
2930 * If the module allready exists in the import module table then return the module ordinal only.
2931 * @returns NO_ERROR
2932 * ERROR_INVALID_PARAMETER
2933 * ERROR_NOT_ENOUGH_MEMORY
2934 * @param pszModuleName Pointer to readonly string containing the modulename which is to be added.
2935 * @param pulModuleOrdinal Pointer to an ULONG which will hold the module ordinal value upon successfull return.
2936 * @sketch validate input (pulModuleOrdinal)
2937 * get/make Odin32 modulename (lie-list)
2938 * IF modulename length > 127 THEN truncate it.
2939 * IF module allready exists in the import module table THEN return successfully.
2940 * IF not enough memory for modulename THEN (try) allocate some more.
2941 * Set length and copy modulename.
2942 * Update offCurImpModuleName.
2943 * return successfully.
2944 * @status completely implemented.
2945 * @author knut st. osmundsen
2946 * @remark Module table format (from Linear eXecutable Module Format,lxspec.inf, Rev.8):
2947 * ÚÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄ¿
2948 * ³ LEN ³ ASCII STRING . . . ³
2949 * ÀÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÙ
2950 *
2951 * LEN = DB String Length. This defines the length of the string in bytes.
2952 * The length of each ascii name string is limited to 255 characters.
2953 * ASCII STRING = DB ASCII String. This is a variable length string with it's
2954 * length defined in bytes by the LEN field. The string is case
2955 * sensitive and is not null terminated.
2956 *
2957 * The end of the import module name table is not terminated by a special character,
2958 * it is followed directly by the import procedure name table.
2959 */
2960ULONG Pe2Lx::addModule(PCSZ pszModuleName, PULONG pulModuleOrdinal)
2961{
2962 ULONG cchModuleName;
2963 ULONG offModule;
2964
2965 #ifdef DEBUG
2966 /* validate input */
2967 if (pulModuleOrdinal < (PULONG)0x10000UL)
2968 {
2969 printErr(("Invalid (stack?) pointer passed in, 0x%08x\n", pulModuleOrdinal));
2970 return ERROR_INVALID_PARAMETER;
2971 }
2972 #endif
2973
2974 /* check lie-list - get Odin32 modulename */
2975 pszModuleName = queryOdin32ModuleName(pszModuleName);
2976
2977 /* length check */
2978 cchModuleName = strlen(pszModuleName);
2979 if (cchModuleName > 255UL) /* we've only got a byte to store the length in... */
2980 {
2981 printWar(("Modulename truncated! %s\n", pszModuleName));
2982 cchModuleName = 255;
2983 }
2984
2985 /* check if module allready exists in the list and find module ordinal*/
2986 *pulModuleOrdinal = 1UL;
2987 offModule = 0UL;
2988 while (offModule < offCurImpModuleName)
2989 {
2990 if (strnicmp(&pachImpModuleNames[offModule + 1], pszModuleName,
2991 (int)pachImpModuleNames[offModule]) == 0) /* case insensitive search - correct? */
2992 {
2993 return NO_ERROR;
2994 }
2995 offModule += 1 + pachImpModuleNames[offModule];
2996 (*pulModuleOrdinal)++;
2997 }
2998
2999 printInf(("Modulename: %s Ordinal: %d\n", pszModuleName, *pulModuleOrdinal));
3000
3001 /* check if there is enough memory */
3002 AllocateMoreMemory(offCurImpModuleName + 1 + cchModuleName > cchIMNAllocated,
3003 pachImpModuleNames, PCHAR, cchIMNAllocated,
3004 1 + cchModuleName, 1 + cchModuleName)
3005
3006 /* copy the modulename */
3007 pachImpModuleNames[offCurImpModuleName] = (CHAR)cchModuleName;
3008 memcpy(&pachImpModuleNames[offCurImpModuleName + 1], pszModuleName, (size_t)cchModuleName);
3009
3010 offCurImpModuleName += cchModuleName + 1;
3011
3012 return NO_ERROR;
3013}
3014
3015
3016/**
3017 * Adds a procedure name to the Import Procedure Table.
3018 * @returns NO_ERROR
3019 * ERROR_INVALID_PARAMETER
3020 * ERROR_NOT_ENOUGH_MEMORY
3021 * @param pszFnName Pointer to readonly procname string.
3022 * @param poffFnName Pointer to variable which will hold the proc name offset on return.
3023 * @sketch Validate pointer parameter poffFnName.
3024 * Determin function name length. (max length 127)
3025 * IF not enough memory for the function name THEN (try) allocate more memory
3026 * Add function name to the import procedure name table.
3027 * return successfully.
3028 * @status completely implemented.
3029 * @author knut st. osmundsen
3030 * @remark Resident Name Table format (from Linear eXecutable Module Format,lxspec.inf, Rev.8):
3031 *
3032 * The import procedure name table defines the procedure name strings imported by this module
3033 * through dynamic link references. These strings are referenced through the imported
3034 * relocation fixups. To determine the length of the import procedure name table add the
3035 * fixup section size to the fixup page table offset, this computes the offset to the end
3036 * of the fixup section, then subtract the import procedure name table offset. These values
3037 * are located in the linear EXE header. The import procedure name table is followed by the
3038 * data pages section. Since the data pages section is aligned on a 'page size' boundary,
3039 * padded space may exist between the last import name string and the first page in the
3040 * data pages section. If this padded space exists it will be zero filled. The strings
3041 * are CASE SENSITIVE and NOT NULL TERMINATED. Each name table entry has the following
3042 * format:
3043 *
3044 * ÚÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄ¿
3045 * 00h ³ LEN ³ ASCII STRING . . . ³
3046 * ÀÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÙ
3047 *
3048 * Import Procedure Name Table
3049 *
3050 * LEN = DB String Length. This defines the length of the string in bytes. The length
3051 * of each ascii name string is limited to 255 characters. The high bit in the LEN field
3052 * (bit 7) is defined as an Overload bit. This bit signifies that additional information
3053 * is contained in the linear EXE module and will be used in the future for parameter
3054 * type checking.
3055 *
3056 * ASCII STRING = DB ASCII String. This is a variable length string with it's length
3057 * defined in bytes by the LEN field. The string is case sensitive and is not null terminated.
3058 *
3059 * Note: The first entry in the import procedure name table must be a null entry. That is,
3060 * the LEN field should be zero followed an empty ASCII STRING (no bytes).
3061 *
3062 * ----
3063 *
3064 * 255 bytes long when bit 7 is Overload bit?. We'll continue truncating to 127 bytes.
3065 *
3066 */
3067ULONG Pe2Lx::addImportFunctionName(PCSZ pszFnName, PULONG poffFnName)
3068{
3069 #ifdef DEBUG
3070 /* validate parameters */
3071 if (poffFnName < (PULONG)0x10000UL)
3072 {
3073 printErr(("poffFnName is invalid!, 0x%08x\n", poffFnName));
3074 return ERROR_INVALID_PARAMETER;
3075 }
3076 #endif
3077
3078 ULONG cchFnName = strlen(pszFnName);
3079
3080 /* max function name length is 127 bytes */
3081 if (cchFnName > 127)
3082 {
3083 printWar(("function name truncated, %s", pszFnName));
3084 cchFnName = 127;
3085 }
3086
3087 AllocateMoreMemory(offCurImpFunctionName + cchFnName + 1 > cchIFNAllocated,
3088 pachImpFunctionNames, PCHAR, cchIFNAllocated, PAGESIZE, PAGESIZE)
3089
3090 /* check if first entry */
3091 if (offCurImpFunctionName == 0UL)
3092 { /* add null entry */
3093 pachImpFunctionNames[offCurImpFunctionName++] = '\0';
3094 }
3095
3096 /* add function name */
3097 pachImpFunctionNames[offCurImpFunctionName] = (CHAR)cchFnName;
3098 memcpy(&pachImpFunctionNames[offCurImpFunctionName+1], pszFnName, (size_t)cchFnName);
3099 *poffFnName = offCurImpFunctionName;
3100 offCurImpFunctionName += 1 + cchFnName;
3101
3102 return NO_ERROR;
3103}
3104
3105
3106/**
3107 * Releases unsused memory from the Fixup data structures.
3108 * @status completely implemented.
3109 * @author knut st. osmundsen
3110 */
3111VOID Pe2Lx::finalizeFixups()
3112{
3113 if (paulFixupPageTable != NULL && cFixupPTEntries < cFPTEAllocated)
3114 {
3115 PVOID pv = realloc(paulFixupPageTable, (size_t)cFixupPTEntries * sizeof(ULONG));
3116 if (pv != NULL)
3117 {
3118 paulFixupPageTable = (PULONG)pv;
3119 cFPTEAllocated = cFixupPTEntries;
3120 }
3121 }
3122
3123 if (pFixupRecords != NULL && offCurFixupRec < cbFRAllocated)
3124 {
3125 PVOID pv = realloc(pFixupRecords, offCurFixupRec);
3126 if (pv != NULL)
3127 {
3128 pFixupRecords = pv;
3129 cbFRAllocated = offCurFixupRec;
3130 }
3131 }
3132}
3133
3134
3135/**
3136 * Releases unsused memory from the Import data structures.
3137 * @status completely implemented.
3138 * @author knut st. osmundsen
3139 */
3140VOID Pe2Lx::finalizeImportNames()
3141{
3142 if (pachImpModuleNames != NULL && offCurImpModuleName < cchIMNAllocated)
3143 {
3144 PVOID pv = realloc(pachImpModuleNames, offCurImpModuleName);
3145 if (pv != NULL)
3146 {
3147 pachImpModuleNames = (PCHAR)pv;
3148 cchIMNAllocated = offCurImpModuleName;
3149 }
3150 }
3151
3152 if (pachImpFunctionNames != NULL && offCurImpFunctionName < cchIFNAllocated)
3153 {
3154 PVOID pv = realloc(pachImpFunctionNames, offCurImpFunctionName);
3155 if (pv != NULL)
3156 {
3157 pachImpFunctionNames = (PCHAR)pv;
3158 cchIFNAllocated = offCurImpFunctionName;
3159 }
3160 }
3161}
3162
3163
3164/**
3165 * Initiates the entry (export) related data members of this object.
3166 * Forwarders are concidered.
3167 * @returns NO_ERROR
3168 * @status completely implemented.
3169 * @author knut st. osmundsen
3170 */
3171ULONG Pe2Lx::initEntry()
3172{
3173 APIRET rc;
3174
3175 if (pEntryBundles != NULL)
3176 {
3177 free(pEntryBundles);
3178 pEntryBundles = NULL;
3179 }
3180 offCurEntryBundle = 0UL;
3181 offLastEntryBundle = 0UL;
3182 ulLastOrdinal = 0UL;
3183 cbEBAllocated = 0UL;
3184
3185 if (pachResNameTable)
3186 {
3187 free(pachResNameTable);
3188 pachResNameTable = NULL;
3189 }
3190 offCurResName = 0UL;
3191 cchRNTAllocated = 0UL;
3192
3193 /* If this is a second call to makeExports, the fForwarders flag may be set. */
3194 /* When it's set we'll have to clean up the fixup structures too. */
3195 if (fForwarders)
3196 {
3197 fForwarders = FALSE;
3198 rc = initFixups();
3199 fForwarders = TRUE;
3200 }
3201 else
3202 rc = NO_ERROR;
3203
3204 return rc;
3205}
3206
3207
3208/**
3209 * Adds a name/ordinal to the resident name table.
3210 * @returns NO_ERROR
3211 * ERROR_NOT_ENOUGH_MEMORY
3212 * @param ulOrdinal Ordinal number for this name.
3213 * @param pszName Pointer to read only name string. (Don't have to be zero-termitated)
3214 * @param cchName Numbers of chars to copy or ~0UL to copy until zero-termintaion.
3215 * @sketch IF cchName == ~0L THEN get name length.
3216 * IF name length > 127 THEN truncate name.
3217 * IF not enough memory THEN (try) allocate more memory.
3218 * Add name:
3219 * Set length.
3220 * Copy name
3221 * Set ordinal
3222 * Update offCurResName to point the next (unused) name entry.
3223 * return successfully.
3224 * @status completely implemented; tested.
3225 * @author knut st. osmundsen
3226 * @remark Resident Name Table format (from Linear eXecutable Module Format,lxspec.inf, Rev.8):
3227 *
3228 * The resident and non-resident name tables define the ASCII names and ordinal numbers for
3229 * exported entries in the module. In addition the first entry in the resident name table
3230 * contains the module name. These tables are used to translate a procedure name string into
3231 * an ordinal number by searching for a matching name string. The ordinal number is used to
3232 * locate the entry point information in the entry table. The resident name table is kept
3233 * resident in system memory while the module is loaded. It is intended to contain the
3234 * exported entry point names that are frequently dynamicaly linked to by name. Non-resident
3235 * names are not kept in memory and are read from the EXE file when a dynamic link reference
3236 * is made. Exported entry point names that are infrequently dynamicaly linked to by name or
3237 * are commonly referenced by ordinal number should be placed in the non-resident name table.
3238 * The trade off made for references by name is performance vs memory usage. Import references
3239 * by name require these tables to be searched to obtain the entry point ordinal number.
3240 * Import references by ordinal number provide the fastest lookup since the search of these
3241 * tables is not required.
3242 *
3243 * Installable File Systems, Physical Device Drivers, and Virtual Device Drivers are closed
3244 * after the file is loaded. Any refeference to the non-resident name table after this time
3245 * will fail. The strings are CASE SENSITIVE and are NOT NULL TERMINATED. Each name table entry
3246 * has the following format:
3247 *
3248 *
3249 * ÚÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄ¿
3250 * 00h ³ LEN ³ ASCII STRING . . . ³ ORDINAL # ³
3251 * ÀÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÙ
3252 *
3253 * Resident or Non-resident Name Table Entry
3254 *
3255 * LEN = DB String Length. This defines the length of the string in bytes. A zero length
3256 * indicates there are no more entries in table. The length of each ascii name string is
3257 * limited to 255 characters. The high bit in the LEN field (bit 7) is defined as an Overload
3258 * bit. This bit signifies that additional information is contained in the linear EXE module
3259 * and will be used in the future for parameter type checking.
3260 *
3261 * ASCII STRING = DB ASCII String. This is a variable length string with it's length defined
3262 * in bytes by the LEN field. The string is case case sensitive and is not null terminated.
3263 *
3264 * ORDINAL # = DW Ordinal number. The ordinal number in an ordered index into the entry table
3265 * for this entry point.
3266 *
3267 */
3268ULONG Pe2Lx::addResName(ULONG ulOrdinal, PCSZ pszName, ULONG cchName)
3269{
3270 /* IF cchName == ~0L THEN get name length. */
3271 if (cchName == ~0UL)
3272 cchName = strlen(pszName);
3273
3274 /* IF name length > 127 THEN truncate name. */
3275 if (cchName > 127)
3276 {
3277 printWar(("Resident name truncated! %s\n", pszName));
3278 cchName = 127;
3279 }
3280
3281 /* IF not enough memory THEN (try) allocate more memory. */
3282 AllocateMoreMemory(cchName + 1 + 2 + offCurResName > cchRNTAllocated,
3283 pachResNameTable, PCHAR, cchRNTAllocated, 2048, 1024)
3284
3285 /* Add name */
3286 pachResNameTable[offCurResName] = (CHAR)cchName;
3287 memcpy(&pachResNameTable[offCurResName + 1], pszName, (size_t)cchName);
3288 *(PUSHORT)&pachResNameTable[offCurResName + 1 + cchName] = (USHORT)ulOrdinal;
3289
3290 /* Update offCurResName to point the next (unused) name entry. */
3291 offCurResName += 1 + cchName + 2;
3292
3293 printInf(("Resident Name: %.*s ordinal:%d\n", cchName, pszName, ulOrdinal));
3294
3295 return NO_ERROR;
3296}
3297
3298
3299/**
3300 * Adds an entry to the entry table.
3301 * The way this is implemented, it is REQUIRED that the entries are added in strict
3302 * ascending order by ordinal.
3303 * @returns NO_ERROR
3304 * ERROR_NOT_ENOUGH_MEMORY
3305 * ERROR_INVALID_PARAMETER
3306 * @param ulOrdinal Ordinal number of the entry point.
3307 * @param ulRVA The RVA of the entry point.
3308 * @sketch Validate input. (ulOrdinal)
3309 * Find object and offObject corresponding to the entrypoint RVA.
3310 * IF no enough memory THEN (try) allocate more.
3311 * IF last ordinal + 1 != new ordinal THEN
3312 * BEGIN
3313 * Add unused entry which skips to the new ordinal - 1.
3314 * Update offCurEntryBundle
3315 * Set offLastEntryBundle to offLastEntryBundle.
3316 * END
3317 * IF offCurEntryBundle == offLastEntryBundle OR last bundle type != 32-bit entry
3318 * OR last bundle object != this object OR bundle is full THEN
3319 * BEGIN
3320 * Add an empty 32-bit bundle.
3321 * Set offLastEntryBundle to start of new 32-bit bundle.
3322 * Set offCurEntryBundle to end of of the new 32-bit bundle.
3323 * END
3324 * Add Flags (01h) and 32-bit offset.
3325 * Update offCurEntryBundle.
3326 * return successfully.
3327 * @status completely implemented.
3328 * @author knut st. osmundsen
3329 * @remark Entry Table format (from Linear eXecutable Module Format,lxspec.inf, Rev.8):
3330 * The entry table contains object and offset information that is used to resolve fixup
3331 * references to the entry points within this module. Not all entry points in the entry
3332 * table will be exported, some entry points will only be used within the module. An ordinal
3333 * number is used to index into the entry table. The entry table entries are numbered
3334 * starting from one. The list of entries are compressed into 'bundles', where possible. The
3335 * entries within each bundle are all the same size. A bundle starts with a count field which
3336 * indicates the number of entries in the bundle. The count is followed by a type field which
3337 * identifies the bundle format. This provides both a means for saving space as well as a
3338 * mechanism for extending the bundle types. The type field allows the definition of 256
3339 * bundle types. The following bundle types will initially be defined:
3340 * Unused Entry.
3341 * 16-bit Entry.
3342 * 286 Call Gate Entry.
3343 * 32-bit Entry.
3344 * Forwarder Entry.
3345 *
3346 * The bundled entry table has the following format:
3347 * ÚÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
3348 * 00h ³ CNT ³TYPE ³ BUNDLE INFO . . ³
3349 * ÀÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
3350 *
3351 * Entry Table
3352 *
3353 * CNT = DB Number of entries. This is the number of entries in this bundle. A zero
3354 * value for the number of entries identifies the end of the entry table. There is no
3355 * further bundle information when the number of entries is zero. In other words the
3356 * entry table is terminated by a single zero byte.
3357 *
3358 * TYPE = DB Bundle type. This defines the bundle type which determines the contents
3359 * of the BUNDLE INFO. The follow types are defined:
3360 * 00h = Unused Entry.
3361 * 01h = 16-bit Entry.
3362 * 02h = 286 Call Gate Entry.
3363 * 03h = 32-bit Entry.
3364 * 04h = Forwarder Entry.
3365 * 80h = Parameter Typing Information Present. This bit signifies that
3366 * additional information is contained in the linear EXE module
3367 * and will be used in the future for parameter type checking.
3368 *
3369 * The following is the format for each bundle type:
3370 *
3371 * Unused Entry:
3372 * ------------
3373 * ÚÄÄÄÄÄÂÄÄÄÄÄ¿
3374 * 00h ³ CNT ³TYPE ³
3375 * ÀÄÄÄÄÄÁÄÄÄÄÄÙ
3376 *
3377 * CNT = DB Number of entries. This is the number of unused entries to skip.
3378 *
3379 * TYPE = DB 0 (Unused Entry)
3380 *
3381 * 32-bit Entry:
3382 * ------------
3383 * ÚÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄ¿
3384 * 00h ³ CNT ³TYPE ³ OBJECT ³
3385 * ÃÄÄÄÄÄÅÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄ¿
3386 * 04h ³FLAGS³ OFFSET ³
3387 * ÃÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŽ
3388 * 09h ³ ... ³ . . . ³
3389 *
3390 *
3391 * CNT = DB Number of entries. This is the number of 32-bit entries in this bundle.
3392 * The flags and offset value are repeated this number of times.
3393 *
3394 * TYPE = DB 3 (32-bit Entry) The 32-bit Entry type will only be defined by the
3395 * linker when the offset in the object can not be specified by a 16-bit offset.
3396 *
3397 * OBJECT = DW Object number. This is the object number for the entries in this bundle.
3398 *
3399 * FLAGS = DB Entry flags. These are the flags for this entry point. They have the
3400 * following definition.
3401 * 01h = Exported entry flag.
3402 * F8h = Parameter dword count mask.
3403 *
3404 * OFFSET = DD Offset in object. This is the offset in the object for the entry point
3405 * defined at this ordinal number.
3406 *
3407 */
3408ULONG Pe2Lx::addEntry(ULONG ulOrdinal, ULONG ulRVA)
3409{
3410 APIRET rc;
3411 ULONG iObj;
3412 ULONG offObject;
3413 struct b32_bundle *pBundle;
3414 struct e32_entry *pEntry;
3415
3416 #ifdef DEBUG
3417 /* Validate input. (ulOrdinal) */
3418 if (ulOrdinal < ulLastOrdinal + 1UL || ulOrdinal > 65535UL)
3419 {
3420 printErr(("Invalid ordinal. ulOrdinal %d, ulLastOrdinal %d.\n", ulOrdinal, ulLastOrdinal));
3421 return ERROR_INVALID_PARAMETER;
3422 }
3423 #endif
3424
3425 /* Find object and offObject corresponding to the entrypoint RVA. */
3426 rc = queryObjectAndOffset(ulRVA, (PULONG)SSToDS(&iObj), (PULONG)SSToDS(&offObject));
3427 if (rc != NO_ERROR)
3428 return rc;
3429
3430 /* IF no enough memory THEN (try) allocate more. */
3431 AllocateMoreMemory(offCurEntryBundle + 4 + 2 + 5 > cbEBAllocated /* max memory uasage! Should detect more exact memory usage! */,
3432 pEntryBundles, struct b32_bundle *, cbEBAllocated , 512, 256)
3433
3434 /* Add unused entry to skip ordinals? */
3435 if (ulOrdinal > ulLastOrdinal + 1)
3436 {
3437 /* Add unused entry which skips to the new ordinal - 1.*/
3438 pBundle = (struct b32_bundle *)((ULONG)pEntryBundles + offCurEntryBundle);
3439 pBundle->b32_cnt = (UCHAR)(ulOrdinal - ulLastOrdinal + 1);
3440 pBundle->b32_type = EMPTY;
3441
3442 /* Update offCurEntryBundle and offLastEntryBundle */
3443 offLastEntryBundle = offCurEntryBundle += 2UL;
3444 }
3445
3446 /* new entry32 bundle? */
3447 pBundle = (struct b32_bundle *)((ULONG)pEntryBundles + offLastEntryBundle);
3448 if (offCurEntryBundle == offLastEntryBundle || pBundle->b32_type != ENTRY32
3449 || pBundle->b32_obj != iObj || pBundle->b32_cnt == 255)
3450 {
3451 /* Add an empty 32-bit bundle. */
3452 pBundle = (struct b32_bundle *)((ULONG)pEntryBundles + offCurEntryBundle);
3453 pBundle->b32_cnt = 0;
3454 pBundle->b32_type = ENTRY32;
3455 pBundle->b32_obj = (USHORT)iObj;
3456 /* Set offLastEntryBundle to start of new 32-bit bundle. */
3457 offLastEntryBundle = offCurEntryBundle;
3458 /* Set offCurEntryBundle to end of of the new 32-bit bundle. */
3459 offCurEntryBundle += sizeof(struct b32_bundle);
3460 }
3461
3462 /* Add Flags (01h) and 32-bit offset. */
3463 pEntry = (struct e32_entry *)((ULONG)pEntryBundles + offCurEntryBundle);
3464 pEntry->e32_flags = E32EXPORT;
3465 pEntry->e32_variant.e32_offset.offset32 = offObject;
3466 pBundle->b32_cnt++;
3467
3468 /* Update offCurEntryBundle. */
3469 offCurEntryBundle += FIXENT32;
3470 ulLastOrdinal = ulOrdinal;
3471
3472 printInfA(("Export entry: ulOrdinal=%d ulRVA=%#5x iObj=%2d offObject=%#5x\n",
3473 ulOrdinal, ulRVA, iObj, offObject));
3474
3475 return NO_ERROR;
3476}
3477
3478
3479/**
3480 * Adds a forwarder entry.
3481 * The way this is implemented, it is REQUIRED that the entries are added in strict
3482 * ascending order by ordinal.
3483 * @returns NO_ERROR
3484 * ERROR_NOT_ENOUGH_MEMORY
3485 * ERROR_INVALID_PARAMETER
3486 * @param ulOrdinal Entry ordinal number.
3487 * @param pszDllName Pointer to string containing the dllname.
3488 * @param pszFnNameOrOrd Pointer to string containing either a function or an ordinal.
3489 * Note. Have currently not found any example of an ordinal...
3490 * That is just an assumption!
3491 * @sketch Set forwarder flag.
3492 * Validate input. (ulOrdinal and pointers)
3493 * IF no enough memory THEN (try) allocate more.
3494 * IF Function ordinal THEN convert it to an ordinal number.
3495 * Add module name.
3496 * IF not forwarder to ordinal THEN Add name to imported procedure table.
3497 * IF last ordinal + 1 != new ordinal THEN
3498 * BEGIN
3499 * Add unused entry which skips to the new ordinal - 1.
3500 * Update offCurEntryBundle
3501 * Set offLastEntryBundle to offLastEntryBundle.
3502 * END
3503 * IF offCurEntryBundle == offLastEntryBundle OR last bundle type != forwarder entry
3504 * OR bundle is full THEN
3505 * BEGIN
3506 * Add an empty forwarder bundle.
3507 * Set offLastEntryBundle to start of the new forwarder bundle.
3508 * Set offCurEntryBundle to end of of the new forwarder bundle.
3509 * END
3510 * Add Flags, module ordinal and name offset/ordinal number.
3511 * Update offCurEntryBundle.
3512 * return successfully.
3513 * @status completely implemented.
3514 * @author knut st. osmundsen
3515 * @remark Entry Table format (from Linear eXecutable Module Format,lxspec.inf, Rev.8):
3516 *
3517 * Forwarder Entry:
3518 * ---------------
3519 * ÚÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄ¿
3520 * 00h ³ CNT ³TYPE ³ RESERVED ³
3521 * ÃÄÄÄÄÄÅÄÄÄÄÄÁÄÄÄÄÄÂÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
3522 * 04h ³FLAGS³ MOD ORD# ³ OFFSET / ORDNUM ³
3523 * ÃÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄŽ
3524 * 09h ³ ... ³ ... ³ ... ³
3525 *
3526 *
3527 * CNT = DB Number of entries. This is the number of forwarder entries in this bundle.
3528 * The FLAGS, MOD ORD#, and OFFSET/ORDNUM values are repeated this number of times.
3529 *
3530 * TYPE = DB 4 (Forwarder Entry)
3531 *
3532 * RESERVED = DW 0 This field is reserved for future use.
3533 *
3534 * FLAGS = DB Forwarder flags. These are the flags for this entry point. They have the
3535 * following definition.
3536 * 01h = Import by ordinal.
3537 * F7h = Reserved for future use; should be zero.
3538 *
3539 * MOD ORD# = DW Module Ordinal Number This is the index into the Import Module Name Table
3540 * for this forwarder.
3541 *
3542 * OFFSET / ORDNUM = DD Procedure Name Offset or Import Ordinal Number If the FLAGS field
3543 * indicates import by ordinal, then this field is the ordinal number into the Entry Table
3544 * of the target module, otherwise this field is the offset into the Procedure Names Table
3545 * of the (?)target(?) module.
3546 *
3547 * A Forwarder entry (type = 4) is an entry point whose value is an imported reference. When a
3548 * load time fixup occurs whose target is a forwarder, the loader obtains the address imported
3549 * by the forwarder and uses that imported address to resolve the fixup.
3550 *
3551 * A forwarder may refer to an entry point in another module which is itself a forwarder, so there
3552 * can be a chain of forwarders. The loader will traverse the chain until it finds a non-forwarded
3553 * entry point which terminates the chain , and use this to resolve the original fixup. Circular
3554 * chains are detected by the loader and result in a load time error. A maximum of 1024
3555 * forwarders is allowed in a chain; more than this results in a load time error.
3556 *
3557 * Forwarders are useful for merging and recombining API calls into different sets of libraries,
3558 * while maintaining compatibility with applications. For example, if one wanted to combine
3559 * MONCALLS, MOUCALLS, and VIOCALLS into a single libraries, one could provide entry points
3560 * for the three libraries that are forwarders pointing to the common implementation.
3561 *
3562 * ---------------
3563 *
3564 * Forwarder makes some minor difficulties concerning function names.
3565 * We then have to
3566 * 1) Allways convert entries before imports (fixups).
3567 * 2) When forwarders are present makeFixups can't be called without calling makeExports first.
3568 * 3) initEntries will clean up import variables too if fForwarders is set.
3569 */
3570ULONG Pe2Lx::addForwarderEntry(ULONG ulOrdinal, PCSZ pszDllName, PCSZ pszFnNameOrOrd)
3571{
3572 APIRET rc;
3573 ULONG ulFnOrdinal; /* function ordinal or function offset into import procdure table.
3574 * The high bit is set when it is an ordinal value. (remember to mask it off!)
3575 * The high bit is clear when it is an offset. */
3576 ULONG ulModuleOrdinal; /* Module ordinal */
3577 struct b32_bundle *pBundle; /* pointer to current (offLast...) entry bundle. */
3578 struct e32_entry *pEntry; /* pointer to new entry (new entry in the array imediately following the bundle) . */
3579 PCSZ psz; /* temporary string pointer. */
3580
3581 /* Set forwarder flag. */
3582 fForwarders = TRUE;
3583
3584 /* Validate input. (ulOrdinal and pointers) */
3585 if (ulOrdinal < ulLastOrdinal + 1UL || ulOrdinal > 65535UL)
3586 {
3587 printErr(("Invalid ordinal. ulOrdinal %d, ulLastOrdinal %d.\n", ulOrdinal, ulLastOrdinal));
3588 return ERROR_INVALID_PARAMETER;
3589 }
3590 #ifdef DEBUG
3591 if (pszDllName < (PCSZ)0x10000UL || pszFnNameOrOrd < (PCSZ)0x10000UL)
3592 return ERROR_INVALID_PARAMETER;
3593 #endif
3594
3595 /* IF no enough memory THEN (try) allocate more. */
3596 AllocateMoreMemory(offCurEntryBundle + 4 + 2 + 7 > cbEBAllocated /* max memory uasage! Should detect more exact memory usage! */,
3597 pEntryBundles, struct b32_bundle *, cbEBAllocated , 512, 256)
3598
3599 /* IF Function ordinal THEN convert it to an ordinal number. */
3600 ulFnOrdinal = 0UL;
3601 psz = pszFnNameOrOrd;
3602 while (*psz != '\0' && *psz >= '0' && *psz <= '9')
3603 ulFnOrdinal = (ulFnOrdinal*10) + *psz - '0';
3604 if (*psz == '\0')
3605 ulFnOrdinal |= 0x80000000UL; /* ordinal flag */
3606 else
3607 ulFnOrdinal = 0; /* not ordinal! */
3608
3609 /* Add module name. */
3610 rc = addModule(pszDllName, (PULONG)SSToDS(&ulModuleOrdinal));
3611 if (rc != NO_ERROR)
3612 return rc;
3613
3614 /* IF not forwarder to ordinal THEN Add name to imported procedure table. */
3615 if (!(ulFnOrdinal & 0x80000000UL))
3616 {
3617 rc = addImportFunctionName(pszFnNameOrOrd, (PULONG)SSToDS(&ulFnOrdinal));
3618 if (rc != NO_ERROR)
3619 return rc;
3620 }
3621
3622 /* Add unused entry to skip ordinals? */
3623 if (ulOrdinal > ulLastOrdinal + 1)
3624 {
3625 /* Add unused entry which skips to the new ordinal - 1.*/
3626 pBundle = (struct b32_bundle *)((ULONG)pEntryBundles + offCurEntryBundle);
3627 pBundle->b32_cnt = (UCHAR)(ulOrdinal - ulLastOrdinal + 1);
3628 pBundle->b32_type = EMPTY;
3629
3630 /* Update offCurEntryBundle and offLastEntryBundle */
3631 offLastEntryBundle = offCurEntryBundle += 2UL;
3632 }
3633
3634 /* new forwarder bundle? */
3635 pBundle = (struct b32_bundle *)((ULONG)pEntryBundles + offLastEntryBundle);
3636 if (offCurEntryBundle == offLastEntryBundle || pBundle->b32_type != ENTRYFWD
3637 || pBundle->b32_cnt == 255)
3638 {
3639 /* Add an empty 32-bit bundle. */
3640 pBundle = (struct b32_bundle *)((ULONG)pEntryBundles + offCurEntryBundle);
3641 pBundle->b32_cnt = 0;
3642 pBundle->b32_type = ENTRYFWD;
3643 pBundle->b32_obj = 0;
3644 /* Set offLastEntryBundle to start of the new forwarder bundle. */
3645 offLastEntryBundle = offCurEntryBundle;
3646 /* Set offCurEntryBundle to end of of the new forwarder bundle. */
3647 offCurEntryBundle += sizeof(struct b32_bundle);
3648 }
3649
3650 /* Add Flags, module ordinal and name offset/ordinal number. */
3651 pEntry = (struct e32_entry *)((ULONG)pEntryBundles + offCurEntryBundle);
3652 pEntry->e32_flags = (UCHAR)(ulFnOrdinal & 0x80000000UL ? FWD_ORDINAL : 0);
3653 pEntry->e32_variant.e32_fwd.modord = (USHORT)ulModuleOrdinal;
3654 pEntry->e32_variant.e32_fwd.value = ulFnOrdinal & 0x7fffffffUL;
3655 pBundle->b32_cnt++;
3656
3657 /* Update offCurEntryBundle. */
3658 offCurEntryBundle += FWDENT;
3659 ulLastOrdinal = ulOrdinal;
3660
3661 printInfA(("Forwarder Export entry: ulOrdinal=%d pszDllName=%s pszFnNameOrOrd=%s\n",
3662 ulOrdinal, pszDllName, pszFnNameOrOrd));
3663
3664 return NO_ERROR;
3665}
3666
3667
3668/**
3669 * Adds the closing entry bundle.
3670 * @returns NO_ERROR
3671 * ERROR_NOT_ENOUGH_MEMORY
3672 * @sketch IF no enough memory THEN (try) allocate more.
3673 * fill in final bundle. (cnt=0 only)
3674 * Update off*.
3675 * return successfully.
3676 * @status completely implemented; tested.
3677 * @author knut st. osmundsen
3678 * @remark Should only be called to close a sequence of addEntry and addForwarderEntry calls.
3679 */
3680ULONG Pe2Lx::addLastEntry()
3681{
3682 struct b32_bundle *pBundle; /* pointer to current (offLast...) entry bundle. */
3683
3684 /* IF no enough memory THEN (try) allocate more. */
3685 /* table is terminated by a single '\0' byte according to the docs. */
3686 AllocateMoreMemory(offCurEntryBundle + 1 > cbEBAllocated,
3687 pEntryBundles, struct b32_bundle *, cbEBAllocated, 1, 1)
3688
3689 /* fill in final bundle (cnt = 0!) */
3690 pBundle = (struct b32_bundle *)((ULONG)pEntryBundles + offCurEntryBundle);
3691 pBundle->b32_cnt = 0;
3692
3693 /* Update offLastEntryBundle and offLastEntryBundle. */
3694 offLastEntryBundle = offCurEntryBundle += 1;
3695
3696 return NO_ERROR;
3697}
3698
3699
3700/**
3701 * Releases unsused memory from the Export data structures.
3702 * @status completely implemented; tested
3703 * @author knut st. osmundsen
3704 */
3705VOID Pe2Lx::finalizeExports()
3706{
3707 if (pEntryBundles != NULL && offCurEntryBundle < cbEBAllocated)
3708 {
3709 PVOID pv = realloc(pEntryBundles, offCurEntryBundle);
3710 if (pv != NULL)
3711 {
3712 pEntryBundles = (struct b32_bundle*)pv;
3713 cbEBAllocated = offCurEntryBundle;
3714 }
3715 }
3716
3717 if (pachResNameTable != NULL && offCurResName < cchRNTAllocated)
3718 {
3719 PVOID pv = realloc(pachResNameTable, offCurResName);
3720 if (pv != NULL)
3721 {
3722 pachResNameTable = (PCHAR)pv;
3723 cchRNTAllocated = offCurEntryBundle;
3724 }
3725 }
3726}
3727
3728
3729/**
3730 * Gets the number of pages in the virtual lx file.
3731 * @returns Number of pages. (0UL is a valid return!)
3732 * @status completely implemented; tested.
3733 * @author knut st. osmundsen
3734 * @remark fAllInOneObject should be established before this function is called!
3735 */
3736ULONG Pe2Lx::getCountOfPages()
3737{
3738 ULONG cPages = 0UL;
3739 ULONG iObj;
3740
3741 for (iObj = 0; iObj < cObjects; iObj++)
3742 {
3743 if (fAllInOneObject && iObj + 1 < cObjects)
3744 cPages += ALIGN(paObjects[iObj+1].ulRVA - paObjects[iObj].ulRVA, PAGESIZE) >> CB2PAGES_SHIFT;
3745 else
3746 cPages += ALIGN(paObjects[iObj].cbVirtual, PAGESIZE) >> CB2PAGES_SHIFT;
3747 }
3748
3749 return cPages;
3750}
3751
3752
3753/**
3754 * Gets the object number (1 based!) and offset into that object.
3755 * @returns NO_ERROR
3756 * ERROR_INVALID_PARAMETER
3757 * @param ulRVA
3758 * @param pulObject Pointer to variable which will hold the object number upon return. (1 based)
3759 * @param poffObject Pointer to variabel which will hold the object offset upon return.
3760 * @sketch Validate input pointers.
3761 * find object. (be aware of fAllInOneObject!)
3762 * IF object not found THEN return error invalid parameter.
3763 * Set output parameters.
3764 * return successfully.
3765 * @status completely implemented; tested.
3766 * @author knut st. osmundsen
3767 * @remark ulRVA points within a valid (LX term) page area.
3768 */
3769ULONG Pe2Lx::queryObjectAndOffset(ULONG ulRVA, PULONG pulObject, PULONG poffObject)
3770{
3771 ULONG iObj;
3772
3773 #ifdef DEBUG
3774 /* validate passed in pointers. */
3775 if (pulObject < (PULONG)0x10000UL)
3776 {
3777 printErr(("Invalid parameter pulObject.\n"));
3778 return ERROR_INVALID_PARAMETER;
3779 }
3780 if (poffObject < (PULONG)0x10000UL)
3781 {
3782 printErr(("Invalid parameter poffObject.\n"));
3783 return ERROR_INVALID_PARAMETER;
3784 }
3785 #endif
3786
3787 /* find object */
3788 if (!fAllInOneObject)
3789 {
3790 iObj = 0;
3791 while (iObj < cObjects && paObjects[iObj].ulRVA + paObjects[iObj].cbVirtual <= ulRVA)
3792 iObj++;
3793
3794 if (iObj >= cObjects || paObjects[iObj].ulRVA > ulRVA)
3795 return ERROR_INVALID_PARAMETER;
3796 }
3797 else
3798 { /* one large object! */
3799 if (cObjects != 0 && ulRVA >= paObjects[0].ulRVA
3800 && ulRVA <= paObjects[cObjects-1].ulRVA + paObjects[cObjects-1].cbVirtual)
3801 iObj = 0;
3802 else
3803 return ERROR_INVALID_PARAMETER;
3804 }
3805
3806 /* set output */
3807 *poffObject = ulRVA - paObjects[iObj].ulRVA;
3808 *pulObject = iObj + 1;
3809
3810 return NO_ERROR;
3811}
3812
3813
3814/**
3815 * Check if the modulename exists in the lielist. If not the passed in modulename is returned.
3816 * @returns Pointer (readonly) to Odin32 modulename.
3817 * @param pszWin32ModuleName Win32 modulename.
3818 * @status completely implemented.
3819 * @author knut st. osmundsen
3820 * @remark static method.
3821 */
3822PCSZ Pe2Lx::queryOdin32ModuleName(PCSZ pszWin32ModuleName)
3823{
3824 int i = 0;
3825
3826 while (paLieList[i].pszWin32Name != NULL)
3827 {
3828 if (stricmp(paLieList[i].pszWin32Name, pszWin32ModuleName) == 0)
3829 return paLieList[i].pszOdin32Name;
3830 i++;
3831 }
3832
3833 return pszWin32ModuleName;
3834}
3835
3836
3837/**
3838 * Static method which dumps a set of nt headers.
3839 * @param pNtHdrs Pointer to nt headers.
3840 * @status Completed
3841 * @author knut st. osmundsen
3842 */
3843VOID Pe2Lx::dumpNtHeaders(PIMAGE_NT_HEADERS pNtHdrs)
3844{
3845 if (pNtHdrs >= (PIMAGE_NT_HEADERS)0x10000)
3846 {
3847 int i;
3848 WORD w;
3849
3850 printInf(("\nPE-headers - File header\n"));
3851 printInf(("Signature %.2s\n", &pNtHdrs->Signature));
3852 printInf(("Machine 0x%08x\n", pNtHdrs->FileHeader.Machine));
3853 switch (pNtHdrs->FileHeader.Machine)
3854 {
3855 case IMAGE_FILE_MACHINE_UNKNOWN: printInf((" IMAGE_FILE_MACHINE_UNKNOWN\n")); break;
3856 case IMAGE_FILE_MACHINE_I386: printInf((" IMAGE_FILE_MACHINE_I386\n")); break;
3857 case IMAGE_FILE_MACHINE_R3000: printInf((" IMAGE_FILE_MACHINE_R3000\n")); break;
3858 case IMAGE_FILE_MACHINE_R4000: printInf((" IMAGE_FILE_MACHINE_R4000\n")); break;
3859 case IMAGE_FILE_MACHINE_R10000: printInf((" IMAGE_FILE_MACHINE_R10000\n")); break;
3860 case IMAGE_FILE_MACHINE_ALPHA: printInf((" IMAGE_FILE_MACHINE_ALPHA\n")); break;
3861 case IMAGE_FILE_MACHINE_POWERPC: printInf((" IMAGE_FILE_MACHINE_POWERPC\n")); break;
3862 default:
3863 printInf((" *unknown*\n"));
3864 }
3865 printInf(("NumberOfSections %d\n", pNtHdrs->FileHeader.NumberOfSections));
3866 printInf(("TimeDataStamp 0x%08x\n", pNtHdrs->FileHeader.TimeDateStamp));
3867 printInf(("PointerToSymbolTable 0x%08x\n", pNtHdrs->FileHeader.PointerToSymbolTable));
3868 printInf(("NumberOfSymbols %d\n", pNtHdrs->FileHeader.NumberOfSymbols));
3869 printInf(("SizeOfOptionalHeader %d\n", pNtHdrs->FileHeader.SizeOfOptionalHeader));
3870 printInf(("Characteristics 0x%04x\n", pNtHdrs->FileHeader.Characteristics));
3871 w = pNtHdrs->FileHeader.Characteristics;
3872 if ((w & IMAGE_FILE_RELOCS_STRIPPED) == IMAGE_FILE_RELOCS_STRIPPED)
3873 printInf((" IMAGE_FILE_RELOCS_STRIPPED\n"));
3874 if ((w & IMAGE_FILE_EXECUTABLE_IMAGE) == IMAGE_FILE_EXECUTABLE_IMAGE)
3875 printInf((" IMAGE_FILE_EXECUTABLE_IMAGE\n"));
3876 if ((w & IMAGE_FILE_LINE_NUMS_STRIPPED) == IMAGE_FILE_LINE_NUMS_STRIPPED)
3877 printInf((" IMAGE_FILE_LINE_NUMS_STRIPPED\n"));
3878 if ((w & IMAGE_FILE_LOCAL_SYMS_STRIPPED) == IMAGE_FILE_LOCAL_SYMS_STRIPPED)
3879 printInf((" IMAGE_FILE_LOCAL_SYMS_STRIPPED\n"));
3880 if ((w & 0x0010) == 0x0010)
3881 printInf((" IMAGE_FILE_AGGRESIVE_WS_TRIM\n"));
3882 if ((w & IMAGE_FILE_BYTES_REVERSED_LO) == IMAGE_FILE_BYTES_REVERSED_LO)
3883 printInf((" IMAGE_FILE_BYTES_REVERSED_LO\n"));
3884 if ((w & IMAGE_FILE_32BIT_MACHINE) == IMAGE_FILE_32BIT_MACHINE)
3885 printInf((" IMAGE_FILE_32BIT_MACHINE\n"));
3886 if ((w & IMAGE_FILE_DEBUG_STRIPPED) == IMAGE_FILE_DEBUG_STRIPPED)
3887 printInf((" IMAGE_FILE_DEBUG_STRIPPED\n"));
3888 if ((w & 0x0400) == 0x0400)
3889 printInf((" IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP\n"));
3890 if ((w & 0x0800) == 0x0800)
3891 printInf((" IMAGE_FILE_NET_RUN_FROM_SWAP\n"));
3892 if ((w & IMAGE_FILE_SYSTEM) == IMAGE_FILE_SYSTEM)
3893 printInf((" IMAGE_FILE_SYSTEM\n"));
3894 if ((w & IMAGE_FILE_DLL) == IMAGE_FILE_DLL)
3895 printInf((" IMAGE_FILE_DLL\n"));
3896 if ((w & 0x4000) == 0x4000)
3897 printInf((" IMAGE_FILE_UP_SYSTEM_ONLY\n"));
3898 if ((w & IMAGE_FILE_BYTES_REVERSED_HI) == IMAGE_FILE_BYTES_REVERSED_HI)
3899 printInf((" IMAGE_FILE_BYTES_REVERSED_HI\n"));
3900
3901 printInf(("\nPE-headers - Optional header\n"));
3902 printInf(("Magic 0x%04x\n", pNtHdrs->OptionalHeader.Magic));
3903 printInf(("MajorLinkerVersion %d\n", pNtHdrs->OptionalHeader.MajorLinkerVersion));
3904 printInf(("MinorLinkerVersion %d\n", pNtHdrs->OptionalHeader.MajorLinkerVersion));
3905 printInf(("SizeOfCode 0x%08x\n", pNtHdrs->OptionalHeader.SizeOfCode));
3906 printInf(("SizeOfInitializedData 0x%08x\n", pNtHdrs->OptionalHeader.SizeOfInitializedData));
3907 printInf(("SizeOfUninitializedData 0x%08x\n", pNtHdrs->OptionalHeader.SizeOfUninitializedData));
3908 printInf(("AddressOfEntryPoint 0x%08x\n", pNtHdrs->OptionalHeader.AddressOfEntryPoint));
3909 printInf(("BaseOfCode 0x%08x\n", pNtHdrs->OptionalHeader.BaseOfCode));
3910 printInf(("BaseOfData 0x%08x\n", pNtHdrs->OptionalHeader.BaseOfData));
3911 printInf(("ImageBase 0x%08x\n", pNtHdrs->OptionalHeader.ImageBase));
3912 printInf(("SectionAlignment 0x%08x\n", pNtHdrs->OptionalHeader.SectionAlignment));
3913 printInf(("FileAlignment 0x%08x\n", pNtHdrs->OptionalHeader.FileAlignment));
3914 printInf(("MajorOperatingSystemVersion %d\n", pNtHdrs->OptionalHeader.MajorOperatingSystemVersion));
3915 printInf(("MinorOperatingSystemVersion %d\n", pNtHdrs->OptionalHeader.MinorOperatingSystemVersion));
3916 printInf(("MajorImageVersion %d\n", pNtHdrs->OptionalHeader.MajorImageVersion));
3917 printInf(("MinorImageVersion %d\n", pNtHdrs->OptionalHeader.MinorImageVersion));
3918 printInf(("MajorSubsystemVersion %d\n", pNtHdrs->OptionalHeader.MajorSubsystemVersion));
3919 printInf(("MinorSubsystemVersion %d\n", pNtHdrs->OptionalHeader.MinorSubsystemVersion));
3920 printInf(("Win32VersionValue 0x%08x\n", pNtHdrs->OptionalHeader.Reserved1));
3921 printInf(("SizeOfImage 0x%08x\n", pNtHdrs->OptionalHeader.SizeOfImage));
3922 printInf(("SizeOfHeaders 0x%08x\n", pNtHdrs->OptionalHeader.SizeOfHeaders));
3923 printInf(("CheckSum 0x%08x\n", pNtHdrs->OptionalHeader.CheckSum));
3924 printInf(("Subsystem 0x%04x\n", pNtHdrs->OptionalHeader.Subsystem));
3925
3926 switch(pNtHdrs->OptionalHeader.Subsystem)
3927 {
3928 case IMAGE_SUBSYSTEM_UNKNOWN: printInf((" IMAGE_SUBSYSTEM_UNKNOWN\n")); break;
3929 case IMAGE_SUBSYSTEM_NATIVE: printInf((" IMAGE_SUBSYSTEM_NATIVE\n")); break;
3930 case IMAGE_SUBSYSTEM_WINDOWS_GUI: printInf((" IMAGE_SUBSYSTEM_WINDOWS_GUI\n")); break;
3931 case IMAGE_SUBSYSTEM_WINDOWS_CUI: printInf((" IMAGE_SUBSYSTEM_WINDOWS_CUI\n")); break;
3932 case IMAGE_SUBSYSTEM_OS2_CUI: printInf((" IMAGE_SUBSYSTEM_OS2_CUI\n")); break;
3933 case IMAGE_SUBSYSTEM_POSIX_CUI: printInf((" IMAGE_SUBSYSTEM_POSIX_CUI\n")); break;
3934 case 8: printInf((" IMAGE_SUBSYSTEM_NATIVE_WINDOWS\n")); break;
3935 case 9: printInf((" IMAGE_SUBSYSTEM_WINDOWS_CE_GUI\n")); break;
3936 default:
3937 printInf((" *unknown*"));
3938 }
3939 printInf(("DllCharacteristics 0x%04x\n", pNtHdrs->OptionalHeader.DllCharacteristics));
3940 printInf(("SizeOfStackReserve 0x%08x\n", pNtHdrs->OptionalHeader.SizeOfStackReserve));
3941 printInf(("SizeOfStackCommit 0x%08x\n", pNtHdrs->OptionalHeader.SizeOfStackCommit));
3942 printInf(("SizeOfHeapReserve 0x%08x\n", pNtHdrs->OptionalHeader.SizeOfHeapReserve));
3943 printInf(("SizeOfHeapCommit 0x%08x\n", pNtHdrs->OptionalHeader.SizeOfHeapCommit));
3944 printInf(("LoaderFlags 0x%08x\n", pNtHdrs->OptionalHeader.LoaderFlags));
3945 printInf(("NumberOfRvaAndSizes 0x%08x\n", pNtHdrs->OptionalHeader.NumberOfRvaAndSizes));
3946
3947 printInf(("\nPE-Headers - DataDirectory\n"));
3948 for (i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++)
3949 {
3950 char *pszName;
3951
3952 switch (i)
3953 {
3954 case IMAGE_DIRECTORY_ENTRY_EXPORT: pszName = "Export Directory (IMAGE_DIRECTORY_ENTRY_EXPORT)"; break;
3955 case IMAGE_DIRECTORY_ENTRY_IMPORT: pszName = "Import Directory (IMAGE_DIRECTORY_ENTRY_IMPORT)"; break;
3956 case IMAGE_DIRECTORY_ENTRY_RESOURCE: pszName = "Resource Directory (IMAGE_DIRECTORY_ENTRY_RESOURCE)"; break;
3957 case IMAGE_DIRECTORY_ENTRY_EXCEPTION: pszName = "Exception Directory (IMAGE_DIRECTORY_ENTRY_EXCEPTION)"; break;
3958 case IMAGE_DIRECTORY_ENTRY_SECURITY: pszName = "Security Directory (IMAGE_DIRECTORY_ENTRY_SECURITY)"; break;
3959 case IMAGE_DIRECTORY_ENTRY_BASERELOC: pszName = "Base Relocation Table (IMAGE_DIRECTORY_ENTRY_BASERELOC)"; break;
3960 case IMAGE_DIRECTORY_ENTRY_DEBUG: pszName = "Debug Directory (IMAGE_DIRECTORY_ENTRY_DEBUG)"; break;
3961 case IMAGE_DIRECTORY_ENTRY_COPYRIGHT: pszName = "Description String (IMAGE_DIRECTORY_ENTRY_COPYRIGHT)"; break;
3962 case IMAGE_DIRECTORY_ENTRY_GLOBALPTR: pszName = "Machine Value (MIPS GP) (IMAGE_DIRECTORY_ENTRY_GLOBALPTR)"; break;
3963 case IMAGE_DIRECTORY_ENTRY_TLS: pszName = "TLS Directory (IMAGE_DIRECTORY_ENTRY_TLS)"; break;
3964 case IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG: pszName = "Load Configuration Directory (IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG)"; break;
3965 case IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT:pszName = "Bound Import Directory in headers (IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT)"; break;
3966 case IMAGE_DIRECTORY_ENTRY_IAT: pszName = "Import Address Table (IMAGE_DIRECTORY_ENTRY_IAT)"; break;
3967 default:
3968 pszName = "unknown";
3969 }
3970
3971 printInf(("%2d %s\n", i, pszName));
3972 printInf((" Address 0x%08x\n", pNtHdrs->OptionalHeader.DataDirectory[i].VirtualAddress));
3973 printInf((" Size 0x%08x\n", pNtHdrs->OptionalHeader.DataDirectory[i].Size));
3974 }
3975 }
3976}
3977
3978
3979/**
3980 * Static method which dumps a section header.
3981 * @param pSection Pointer to a section header.
3982 * @status paritally implemented.
3983 * @author knut st. osmundsen
3984 * @remark Missing flags symbols!
3985 */
3986VOID Pe2Lx::dumpSectionHeader(PIMAGE_SECTION_HEADER pSection)
3987{
3988 if (pSection >= (PIMAGE_SECTION_HEADER)0x10000)
3989 {
3990 printInf(("\nSection Name: %.8s\n", pSection->Name));
3991 printInf(("Raw data size: 0x%08x\n", pSection->SizeOfRawData));
3992 printInf(("Virtual Address: 0x%08x\n", pSection->VirtualAddress));
3993 printInf(("Virtual Size: 0x%08x\n", pSection->Misc.VirtualSize));
3994 printInf(("Pointer to raw data: 0x%08x\n", pSection->PointerToRawData));
3995 printInf(("Section flags: 0x%08x\n", pSection->Characteristics));
3996 /* FIXME! display flags! */
3997 }
3998 else
3999 printInf(("dumpSectionHeader - invalid pointer specified! pSection=%#8x\n", pSection));
4000}
4001
4002
4003/**
4004 * Constructor.
4005 * @param hFile Filehandle.
4006 * @param cObjects Count of objects in the object array pointed to by paObjects.
4007 * @param paObjects Read-only pointer to object array.
4008 * @status completely implemented; tested.
4009 * @author knut st. osmundsen
4010 */
4011BufferedRVARead::BufferedRVARead(SFN hFile, ULONG cObjects, PCLXOBJECT paObjects)
4012 : hFile(hFile), cObjects(cObjects), paObjects(paObjects), ulRVA(~0UL)
4013{
4014}
4015
4016#if 0 /* made inline! */
4017/**
4018 * Reads a chunk of data at the spcified RVA.
4019 * @returns NO_ERROR on success.
4020 * ERROR_INVALID_PARAMETER
4021 * <Whatever rc ReadAt returns>
4022 * @param ulRVA RVA to read from. Within the filesize.
4023 * @param pvBuffer Pointer to output buffer. pvBuffer > 64KB
4024 * @param cbBuffer Number of bytes to read. 0 < cbBuffer > 256MB
4025 * @status completely implemented; tested.
4026 * @author knut st. osmundsen
4027 */
4028ULONG BufferedRVARead::readAtRVA(ULONG ulRVA, PVOID pvBuffer, ULONG cbBuffer)
4029{
4030 /*
4031 * five cases:
4032 * 1) entire area is within the buffer.
4033 * 2) start of area is within the buffer.
4034 * 3) end of area is within the buffer.
4035 * 4) the area is larger than the buffer, covering it.
4036 * 5) the area is outside the buffer.
4037 *
4038 * these are optimal: 1, 2, and 5.
4039 * The request is allways process from start to end. This will make case 3 and 4 less effecient.
4040 */
4041 #ifdef DEBUG
4042 if (ulRVA == ~0UL || (ULONG)pvBuffer < 0x10000UL || cbBuffer == 0UL || cbBuffer >= 0x10000000UL)
4043 return ERROR_INVALID_PARAMETER;
4044 #endif
4045
4046 do
4047 {
4048 if (ulRVA >= this->ulRVA && ulRVA < this->ulRVA + sizeof(achBuffer))
4049 { /* in buffer */
4050 register ULONG cbRead = sizeof(achBuffer) - (ulRVA - this->ulRVA);
4051 cbRead = min(cbRead, cbBuffer);
4052 memcpy(pvBuffer, &achBuffer[ulRVA - this->ulRVA], (size_t)cbRead);
4053 if (cbBuffer == cbRead)
4054 return NO_ERROR;
4055 cbBuffer -= cbRead;
4056 pvBuffer = (PVOID)((ULONG)pvBuffer + cbRead);
4057 ulRVA += cbRead;
4058 }
4059 else
4060 { /* not in buffer, then read it into the buffer! */
4061 APIRET rc = readToBuffer(ulRVA);
4062 if (rc != NO_ERROR)
4063 return rc;
4064 }
4065 } while (cbBuffer != 0UL);
4066
4067 return NO_ERROR;
4068}
4069#endif
4070
4071
4072/**
4073 * Reads a zero string into a heap block and returns it to the caller (thru ppsz).
4074 * @returns NO_ERROR
4075 * ERROR_INVALID_PARAMETER
4076 * ERROR_NOT_ENOUGH_MEMORY
4077 * Return code from ReadAt.
4078 * @param ulRVA RVA which the string is to be read from.
4079 * @param ppsz Pointer to a stringpointer. Output: This will hold pointer to a heapblock with the string.
4080 * @status completely implemented; tested.
4081 * @author knut st. osmundsen
4082 */
4083ULONG BufferedRVARead::dupString(ULONG ulRVA, PSZ *ppsz)
4084{
4085 #ifdef DEBUG
4086 if (ulRVA == ~0UL || ppsz == NULL)
4087 return ERROR_INVALID_PARAMETER;
4088 #endif
4089
4090 if (ppsz < (PSZ*)0x10000UL)
4091 {
4092 printErr(("Call to dupString with a unconverted stack pointer!.\n"));
4093 ppsz = (PSZ*)SSToDS(ppsz);
4094 }
4095
4096 *ppsz = NULL;
4097 ULONG cchAllocated = 0UL;
4098 ULONG offCurrent = 0UL;
4099 while (TRUE)
4100 {
4101 if (ulRVA >= this->ulRVA && ulRVA < this->ulRVA + sizeof(achBuffer))
4102 { /* in buffer */
4103 ULONG cchAlloc;
4104 PCHAR pch = (PCHAR)memchr(&achBuffer[ulRVA - this->ulRVA], '\0',
4105 sizeof(achBuffer) - (size_t)(ulRVA - this->ulRVA));
4106
4107 /* amout of memory to allocate */
4108 if (pch != NULL)
4109 cchAlloc = (ULONG)pch - (ULONG)&achBuffer[ulRVA - this->ulRVA] + 1;
4110 else
4111 cchAlloc = sizeof(achBuffer) - (ulRVA - this->ulRVA) + 42; /* 42 - think of a number... */
4112
4113 /* allocate (more) memory */
4114 if (*ppsz == NULL)
4115 *ppsz = (PSZ)malloc((size_t)cchAlloc);
4116 else
4117 {
4118 PVOID pv = realloc(*ppsz, (size_t)(cchAlloc + cchAllocated));
4119 if (pv == NULL)
4120 {
4121 free(*ppsz);
4122 *ppsz = NULL;
4123 return ERROR_NOT_ENOUGH_MEMORY;
4124 }
4125 *ppsz = (PSZ)pv;
4126 }
4127 cchAllocated += cchAlloc;
4128
4129 /* copy string data */
4130 if (pch != NULL)
4131 { /* final part of the string. */
4132 strcpy(&(*ppsz)[offCurrent], &achBuffer[ulRVA - this->ulRVA]);
4133 break;
4134 }
4135 /* more to come */
4136 memcpy(&(*ppsz)[offCurrent], &achBuffer[ulRVA - this->ulRVA], sizeof(achBuffer) - (size_t)(ulRVA - this->ulRVA));
4137 offCurrent += sizeof(achBuffer) - (ulRVA - this->ulRVA);
4138 ulRVA = ALIGN(ulRVA+1, sizeof(achBuffer));
4139 }
4140 else
4141 { /* not in buffer, then read it into the buffer! */
4142 APIRET rc = readToBuffer(ulRVA);
4143 if (rc != NO_ERROR)
4144 return rc;
4145 }
4146 }
4147
4148 return NO_ERROR;
4149}
4150
4151
4152/**
4153 * Assignment operator.
4154 * @returns Reference to this BufferedRVARead object.
4155 * @param SrcObj The object on the right side of the operator.
4156 * @status completely implemented.
4157 * @author knut st. osmundsen
4158 */
4159BufferedRVARead & BufferedRVARead::operator =(BufferedRVARead &SrcObj)
4160{
4161 hFile = SrcObj.hFile;
4162 cObjects = SrcObj.cObjects;
4163 paObjects = SrcObj.paObjects;
4164 ulRVA = SrcObj.ulRVA;
4165 if (ulRVA != ~0UL)
4166 memcpy(&achBuffer[0], &SrcObj.achBuffer[0], sizeof(achBuffer));
4167 return *this;
4168}
4169
4170
4171/**
4172 * Reads data to the buffer for a given RVA.
4173 * @returns NO_ERROR
4174 * ERROR_INVALID_PARAMETER
4175 * Return code from ReadAt.
4176 * @param ulRVA RVA to read at/near.
4177 * @status completely implemented; tested.
4178 * @author knut st. osmundsen
4179 */
4180ULONG BufferedRVARead::readToBuffer(ULONG ulRVA)
4181{
4182 ULONG ulRVARead;
4183
4184 /* where to read? */
4185 if (ulRVA != this->ulRVA + sizeof(achBuffer) != ulRVA || this->ulRVA != ~0UL)
4186 ulRVARead = this->ulRVA = ulRVA & ~(PAGESIZE-1UL); /* align on page boundrary - ASSUMES: buffersize >= PAGESIZE! */
4187 else
4188 ulRVARead = this->ulRVA += sizeof(achBuffer); /* immediately after current buffer */
4189
4190 ULONG cbLeftToRead = sizeof(achBuffer);
4191 ULONG iObj = 0;
4192 while (cbLeftToRead != 0UL)
4193 {
4194 while (iObj < cObjects && ulRVARead >= (iObj + 1 < cObjects ? paObjects[iObj+1].ulRVA
4195 : paObjects[iObj].ulRVA + ALIGN(paObjects[iObj].cbVirtual, PAGESIZE))
4196 )
4197 iObj++;
4198 if (iObj >= cObjects)
4199 {
4200 this->ulRVA = ~0UL;
4201 return ERROR_INVALID_PARAMETER;
4202 }
4203
4204 /* ulRVARead points at physical or virtual data? */
4205 if (ulRVARead < paObjects[iObj].ulRVA + paObjects[iObj].cbPhysical)
4206 { /* physical data - read from file */
4207 APIRET rc;
4208 ULONG cbToRead = min(paObjects[iObj].ulRVA + paObjects[iObj].cbPhysical - ulRVARead, cbLeftToRead);
4209 rc = ReadAt(hFile,
4210 ulRVARead - paObjects[iObj].ulRVA + paObjects[iObj].offPEFile,
4211 &achBuffer[sizeof(achBuffer)-cbLeftToRead],
4212 cbToRead
4213 );
4214 if (rc != NO_ERROR)
4215 {
4216 this->ulRVA = ~0UL;
4217 return rc;
4218 }
4219 cbLeftToRead -= cbToRead;
4220 ulRVARead += cbToRead;
4221 }
4222 else
4223 { /* virtual data - memset(,0,) */
4224 ULONG cbToSet = (iObj + 1 < cObjects ? paObjects[iObj+1].ulRVA
4225 : paObjects[iObj].ulRVA + ALIGN(paObjects[iObj].cbVirtual, PAGESIZE))
4226 - ulRVARead; /* calcs size of virtual data left in this object */
4227 cbToSet = min(cbToSet, cbLeftToRead);
4228
4229 memset(&achBuffer[sizeof(achBuffer)-cbLeftToRead], 0, (size_t)cbToSet);
4230 cbLeftToRead -= cbToSet;
4231 ulRVARead += cbToSet;
4232 }
4233 }
4234
4235 return NO_ERROR;
4236}
4237
4238
4239/* end of file */
Note: See TracBrowser for help on using the repository browser.