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

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

Corrected problem with kernel build 14053. (new parameter to ldrOpenPath)
Added symbols for 14053 and 8266.

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