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

Last change on this file since 6253 was 6234, checked in by bird, 24 years ago

Three things. Fixed the way we get the environment variables and use our own search methods for the LIBPATHs. Corrected and partly rewrote applyFixup, splitted out delta fixups for performance reasons. Mark all normal executables 'NO INTERNAL FIXUPS' to try force them to load the given address.

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