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

Last change on this file since 4164 was 4164, checked in by bird, 25 years ago

Merged in the Grace branch. New Win32k!

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