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

Last change on this file since 7945 was 7945, checked in by bird, 24 years ago

First try on the

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