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

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

Some bugsfixes - Yield is disabled.
Added parameters.
Correcte moduleheaders.
Introduced a new base class for virtual lx modules + some elf sketches.

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