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

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

Correcte the RING0 ReadAt macro.

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