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

Last change on this file was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

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