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

Last change on this file since 6496 was 6493, checked in by bird, 24 years ago

Ignore ERROR_DRIVE_LOCKED (which is normally caused by an chkdsk or format operation).

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