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

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

Updated paLieList with OpenGL and CrtDll.

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