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

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