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

Last change on this file since 6852 was 6852, checked in by sandervl, 24 years ago

added options to strip fixups and to reroute imports to custom odin dll

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