source: trunk/src/kernel32/winimagepe2lx.cpp@ 8589

Last change on this file since 8589 was 8589, checked in by bird, 23 years ago

Only apply the case workaround for 4.5.1+ toolkits.

File size: 32.5 KB
Line 
1/* $Id: winimagepe2lx.cpp,v 1.20 2002-06-08 00:26:59 bird Exp $ */
2
3/*
4 * Win32 PE2LX Image base class
5 *
6 * Copyright 1998-1999 Sander van Leeuwen (sandervl@xs4all.nl)
7 * Copyright 1998-1999 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
8 *
9 * Project Odin Software License can be found in LICENSE.TXT
10 *
11 */
12
13/*******************************************************************************
14* Defined Constants And Macros *
15*******************************************************************************/
16#define INCL_DOSERRORS /* DOS Error values */
17#define INCL_DOSPROFILE /* DosQuerySysState (Toolkit 4.5) */
18#define INCL_DOSMODULEMGR /* DOS Module management */
19#define INCL_DOSMISC /* DOS Misc - for the LIBPATHSTRICT define */
20
21#define ALIGN(a, alignment) (((a) + (alignment - 1UL)) & ~(alignment - 1UL))
22
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#include <os2wrap.h> //Odin32 OS/2 api wrappers
28
29#include <malloc.h>
30#include <process.h>
31#include <stdlib.h>
32#include <string.h>
33
34#include <win32type.h>
35#include <misc.h>
36#include "winimagebase.h"
37#include "winimagepe2lx.h"
38#include "Win32k.h"
39
40#define DBG_LOCALLOG DBG_winimagepe2lx
41#include "dbglocal.h"
42
43/*******************************************************************************
44* Structures and Typedefs *
45*******************************************************************************/
46#ifndef QS_MTE
47 /* From OS/2 Toolkit v4.5 (BSEDOS.H) */
48
49 /* Global Record structure
50 * Holds all global system information. Placed first in user buffer
51 */
52 typedef struct qsGrec_s { /* qsGrec */
53 ULONG cThrds;
54 ULONG c32SSem;
55 ULONG cMFTNodes;
56 }qsGrec_t;
57
58 /*
59 * System wide MTE information
60 * ________________________________
61 * | pNextRec |----|
62 * |-------------------------------| |
63 * | hmte | |
64 * |-------------------------------| |
65 * | ctImpMod | |
66 * |-------------------------------| |
67 * | ctObj | |
68 * |-------------------------------| |
69 * | pObjInfo |----|----------|
70 * |-------------------------------| | |
71 * | pName |----|----| |
72 * |-------------------------------| | | |
73 * | imported module handles | | | |
74 * | . | | | |
75 * | . | | | |
76 * | . | | | |
77 * |-------------------------------| <--|----| |
78 * | "pathname" | | |
79 * |-------------------------------| <--|----------|
80 * | Object records | |
81 * | (if requested) | |
82 * |_______________________________| |
83 * <-----
84 * NOTE that if the level bit is set to QS_MTE, the base Lib record will be followed
85 * by a series of object records (qsLObj_t); one for each object of the
86 * module.
87 */
88
89 typedef struct qsLObjrec_s { /* qsLOrec */
90 ULONG oaddr; /* object address */
91 ULONG osize; /* object size */
92 ULONG oflags; /* object flags */
93 } qsLObjrec_t;
94
95 typedef struct qsLrec_s { /* qsLrec */
96 void FAR *pNextRec; /* pointer to next record in buffer */
97 USHORT hmte; /* handle for this mte */
98 USHORT fFlat; /* true if 32 bit module */
99 ULONG ctImpMod; /* # of imported modules in table */
100 ULONG ctObj; /* # of objects in module (mte_objcnt)*/
101 qsLObjrec_t FAR *pObjInfo; /* pointer to per object info if any */
102 UCHAR FAR *pName; /* -> name string following struc */
103 } qsLrec_t;
104
105
106
107 /* Pointer Record Structure
108 * This structure is the first in the user buffer.
109 * It contains pointers to heads of record types that are loaded
110 * into the buffer.
111 */
112
113 typedef struct qsPtrRec_s { /* qsPRec */
114 qsGrec_t *pGlobalRec;
115 void *pProcRec; /* ptr to head of process records */
116 void *p16SemRec; /* ptr to head of 16 bit sem recds */
117 void *p32SemRec; /* ptr to head of 32 bit sem recds */
118 void *pMemRec; /* ptr to head of shared mem recs */
119 qsLrec_t *pLibRec; /* ptr to head of mte records */
120 void *pShrMemRec; /* ptr to head of shared mem records */
121 void *pFSRec; /* ptr to head of file sys records */
122 } qsPtrRec_t;
123
124#else
125 #if defined(QS_MODVER) && defined(QS_DCE_AUTORESET) && defined(LIBPATHSTRICT) /* hope these didn't exists in the other toolkits */
126 /*
127 * Workaround for the 4.5.1+ toolkits.
128 */
129 #define qsPtrRec_t QSPTRREC
130 #define qsLrec_t QSLREC
131 #define qsLObjrec_t QSLOBJREC
132 #define qsGrec_t QSGREC
133 #endif
134#endif
135
136
137/*******************************************************************************
138* External Functions *
139*******************************************************************************/
140#ifndef QS_MTE
141 /* from OS/2 Toolkit v4.5 */
142
143 APIRET APIENTRY DosQuerySysState(ULONG EntityList, ULONG EntityLevel, PID pid,
144 TID tid, PVOID pDataBuf, ULONG cbBuf);
145 #define QS_MTE 0x0004
146#endif
147
148
149
150/**
151 * Constructor - creates an pe2lx image object from a module handle to a pe2lx module.
152 * @param hinstance OS/2 module handle.
153 * @param fWin32k TRUE: Win32k module.
154 * FALSE: Pe2Lx module.
155 * @status partially implemented.
156 * @author knut st. osmundsen, Sander van Leeuwen
157 */
158Win32Pe2LxImage::Win32Pe2LxImage(HINSTANCE hinstance, BOOL fWin32k)
159 : Win32ImageBase(hinstance),
160 paSections(NULL), cSections(0), pNtHdrs(NULL), fWin32k(fWin32k),
161 hmod(hinstance)
162{
163 setFullPath(szFileName);
164}
165
166
167/**
168 * Free memory associated with this object.
169 * @status completely implemented.
170 * @author knut st. osmundsen, Sander van Leeuwen
171 */
172Win32Pe2LxImage::~Win32Pe2LxImage()
173{
174 cleanup();
175}
176
177
178/**
179 * Initiates the object.
180 * Must be called immediately after the object construction.
181 * @returns Success indicator, TRUE == success; FALSE = failure.
182 * @sketch Get section placement and sizes for this module. (paSections, cSections)
183 * Verify that there is at least one section - the header section.
184 * Locate the NT headers.
185 * Set pNtHdrs pointer.
186 * Validate the NT headers.
187 * Read the PE section table the set the RVAs in paSections.
188 * Set instance handle to address of header.
189 * Locate and set the entrypoint.
190 * Locate the resource directory (if any). (pResRootDir, ulRVAResourceSection)
191 * TLS - FIXME!
192 * @status completely implemented.
193 * @author knut st. osmundsen
194 * @remark Object must be destroyed if failure!
195 */
196BOOL Win32Pe2LxImage::init()
197{
198 APIRET rc;
199
200 /* Get section placement and sizes for this module. (paSections, cSections) */
201 rc = getSections();
202 if (rc != NO_ERROR)
203 {
204 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: error - getSection failed with rc=%d\n",
205 rc));
206 return FALSE;
207 }
208
209 /* Verify that there is at least one section - the header section. */
210 if (cSections < 1)
211 {
212 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: no header section, cSections is 0\n"));
213 return FALSE;
214 }
215
216 /* Locate the NT headers. */
217 PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)paSections[0].ulAddress;
218 if ((pDosHdr->e_magic != IMAGE_DOS_SIGNATURE
219 || pDosHdr->e_lfanew < sizeof(IMAGE_DOS_HEADER) /* Larger than 64 bytes */
220 || pDosHdr->e_lfanew > 0x04000000UL /* or less that 64MB. */
221 )
222 && !*(PDWORD)paSections[0].ulAddress == IMAGE_NT_SIGNATURE
223 )
224 {
225 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: Not a pe2lx image!(?)\n"));
226 return FALSE;
227 }
228
229 /* Set pNtHdrs pointer. */
230 if (pDosHdr->e_magic == IMAGE_DOS_SIGNATURE)
231 pNtHdrs = (PIMAGE_NT_HEADERS)(paSections[0].ulAddress + pDosHdr->e_lfanew);
232 else
233 pNtHdrs = (PIMAGE_NT_HEADERS)paSections[0].ulAddress;
234
235 /* Validate the NT headers. */
236 if (pNtHdrs->Signature != IMAGE_NT_SIGNATURE
237 || pNtHdrs->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC
238 || pNtHdrs->FileHeader.Machine != IMAGE_FILE_MACHINE_I386
239 || (cSections != 1 /* all in one object */
240 && pNtHdrs->FileHeader.NumberOfSections
241 > cSections - 1 - (pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL ? 0 : 1) /* hdr section and stack */
242 )
243 /* TODO: add more tests? */
244 )
245 {
246 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: Not a pe2lx image!(?)\n"));
247 return FALSE;
248 }
249
250 /* set RVAs */
251 rc = setSectionRVAs();
252 if (rc != NO_ERROR)
253 {
254 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: setSectionRVAs failed with rc=%d\n", rc));
255 return FALSE;
256 }
257
258 /* Set instance handle to address of header. */
259 hinstance = (HINSTANCE)paSections[0].ulAddress;
260
261 /* Locate and set the entrypoint. */
262 setEntryPoint((ULONG)getPointerFromRVA(pNtHdrs->OptionalHeader.AddressOfEntryPoint));
263 if (entryPoint == 0UL &&
264 (pNtHdrs->OptionalHeader.AddressOfEntryPoint != NULL /* getPointerFromRVA failed... */
265 || !(pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL)) /* EXEs must have and entry point! */
266 )
267 {
268 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: entrypoint is incorrect, AddrOfEP=0x%08x, entryPoint=0x%08x\n",
269 pNtHdrs->OptionalHeader.AddressOfEntryPoint, entryPoint));
270 return FALSE;
271 }
272
273 /* Locate the resource directory (if any) */
274 if (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_RESOURCE
275 && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress > 0UL)
276 {
277 ulRVAResourceSection = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
278 pResRootDir = (PIMAGE_RESOURCE_DIRECTORY)getPointerFromRVA(ulRVAResourceSection);
279 /* _temporary_ fix:
280 * We'll have to make the resource section writable.
281 * And we'll have to make the pages before it readable.
282 */
283 LONG iSection = getSectionIndexFromRVA(ulRVAResourceSection);
284 if (iSection >= 0)
285 {
286 rc = DosSetMem((PVOID)paSections[iSection].ulAddress, paSections[iSection].cbVirtual, PAG_WRITE | PAG_READ);
287
288 ULONG ulAddr = paSections[iSection].ulAddress - 0x10000; //64KB
289 while (ulAddr < paSections[iSection].ulAddress)
290 {
291 ULONG fl = ~0UL;
292 ULONG cb = ~0UL;
293 rc = DosQueryMem((PVOID)ulAddr, &cb, &fl);
294 if (rc == NO_ERROR)
295 {
296 if (fl & PAG_GUARD)
297 rc = -1;
298 else if (fl & PAG_COMMIT)
299 fl &= ~(PAG_COMMIT);
300 else
301 fl |= PAG_COMMIT;
302 cb = (cb + 0xfffUL) & ~0xfffUL;
303 }
304 else
305 {
306 fl = PAG_COMMIT;
307 cb = 0x1000;
308 }
309 fl &= PAG_READ | PAG_COMMIT | PAG_WRITE | PAG_GUARD;
310 fl |= PAG_READ;
311 if (cb > paSections[iSection].ulAddress - ulAddr)
312 cb = paSections[iSection].ulAddress - ulAddr;
313 if (rc == NO_ERROR)
314 rc = DosSetMem((PVOID)ulAddr, cb, fl);
315
316 ulAddr += cb;
317 }
318 }
319 }
320
321 /* TLS - Thread Local Storage */
322 if (pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress != 0UL
323 && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size != 0UL)
324 {
325 PIMAGE_TLS_DIRECTORY pTLSDir;
326 LONG iSection;
327 iSection = getSectionIndexFromRVA(pNtHdrs->OptionalHeader.
328 DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].
329 VirtualAddress);
330 pTLSDir = (PIMAGE_TLS_DIRECTORY)getPointerFromRVA(pNtHdrs->OptionalHeader.
331 DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].
332 VirtualAddress);
333
334 if (pTLSDir != NULL && iSection != -1)
335 {
336 PVOID pv;
337
338 /*
339 * According to the docs StartAddressOfRawData and EndAddressOfRawData is
340 * real pointers with a baserelocs.
341 *
342 * The docs says nothing about the two AddressOf pointers. So, we'll assume that
343 * these also are real pointers. But, we'll try compensate if they should not have
344 * base realocations.
345 */
346 if (validateRealPointer((PVOID)pTLSDir->StartAddressOfRawData)
347 &&
348 validateRealPointer((PVOID)pTLSDir->EndAddressOfRawData)
349 )
350 {
351 setTLSAddress((PVOID)pTLSDir->StartAddressOfRawData);
352 setTLSInitSize(pTLSDir->EndAddressOfRawData - pTLSDir->StartAddressOfRawData);
353 setTLSTotalSize(pTLSDir->EndAddressOfRawData - pTLSDir->StartAddressOfRawData + pTLSDir->SizeOfZeroFill);
354
355 if (pTLSDir->AddressOfIndex)
356 {
357 if (validateRealPointer(pTLSDir->AddressOfIndex))
358 /* assume baserelocations for thepointer; use it without any change. */
359 setTLSIndexAddr((LPDWORD)(void*)pTLSDir->AddressOfIndex);
360 else
361 { /* assume no baserelocs for these pointers? Complain and debugint3 */
362 eprintf(("Win32Pe2LxImage::init: TLS - AddressOfIndex(%#8x) is not a pointer with basereloc.\n",
363 pTLSDir->AddressOfIndex));
364 pv = getPointerFromPointer(pTLSDir->AddressOfIndex);
365 if (pv == NULL)
366 {
367 eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS AddressOfIndex - %#8x.\n",
368 pTLSDir->AddressOfIndex));
369 return FALSE;
370 }
371 setTLSIndexAddr((LPDWORD)pv);
372 }
373 }
374
375 if (pTLSDir->AddressOfCallBacks)
376 {
377 if (validateRealPointer(pTLSDir->AddressOfCallBacks))
378 /* assume baserelocations for thepointer; use it without any change. */
379 setTLSCallBackAddr(pTLSDir->AddressOfCallBacks);
380 else
381 { /* assume no baserelocs for these pointers? Complain and debugint3 */
382 eprintf(("Win32Pe2LxImage::init: Warning: TLS - AddressOfCallBacks(%#8x) is not a pointer with basereloc.\n",
383 pTLSDir->AddressOfCallBacks));
384 pv = getPointerFromPointer(pTLSDir->AddressOfCallBacks);
385 if (pv == NULL)
386 {
387 eprintf(("Win32Pe2LxImage::init: invalid pointer to TLS AddressOfCallBacks - %#8x.\n",
388 pTLSDir->AddressOfIndex));
389 return FALSE;
390 }
391 setTLSCallBackAddr((PIMAGE_TLS_CALLBACK*)pv);
392 }
393 }
394 }
395 }
396 else
397 {
398 eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS Dir - %#8x. (getPointerFromRVA failed)\n",
399 pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress));
400 return FALSE;
401 }
402 }
403 return TRUE;
404}
405
406
407
408/**
409 * Gets the object layout for this module. Creates the paSections array.
410 * @returns OS2 errorcode. (NO_ERROR == success)
411 * @sketch Allocate output buffer.
412 * Call DosQuerySysState.
413 * IF buffer overflow THEN retry calling it with larger buffers, until buffer size is 1MB.
414 * IF success THEN
415 * BEGIN
416 * Find record for this module.
417 * IF record found THEN allocate memory for object table and copy it. (paSections, cSections)
418 * END
419 * @status Completely implemented.
420 * @author knut st. osmundsen
421 */
422ULONG Win32Pe2LxImage::getSections()
423{
424 APIRET rc = NO_ERROR;
425
426 /*
427 * If Win32k.sys is installed we'll use it.
428 */
429 if (libWin32kInstalled())
430 {
431 ULONG cbQte = sizeof(QOTEBUFFER) + sizeof(QOTE)*20;
432 PQOTEBUFFER pQOte = (PQOTEBUFFER)malloc(sizeof(QOTEBUFFER) + sizeof(QOTE)*20);
433 if (pQOte != NULL)
434 {
435 /*
436 * Get the query OTEs for this module.
437 * If there is a buffer overflow we'll allocate more storage and retry.
438 */
439 rc = W32kQueryOTEs(hmod, pQOte, cbQte);
440 while (rc == ERROR_BUFFER_OVERFLOW && cbQte < 32000);
441 {
442 PVOID pvOld = pQOte;
443 cbQte += sizeof(QOTE) * 20;
444 pQOte = (PQOTEBUFFER)realloc(pQOte, cbQte);
445 if (pQOte == NULL)
446 {
447 free(pvOld);
448 return ERROR_NOT_ENOUGH_MEMORY;
449 }
450
451 rc = W32kQueryOTEs(hmod, pQOte, cbQte);
452 }
453
454 /*
455 * If successfully got the OTEs then allocate and set paSections structs.
456 */
457 if (rc == NO_ERROR)
458 {
459 /* Allocate memory for paSections */
460 paSections = (PSECTION)malloc(pQOte->cOTEs * sizeof(SECTION));
461 if (paSections != NULL)
462 {
463 /* objects -> section array */
464 for (int i = 0; i < pQOte->cOTEs; i++)
465 {
466 paSections[i].ulRVA = ~0UL;
467 paSections[i].cbVirtual = pQOte->aOTE[i].ote_size;
468 paSections[i].ulAddress = pQOte->aOTE[i].ote_base;
469 }
470 cSections = pQOte->cOTEs;
471 }
472 else
473 rc = ERROR_NOT_ENOUGH_MEMORY;
474 }
475 else
476 {
477 dprintf(("Win32Pe2LxImage::getSections: libW32kQueryOTEs failed with rc=%d."
478 " Falls back on the DosQuerySysState method.\n", rc));
479 }
480 }
481 else
482 { /* server error, no use in trying the fallback method. */
483 dprintf(("Win32Pe2LxImage::getSections: malloc failed\n"));
484 return ERROR_NOT_ENOUGH_MEMORY;
485 }
486
487 if (rc == NO_ERROR)
488 return rc;
489 }
490
491
492 /*
493 * Fallback method, using DosQuerySysState.
494 */
495 qsPtrRec_t * pPtrRec;
496 ULONG cbBuf = 65536;
497
498 pPtrRec = (qsPtrRec_t *)malloc(cbBuf);
499 if (pPtrRec != NULL)
500 {
501 rc = DosQuerySysState(QS_MTE, QS_MTE, getpid(), 0L, pPtrRec, cbBuf);
502 while (cbBuf < 1024*1024 && rc == ERROR_BUFFER_OVERFLOW)
503 {
504 PVOID pv = pPtrRec;
505 cbBuf += 65536;
506 pPtrRec = (qsPtrRec_t *)realloc(pv, cbBuf);
507 if (pPtrRec != NULL)
508 rc = DosQuerySysState(QS_MTE, QS_MTE, getpid(), 0L, pPtrRec, cbBuf);
509 else
510 {
511 rc = ERROR_NOT_ENOUGH_MEMORY;
512 free(pv);
513 }
514 }
515
516 if (rc == NO_ERROR)
517 {
518 qsLrec_t * pLrec = pPtrRec->pLibRec;
519 while (pLrec != NULL)
520 {
521 /*
522 * Bug detected in OS/2 FP13. Probably a problem which occurs
523 * in _LDRSysMteInfo when qsCheckCache is calle before writing
524 * object info. The result is that the cache flushed and the
525 * attempt of updating the qsLrec_t next and object pointer is
526 * not done. This used to work earlier and on Aurora AFAIK.
527 *
528 * The fix for this problem is to check if the pObjInfo is NULL
529 * while the number of objects isn't 0 and correct this. pNextRec
530 * will also be NULL at this time. This will be have to corrected
531 * before we exit the loop or moves to the next record.
532 * There is also a nasty alignment of the object info... Hope
533 * I got it right. (This aligment seems new to FP13.)
534 */
535 if (pLrec->pObjInfo == NULL /*&& pLrec->pNextRec == NULL*/ && pLrec->ctObj > 0)
536 {
537 pLrec->pObjInfo = (qsLObjrec_t*)(
538 (char*)pLrec
539 + ((sizeof(qsLrec_t) /* size of the lib record */
540 + pLrec->ctImpMod * sizeof(short) /* size of the array of imported modules */
541 + strlen((char*)pLrec->pName) + 1 /* size of the filename */
542 + 3) & ~3)); /* the size is align on 4 bytes boundrary */
543 pLrec->pNextRec = (qsLrec_t*)((char*)pLrec->pObjInfo
544 + sizeof(qsLObjrec_t) * pLrec->ctObj);
545 }
546 if (pLrec->hmte == hmod)
547 break;
548
549 /*
550 * Next record
551 */
552 pLrec = (qsLrec_t*)pLrec->pNextRec;
553 }
554
555
556 if (pLrec)
557 {
558 if (pLrec->pObjInfo != NULL)
559 {
560 /* Allocate memory for paSections */
561 paSections = (PSECTION)malloc(pLrec->ctObj*sizeof(SECTION));
562 if (paSections != NULL)
563 {
564 /* objects -> section array */
565 for (int i = 0; i < pLrec->ctObj; i++)
566 {
567 paSections[i].ulRVA = ~0UL;
568 paSections[i].cbVirtual = pLrec->pObjInfo[i].osize;
569 paSections[i].ulAddress = pLrec->pObjInfo[i].oaddr;
570 }
571 cSections = pLrec->ctObj;
572 }
573 else
574 rc = ERROR_NOT_ENOUGH_MEMORY;
575 }
576 else
577 {
578 rc = ERROR_BAD_EXE_FORMAT;
579 dprintf(("Win32Pe2LxImage::getSections: Error - no object table!\n"));
580 }
581 }
582 else
583 rc = ERROR_MOD_NOT_FOUND;
584 }
585 else
586 dprintf(("DosQuerySysState - failed with rc=%d (cbBuf=%d)\n", rc, cbBuf));
587
588 if (pPtrRec != NULL)
589 free(pPtrRec);
590 }
591 else
592 rc = ERROR_NOT_ENOUGH_MEMORY;
593
594 return rc;
595}
596
597
598/**
599 * Sets the ulRVA according to the original PE section table.
600 * @returns OS/2 errorcode. (NO_ERROR == success)
601 * @sketch DEBUG: Validate pNtHdrs
602 * Make pointer to start of PE section table.
603 * Set RVA for the header section.
604 * IF not all in one object exe? THEN
605 * Loop thru the sections in the PE section table.
606 * Note: due to the header section: PE section no. + 1 == LX object no.
607 * ELSE
608 * BEGIN
609 * (try) Reallocate paSections to NumberOfSections + 3.
610 * Loop thru the PE sections and make paSections from them.
611 * Add final Stack or TIBFix+Stack section if necessary.
612 * Resize header section.
613 * END
614 * @status completely implemented.
615 * @author knut st. osmundsen
616 * @remark Must not be called before pNtHdrs is set.
617 */
618ULONG Win32Pe2LxImage::setSectionRVAs()
619{
620 #if DEBUG
621 if (pNtHdrs == NULL)
622 {
623 DebugInt3();
624 return ERROR_INVALID_PARAMETER;
625 }
626 #endif
627
628 PIMAGE_SECTION_HEADER paPESections = (PIMAGE_SECTION_HEADER)
629 ((unsigned)pNtHdrs + sizeof(*pNtHdrs) +
630 (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes - IMAGE_NUMBEROF_DIRECTORY_ENTRIES) * sizeof(IMAGE_DATA_DIRECTORY)
631 );
632
633 /* set RVA for the header section to 0UL. */
634 paSections[0].ulRVA = 0UL;
635
636 /* All in one object exe? */
637 if (pNtHdrs->FileHeader.NumberOfSections < cSections)
638 {
639 /* loop thru the other sections */
640 for (int i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++)
641 paSections[i+1].ulRVA = paPESections[i].VirtualAddress;
642 }
643 else
644 { /* all in one object */
645 /* (try) Reallocate paSections to NumberOfSections + 3. */
646 PVOID pv = realloc(paSections, sizeof(paSections[0]) * (pNtHdrs->FileHeader.NumberOfSections + 3));
647 if (pv != NULL)
648 {
649 paSections = (PSECTION)pv;
650
651 /* loop thru the PE sections */
652 for (int i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++)
653 {
654 if (paSections[0].cbVirtual < paPESections[i].VirtualAddress)
655 {
656 dprintf(("Win32Pe2LxImage::setSectionRVAs: mismatch between section table and all-in-one-object"
657 "paSections[0].cbVirtual %#x paPESections[i].VirtualAddress %#x\n",
658 paSections[0].cbVirtual, paPESections[i].VirtualAddress
659 ));
660 return ERROR_BAD_EXE_FORMAT;
661 }
662 paSections[i+1].ulRVA = paPESections[i].VirtualAddress;
663 paSections[i+1].cbVirtual = max(paPESections[i].Misc.VirtualSize, paPESections[i].SizeOfRawData);
664 paSections[i+1].ulAddress = paSections[0].ulAddress + paPESections[i].VirtualAddress;
665 }
666 cSections = pNtHdrs->FileHeader.NumberOfSections + 1;
667
668 /* add final Stack or TIBFix+Stack section if necessary */
669 if (paSections[0].cbVirtual > paSections[i].ulRVA + ALIGN(paSections[i].cbVirtual, 0x1000))
670 {
671 paSections[i+1].ulRVA = ~0UL;
672 paSections[i+1].cbVirtual = paSections[0].cbVirtual - paSections[i].ulRVA + ALIGN(paSections[i].cbVirtual, 0x1000);
673 paSections[i+1].ulAddress = paSections[i].ulAddress + ALIGN(paSections[i].cbVirtual, 0x1000);
674 i++;
675 cSections++;
676 }
677
678 /* resize header section */
679 paSections[0].cbVirtual = paSections[1].ulRVA; /*....*/
680 }
681 else
682 return ERROR_NOT_ENOUGH_MEMORY;
683 }
684
685 return NO_ERROR;
686}
687
688
689/**
690 * Frees memory used by this object.
691 * When an exception is to be thrown, this function is called first to clean up
692 * the object. Base class(es) are automatically clean up by theire destructor(s).
693 * @status completely implemented.
694 * @author knut st. osmundsen
695 */
696VOID Win32Pe2LxImage::cleanup()
697{
698 if (paSections != NULL)
699 {
700 free(paSections);
701 paSections = NULL;
702 cSections = 0;
703 }
704
705 if (fDll)
706 DosFreeModule(hmod);
707}
708
709
710/**
711 * Converts a RVA into a pointer.
712 * @returns Pointer matching the given RVA, NULL on error.
713 * @param ulRVA An address relative to the imagebase of the original PE image.
714 * If this is 0UL NULL is returned.
715 * @sketch DEBUG: validate state, paSections != NULL
716 * IF ulRVA is 0 THEN return NULL
717 * LOOP while more section left and ulRVA is not within section
718 * next section
719 * IF section matching ulRVA is not found THEN fail.
720 * return pointer matching RVA.
721 * @status completely implemented.
722 * @author knut st. osmundsen
723 * @remark Should not be called until getSections has returned successfully.
724 * RVA == 0 is ignored.
725 */
726PVOID Win32Pe2LxImage::getPointerFromRVA(ULONG ulRVA)
727{
728 int i;
729
730 #ifdef DEBUG
731 if (paSections == NULL)
732 {
733 eprintf(("Win32Pe2LxImage::getPointerFromRVA: paSections is NULL!\n"));
734 return NULL;
735 }
736 #endif
737
738 if (ulRVA == 0UL)
739 return NULL;
740
741 i = 0;
742 while (i < cSections &&
743 (paSections[i].ulRVA > ulRVA || paSections[i].ulRVA + paSections[i].cbVirtual <= ulRVA)) /* ALIGN on page too? */
744 i++;
745
746 if (i >= cSections)
747 return NULL;
748
749 return (PVOID)(ulRVA - paSections[i].ulRVA + paSections[i].ulAddress);
750}
751
752
753/**
754 * Converts a pointer with not basereloc to a pointer.
755 * @returns Pointer with baserelocation applied.
756 * @param pv Pointer without baserelocation.
757 * @status completely implemented.
758 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
759 */
760PVOID Win32Pe2LxImage::getPointerFromPointer(PVOID pv)
761{
762 if (pv == NULL)
763 return NULL;
764
765 return getPointerFromRVA((ULONG)pv - pNtHdrs->OptionalHeader.ImageBase);
766}
767
768
769/**
770 * Converts a RVA into a paSections index.
771 * @returns Index into paSections for the section containing the RVA.
772 * -1 on error.
773 * @param ulRVA An address relative to the imagebase of the original PE image.
774 * If this is 0UL -1 is returned.
775 * @sketch DEBUG: validate state, paSections != NULL
776 * IF ulRVA is 0 THEN return -1
777 * LOOP while more section left and ulRVA is not within section
778 * next section
779 * IF section matching ulRVA is found THEN return index ELSE fail.
780 * @status completely implemented.
781 * @author knut st. osmundsen
782 * @remark Should not be called until getSections has returned successfully.
783 * RVA == 0 is ignored.
784 */
785LONG Win32Pe2LxImage::getSectionIndexFromRVA(ULONG ulRVA)
786{
787 LONG i;
788
789 #ifdef DEBUG
790 if (paSections == NULL)
791 {
792 eprintf(("Win32Pe2LxImage::getSectionIndexFromRVA: paSections is NULL!\n"));
793 return NULL;
794 }
795 #endif
796
797 if (ulRVA == 0UL)
798 return -1;
799
800 i = 0;
801 while (i < cSections &&
802 (paSections[i].ulRVA > ulRVA && paSections[i].ulRVA + paSections[i].cbVirtual <= ulRVA)) /* ALIGN on page too? */
803 i++;
804
805 return i < cSections ? i : -1;
806}
807
808
809/**
810 * Validates that a given pointer is pointing to valid memory within
811 * the loaded executable image.
812 * @returns TRUE if the pointer is valid.
813 * FALSE if the pointer is invalid.
814 * @param pv Pointer to validate.
815 * @sketch
816 * @status completely implemented.
817 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
818 */
819BOOL Win32Pe2LxImage::validateRealPointer(PVOID pv)
820{
821 int i;
822
823 #ifdef DEBUG
824 if (paSections == NULL)
825 {
826 eprintf(("Win32Pe2LxImage::validateRealPointer: paSections is NULL!\n"));
827 return NULL;
828 }
829 #endif
830
831 if (pv == NULL)
832 return FALSE;
833
834 i = 0;
835 while (i < cSections &&
836 (paSections[i].ulAddress < (ULONG)pv ||
837 paSections[i].ulAddress + paSections[i].cbVirtual <= (ULONG)pv) /* Align on page too? */
838 )
839 i++;
840
841 return i < cSections;
842}
843
844
845/**
846 * Gets pointer to an exported procedure by procedure name.
847 * @returns Address of exported procedure. 0UL if not found.
848 * @param name Exported procedure name.
849 * @status completely implemented.
850 * @author Sander van Leeuwen
851 * @remark
852 */
853ULONG Win32Pe2LxImage::getApi(char *name)
854{
855 APIRET rc;
856 ULONG ulApiAddr;
857
858 rc = DosQueryProcAddr(hmod, 0, name, (PFN *)&ulApiAddr);
859 return rc == NO_ERROR ? ulApiAddr : 0;
860}
861
862
863/**
864 * Gets pointer to an exported procedure by ordinal.
865 * @returns Pointer to an exported procedure. 0UL if not found.
866 * @param ordinal Export ordinal number.
867 * @status completely implemented.
868 * @author Sander van Leeuwen
869 * @remark FIXME:
870 * This function should be implemented for both Exe and Dll images!
871 * It could be done similar in both peldr image and pe2lx images by
872 * accessing PE structures.
873 */
874ULONG Win32Pe2LxImage::getApi(int ordinal)
875{
876 APIRET rc;
877 ULONG ulApiAddr;
878
879 rc = DosQueryProcAddr(hmod, ordinal, NULL, (PFN *)&ulApiAddr);
880
881 return rc == NO_ERROR ? ulApiAddr : 0;
882}
Note: See TracBrowser for help on using the repository browser.