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

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

Added oleaut32 to the lie list.

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