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

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

Corrected bug in applyFixups which caused fixups not to be applied when
fAllInOneObject was set.
Force all-in-one-object (alignment) fix.

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