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

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

Corrections to make win32k work.
(And now it does work, at least at my test machine...)

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