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

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

Moved parts from pe2lx.cpp/h to ModuleBase.cpp/h.
Corrected writeLxFile to writeFile.

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