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

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

Allow loading of executables using the NATIVE (=NAIVE? ;-) subsystem.

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