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

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

bugfix for custom build

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