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

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

Updated option/argument handling.
Corrected a few bugs.

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