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

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

Implemented applyFixups which will apply fixups when a page is being loaded.

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