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

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

Temporary backup checkin.

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