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

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

Corrected lie list.

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