source: trunk/src/kernel32/winimagepeldr.cpp@ 9537

Last change on this file since 9537 was 9537, checked in by sandervl, 23 years ago

Don't display message boxes for module load errors. Pass errors back to the PE loader.

File size: 78.6 KB
Line 
1/* $Id: winimagepeldr.cpp,v 1.102 2002-12-20 11:39:42 sandervl Exp $ */
2
3/*
4 * Win32 PE loader Image base class
5 *
6 * Copyright 1998-2000 Sander van Leeuwen (sandervl@xs4all.nl)
7 * Copyright 1998 Knut St. Osmundsen
8 *
9 * Project Odin Software License can be found in LICENSE.TXT
10 *
11 * TODO: Check psh[i].Characteristics for more than only the code section
12 * TODO: Make resource section readonly when GDI32 is fixed
13 * TODO: Loading of forwarder dlls before handling imports might not be correct
14 * (circular dependencies; have to check what NT does)
15 * TODO: Two LoadLibrary calls in two threads at the same time won't be handled properly (rare but possible)
16 *
17 * NOTE: FLAG_PELDR_LOADASDATAFILE is a special flag to only load the resource directory
18 * of a PE image. Processing imports, sections etc is not done.
19 * This is useful for GetVersionSize/Resource in case it wants to
20 * get version info of an image that is not loaded.
21 * So an instance of this type can't be used for anything but resource lookup!
22 *
23 * NOTE: File pointer operations relative to the start of the file must add
24 * ulPEOffset (in case PE image start != file start)
25 *
26 */
27#define INCL_DOSFILEMGR /* File Manager values */
28#define INCL_DOSMODULEMGR
29#define INCL_DOSERRORS /* DOS Error values */
30#define INCL_DOSPROCESS /* DOS Process values */
31#define INCL_DOSMISC /* DOS Miscellanous values */
32#define INCL_WIN
33#define INCL_BASE
34#include <os2wrap.h> //Odin32 OS/2 api wrappers
35
36#include <stdio.h>
37#include <string.h>
38#include <stdlib.h>
39
40#include <assert.h>
41//use a different logfile
42#define PRIVATE_LOGGING
43#include <misc.h>
44#include <win32api.h>
45#include <heapcode.h>
46#include "winimagebase.h"
47#include "winimagepeldr.h"
48#include "windllpeldr.h"
49#include "windlllx.h"
50#include "winexebase.h"
51#include <pefile.h>
52#include <unicode.h>
53#include "oslibmisc.h"
54#include "initterm.h"
55#include <win\virtual.h>
56#include "oslibdos.h"
57#include "oslibmem.h"
58#include "mmap.h"
59#include <wprocess.h>
60
61//Define COMMIT_ALL to let the pe loader commit all sections of the image
62//This is very useful during debugging as you'll get lots of exceptions
63//otherwise.
64//#ifdef DEBUG
65#define COMMIT_ALL
66//#endif
67
68char szErrorModule[260] = "";
69
70#ifdef DEBUG
71static FILE *_privateLogFile = NULL;
72#endif
73
74ULONG WIN32API MissingApiOrd(char *parentimage, char *dllname, int ordinal);
75ULONG WIN32API MissingApiName(char *parentimage, char *dllname, char *functionname);
76ULONG WIN32API MissingApi(char *message);
77
78//******************************************************************************
79//******************************************************************************
80void OpenPrivateLogFilePE()
81{
82#ifdef DEBUG
83 char logname[CCHMAXPATH];
84
85 sprintf(logname, "pe_%d.log", loadNr);
86 _privateLogFile = fopen(logname, "w");
87 if(_privateLogFile == NULL) {
88 sprintf(logname, "%spe_%d.log", kernel32Path, loadNr);
89 _privateLogFile = fopen(logname, "w");
90 }
91 dprintfGlobal(("PE LOGFILE : %s", logname));
92#endif
93}
94//******************************************************************************
95//******************************************************************************
96void ClosePrivateLogFilePE()
97{
98#ifdef DEBUG
99 if(_privateLogFile) {
100 fclose(_privateLogFile);
101 _privateLogFile = NULL;
102 }
103#endif
104}
105//******************************************************************************
106//******************************************************************************
107Win32PeLdrImage::Win32PeLdrImage(char *pszFileName, BOOL isExe) :
108 Win32ImageBase(-1),
109 nrsections(0), imageSize(0), dwFlags(0), section(NULL),
110 imageVirtBase(-1), realBaseAddress(0), imageVirtEnd(0),
111 nrNameExports(0), nrOrdExports(0), nameexports(NULL), ordexports(NULL),
112 memmap(NULL), pFixups(NULL), dwFixupSize(0), curnameexport(NULL), curordexport(NULL),
113 nrOrdExportsRegistered(0)
114{
115 HFILE dllfile;
116
117 fIsPEImage = TRUE;
118
119 strcpy(szFileName, pszFileName);
120 strupr(szFileName);
121 if(isExe) {
122 if(!strchr(szFileName, '.')) {
123 strcat(szFileName,".EXE");
124 }
125 dllfile = OSLibDosOpen(szFileName, OSLIB_ACCESS_READONLY|OSLIB_ACCESS_SHAREDENYNONE);
126 if(dllfile == NULL) {
127 if(!strstr(szFileName, ".EXE")) {
128 strcat(szFileName,".EXE");
129 }
130 dllfile = OSLibDosOpen(szFileName, OSLIB_ACCESS_READONLY|OSLIB_ACCESS_SHAREDENYNONE);
131 if(dllfile == NULL) {
132 OSLibDosSearchPath(OSLIB_SEARCHENV, "PATH", szFileName, szFileName, sizeof(szFileName));
133 }
134 }
135 else OSLibDosClose(dllfile);
136 }
137 else {
138 findDll(szFileName, szModule, sizeof(szModule));
139 strcpy(szFileName, szModule);
140 }
141 strcpy(szModule, OSLibStripPath(szFileName));
142 strupr(szModule);
143}
144//******************************************************************************
145//******************************************************************************
146Win32PeLdrImage::~Win32PeLdrImage()
147{
148 if(memmap)
149 delete memmap;
150
151 if(hFile) {
152 OSLibDosClose(hFile);
153 hFile = 0;
154 }
155
156 if(realBaseAddress)
157 OSLibDosFreeMem((PVOID)realBaseAddress);
158
159 if(nameexports)
160 free(nameexports);
161
162 if(ordexports)
163 free(ordexports);
164
165 if(section)
166 free(section);
167}
168//******************************************************************************
169//******************************************************************************
170DWORD Win32PeLdrImage::init(ULONG reservedMem, ULONG ulPEOffset)
171{
172 LPVOID win32file = NULL;
173 ULONG filesize, ulRead, ulNewPos;
174 PIMAGE_SECTION_HEADER psh;
175 IMAGE_SECTION_HEADER sh;
176 IMAGE_TLS_DIRECTORY *tlsDir = NULL;
177 int nSections, i;
178 char szFullPath[CCHMAXPATH] = "";
179 IMAGE_DOS_HEADER doshdr;
180 ULONG signature;
181 DWORD lasterror = LDRERROR_INTERNAL;
182
183 //offset in executable image where real PE file starts (default 0)
184 this->ulPEOffset = ulPEOffset;
185
186 hFile = OSLibDosOpen(szFileName, OSLIB_ACCESS_READONLY|OSLIB_ACCESS_SHAREDENYNONE);
187
188 dprintf((LOG, "KERNEL32-PELDR: Opening PE-image (%s) returned handle %08xh.\n",
189 szFileName,
190 hFile));
191
192 //change to PE image start if necessary
193 if(ulPEOffset) {
194 if(OSLibDosSetFilePtr(hFile, ulPEOffset, OSLIB_SETPTR_FILE_BEGIN) == -1) {
195 lasterror = LDRERROR_INVALID_MODULE;
196 goto failure;
197 }
198 }
199
200 //default error:
201 strcpy(szErrorModule, OSLibStripPath(szFileName));
202 if(hFile == NULL) {
203 lasterror = LDRERROR_INTERNAL;
204 goto failure;
205 }
206 //read dos header
207 if(DosRead(hFile, (LPVOID)&doshdr, sizeof(doshdr), &ulRead)) {
208 lasterror = LDRERROR_INVALID_MODULE;
209 goto failure;
210 }
211 if(OSLibDosSetFilePtr(hFile, ulPEOffset+doshdr.e_lfanew, OSLIB_SETPTR_FILE_BEGIN) == -1) {
212 lasterror = LDRERROR_INVALID_MODULE;
213 goto failure;
214 }
215 //read signature dword
216 if(DosRead(hFile, (LPVOID)&signature, sizeof(signature), &ulRead)) {
217 lasterror = LDRERROR_INVALID_MODULE;
218 goto failure;
219 }
220 //read pe header
221 if(DosRead(hFile, (LPVOID)&fh, sizeof(fh), &ulRead)) {
222 lasterror = LDRERROR_INVALID_MODULE;
223 goto failure;
224 }
225 //read optional header
226 if(DosRead(hFile, (LPVOID)&oh, sizeof(oh), &ulRead)) {
227 lasterror = LDRERROR_INVALID_MODULE;
228 goto failure;
229 }
230 if(doshdr.e_magic != IMAGE_DOS_SIGNATURE || signature != IMAGE_NT_SIGNATURE) {
231 dprintf((LOG, "Not a valid PE file (probably a 16 bits windows exe/dll)!"));
232 lasterror = LDRERROR_INVALID_MODULE;
233 goto failure;
234 }
235
236 if(oh.SizeOfImage == 0) {//just in case
237 oh.SizeOfImage = OSLibDosGetFileSize(hFile, NULL);
238 }
239
240 imageSize = oh.SizeOfImage;
241 //Allocate memory to hold the entire image
242 if(allocSections(reservedMem) == FALSE) {
243 dprintf((LOG, "Failed to allocate image memory for %s at %x, rc %d", szFileName, oh.ImageBase, errorState));;
244 lasterror = LDRERROR_MEMORY;
245 goto failure;
246 }
247
248 memmap = new Win32MemMap(this, realBaseAddress, imageSize);
249 if(memmap == NULL || !memmap->Init()) {
250 lasterror = LDRERROR_MEMORY;
251 goto failure;
252 }
253 win32file = memmap->mapViewOfFile(0, 0, 2);
254
255 if(DosQueryPathInfo(szFileName, FIL_QUERYFULLNAME, szFullPath, sizeof(szFullPath)) == 0) {
256 setFullPath(szFullPath);
257 }
258
259 if(!(fh.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)) {//not valid
260 dprintf((LOG, "Not a valid PE file!"));
261 lasterror = LDRERROR_INVALID_MODULE;
262 goto failure;
263 }
264 if(fh.Machine != IMAGE_FILE_MACHINE_I386) {
265 dprintf((LOG, "Doesn't run on x86 processors!"));
266 lasterror = LDRERROR_INVALID_CPU;
267 goto failure;
268 }
269 //IMAGE_FILE_SYSTEM == only drivers (device/file system/video etc)?
270 if(fh.Characteristics & IMAGE_FILE_SYSTEM) {
271 dprintf((LOG, "Can't convert system files"));
272 lasterror = LDRERROR_FILE_SYSTEM;
273 goto failure;
274 }
275
276 if(fh.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) {
277 dprintf((LOG, "No fixups, might not run!"));
278 }
279
280 dprintf((LOG, "PE file : %s", szFileName));
281 dprintf((LOG, "PE Optional header: "));
282 dprintf((LOG, "Preferred address : %d", oh.ImageBase ));
283 dprintf((LOG, "Base Of Code : %d", oh.BaseOfCode ));
284 dprintf((LOG, "CodeSize : %d", oh.SizeOfCode ));
285 dprintf((LOG, "Base Of Data : %d", oh.BaseOfData ));
286 dprintf((LOG, "Data Size (uninit): %d", oh.SizeOfUninitializedData ));
287 dprintf((LOG, "Data Size (init) : %d", oh.SizeOfInitializedData ));
288 dprintf((LOG, "Entry Point : %d", oh.AddressOfEntryPoint ));
289 dprintf((LOG, "Section Alignment : %d", oh.SectionAlignment ));
290 dprintf((LOG, "Stack Reserve size: %d", oh.SizeOfStackReserve ));
291 dprintf((LOG, "Stack Commit size : %d", oh.SizeOfStackCommit ));
292 dprintf((LOG, "SizeOfHeapReserve : %d", oh.SizeOfHeapReserve ));
293 dprintf((LOG, "SizeOfHeapCommit : %d", oh.SizeOfHeapCommit ));
294 dprintf((LOG, "FileAlignment : %d", oh.FileAlignment ));
295 dprintf((LOG, "Subsystem : %d", oh.Subsystem ));
296 dprintf((LOG, "Image Size : %d", oh.SizeOfImage ));
297 dprintf((LOG, "Header Size : %d", oh.SizeOfHeaders ));
298 dprintf((LOG, "MajorImageVersion : %d", oh.MajorImageVersion ));
299 dprintf((LOG, "MinorImageVersion : %d", oh.MinorImageVersion ));
300
301 //get header page
302 commitPage(realBaseAddress, FALSE);
303
304 nSections = NR_SECTIONS(win32file);
305 section = (Section *)malloc(nSections*sizeof(Section));
306 if(section == NULL) {
307 DebugInt3();
308 lasterror = LDRERROR_MEMORY;
309 goto failure;
310 }
311 memset(section, 0, nSections*sizeof(Section));
312
313 imageSize = 0;
314 if ((psh = (PIMAGE_SECTION_HEADER)SECTIONHDROFF (win32file)) != NULL)
315 {
316 dprintf((LOG, "*************************PE SECTIONS START**************************" ));
317 for (i=0; i<nSections; i++)
318 {
319 dprintf((LOG, "Section: %-8s", psh[i].Name ));
320 dprintf((LOG, "Raw data size: %x", psh[i].SizeOfRawData ));
321 dprintf((LOG, "Virtual Address: %x", psh[i].VirtualAddress ));
322 dprintf((LOG, "Virtual Address Start:%x", psh[i].VirtualAddress+oh.ImageBase ));
323 dprintf((LOG, "Virtual Address End: %x", psh[i].VirtualAddress+oh.ImageBase+psh[i].Misc.VirtualSize ));
324 dprintf((LOG, "Virtual Size: %x", psh[i].Misc.VirtualSize ));
325 dprintf((LOG, "Pointer to raw data: %x", psh[i].PointerToRawData ));
326 dprintf((LOG, "Section flags: %x\n\n", psh[i].Characteristics ));
327
328 if(IsSectionType(win32file, &psh[i], IMAGE_DIRECTORY_ENTRY_BASERELOC))
329 {
330 dprintf((LOG, ".reloc" ));
331 addSection(SECTION_RELOC, psh[i].PointerToRawData,
332 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
333 psh[i].Misc.VirtualSize, psh[i].Characteristics);
334 continue;
335 }
336 if(IsSectionType(win32file, &psh[i], IMAGE_DIRECTORY_ENTRY_EXPORT))
337 {
338 //SvL: Angus.exe has empty export section that's really an
339 // uninitialized data section
340 if(psh[i].SizeOfRawData) {
341 dprintf((LOG, ".edata" ));
342 addSection(SECTION_EXPORT, psh[i].PointerToRawData,
343 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
344 psh[i].Misc.VirtualSize, psh[i].Characteristics);
345 continue;
346 }
347 }
348 if(IsSectionType(win32file, &psh[i], IMAGE_DIRECTORY_ENTRY_RESOURCE))
349 {
350 dprintf((LOG, ".rsrc" ));
351 addSection(SECTION_RESOURCE, psh[i].PointerToRawData,
352 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
353 psh[i].Misc.VirtualSize, psh[i].Characteristics);
354 continue;
355 }
356 if(IsSectionType(win32file, &psh[i], IMAGE_DIRECTORY_ENTRY_TLS))
357 {
358 dprintf((LOG, "TLS section"));
359 tlsDir = (IMAGE_TLS_DIRECTORY *)ImageDirectoryOffset(win32file, IMAGE_DIRECTORY_ENTRY_TLS);
360 if(tlsDir) {
361 addSection(SECTION_TLS, psh[i].PointerToRawData,
362 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
363 psh[i].Misc.VirtualSize, psh[i].Characteristics);
364 }
365 continue;
366 }
367 if(IsSectionType(win32file, &psh[i], IMAGE_DIRECTORY_ENTRY_DEBUG))
368 {
369 dprintf((LOG, ".rdebug" ));
370 addSection(SECTION_DEBUG, psh[i].PointerToRawData,
371 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
372 psh[i].Misc.VirtualSize, psh[i].Characteristics);
373 continue;
374 }
375 if(IsSectionType(win32file, &psh[i], IMAGE_DIRECTORY_ENTRY_IMPORT))
376 {
377 int type = SECTION_IMPORT;
378 dprintf((LOG, "Import Data Section" ));
379 if(psh[i].Characteristics & IMAGE_SCN_CNT_CODE) {
380 dprintf((LOG, "Also Code Section"));
381 type |= SECTION_CODE;
382 }
383 addSection(type, psh[i].PointerToRawData,
384 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
385 psh[i].Misc.VirtualSize, psh[i].Characteristics);
386 continue;
387 }
388 //KSO Sun 1998-08-09: Borland does not alway set the CODE flag for its "CODE" section
389 if(psh[i].Characteristics & IMAGE_SCN_CNT_CODE ||
390 (psh[i].Characteristics & IMAGE_SCN_MEM_EXECUTE &&
391 !(psh[i].Characteristics & (IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_CNT_INITIALIZED_DATA))) //KSO: make sure its not marked as a datasection
392 )
393 {
394 dprintf((LOG, "Code Section"));
395 addSection(SECTION_CODE, psh[i].PointerToRawData,
396 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
397 psh[i].Misc.VirtualSize, psh[i].Characteristics);
398 continue;
399 }
400 if(!(psh[i].Characteristics & IMAGE_SCN_MEM_WRITE)) { //read only data section
401 dprintf((LOG, "Read Only Data Section" ));
402 addSection(SECTION_READONLYDATA, psh[i].PointerToRawData,
403 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
404 psh[i].Misc.VirtualSize, psh[i].Characteristics);
405 continue;
406 }
407 if(psh[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
408 dprintf((LOG, "Uninitialized Data Section" ));
409 addSection(SECTION_UNINITDATA, psh[i].PointerToRawData,
410 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
411 psh[i].Misc.VirtualSize, psh[i].Characteristics);
412 continue;
413 }
414 if(psh[i].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) {
415 dprintf((LOG, "Initialized Data Section" ));
416 addSection(SECTION_INITDATA, psh[i].PointerToRawData,
417 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
418 psh[i].Misc.VirtualSize, psh[i].Characteristics);
419 continue;
420 }
421 if(psh[i].Characteristics & (IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ)) {
422 dprintf((LOG, "Other Section, stored as read/write uninit data" ));
423 addSection(SECTION_UNINITDATA, psh[i].PointerToRawData,
424 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
425 psh[i].Misc.VirtualSize, psh[i].Characteristics);
426 continue;
427 }
428 dprintf((LOG, "Unknown section" ));
429 lasterror = LDRERROR_INVALID_SECTION;
430 goto failure;
431 }
432 }
433 dprintf((LOG, "*************************PE SECTIONS END **************************" ));
434
435 imageSize += imageVirtBase - oh.ImageBase;
436 dprintf((LOG, "Total size of Image %x", imageSize ));
437 dprintf((LOG, "imageVirtBase %x", imageVirtBase ));
438 dprintf((LOG, "imageVirtEnd %x", imageVirtEnd ));
439
440 //In case there are any gaps between sections, adjust size
441 if(imageSize != imageVirtEnd - oh.ImageBase)
442 {
443 dprintf((LOG, "imageSize != imageVirtEnd - oh.ImageBase!" ));
444 imageSize = imageVirtEnd - oh.ImageBase;
445 }
446 if(imageSize < oh.SizeOfImage) {
447 imageSize = oh.SizeOfImage;
448 }
449
450 dprintf((LOG, "OS/2 base address %x", realBaseAddress ));
451 if(oh.AddressOfEntryPoint) {
452 entryPoint = realBaseAddress + oh.AddressOfEntryPoint;
453 }
454 else {
455 dprintf((LOG, "EntryPoint == NULL" ));
456 entryPoint = NULL;
457 }
458
459 //set memory protection flags
460 if(setMemFlags() == FALSE) {
461 dprintf((LOG, "Failed to set memory protection" ));
462 lasterror = LDRERROR_MEMORY;
463 }
464
465 if(realBaseAddress != oh.ImageBase && !(dwFlags & FLAG_PELDR_LOADASDATAFILE)) {
466 pFixups = (PIMAGE_BASE_RELOCATION)ImageDirectoryOffset(win32file, IMAGE_DIRECTORY_ENTRY_BASERELOC);
467 dwFixupSize = ImageDirectorySize(win32file, IMAGE_DIRECTORY_ENTRY_BASERELOC);
468 commitPage((ULONG)pFixups, FALSE);
469 }
470
471 if(!(dwFlags & FLAG_PELDR_LOADASDATAFILE))
472 {
473 if(tlsDir = (IMAGE_TLS_DIRECTORY *)ImageDirectoryOffset(win32file, IMAGE_DIRECTORY_ENTRY_TLS))
474 {
475 Section *sect;
476 BOOL fTLSFixups = FALSE;
477
478 sect = findSectionByAddr(tlsDir->StartAddressOfRawData);
479 //There might be fixups for the TLS structure, so search the sections
480 //by the OS/2 virtual address too
481 if(sect == NULL) {
482 sect = findSectionByOS2Addr(tlsDir->StartAddressOfRawData);
483 fTLSFixups = TRUE;
484 }
485
486 dprintf((LOG, "TLS Directory" ));
487 dprintf((LOG, "TLS Address of Index %x", tlsDir->AddressOfIndex ));
488 dprintf((LOG, "TLS Address of Callbacks %x", tlsDir->AddressOfCallBacks ));
489 dprintf((LOG, "TLS SizeOfZeroFill %x", tlsDir->SizeOfZeroFill ));
490 dprintf((LOG, "TLS Characteristics %x", tlsDir->Characteristics ));
491 if(sect == NULL) {
492 dprintf((LOG, "Couldn't find TLS section!!" ));
493 lasterror = LDRERROR_INVALID_HEADER;
494 goto failure;
495 }
496 setTLSAddress((char *)sect->realvirtaddr);
497 setTLSInitSize(tlsDir->EndAddressOfRawData - tlsDir->StartAddressOfRawData);
498 setTLSTotalSize(tlsDir->EndAddressOfRawData - tlsDir->StartAddressOfRawData + tlsDir->SizeOfZeroFill);
499
500 fTLSFixups = FALSE;
501 sect = findSectionByAddr((ULONG)tlsDir->AddressOfIndex);
502 //There might be fixups for the TLS structure, so search the sections
503 //by the OS/2 virtual address too
504 if(sect == NULL) {
505 sect = findSectionByOS2Addr((ULONG)tlsDir->AddressOfIndex);
506 fTLSFixups = TRUE;
507 }
508 if(sect == NULL) {
509 dprintf((LOG, "Couldn't find TLS AddressOfIndex section!!" ));
510 lasterror = LDRERROR_INVALID_HEADER;
511 goto failure;
512 }
513 if(fTLSFixups) {
514 setTLSIndexAddr((LPDWORD)tlsDir->AddressOfIndex); //no fixup required
515 }
516 else {//need to add a manual fixup
517 setTLSIndexAddr((LPDWORD)(sect->realvirtaddr + ((ULONG)tlsDir->AddressOfIndex - sect->virtaddr)));
518 }
519
520 if((ULONG)tlsDir->AddressOfCallBacks != 0)
521 {
522 fTLSFixups = FALSE;
523
524 sect = findSectionByAddr((ULONG)tlsDir->AddressOfCallBacks);
525 //There might be fixups for the TLS structure, so search the sections
526 //by the OS/2 virtual address too
527 if(sect == NULL) {
528 sect = findSectionByOS2Addr((ULONG)tlsDir->AddressOfIndex);
529 fTLSFixups = TRUE;
530 }
531 if(sect == NULL) {
532 dprintf((LOG, "Couldn't find TLS AddressOfCallBacks section!!" ));
533 lasterror = LDRERROR_INVALID_HEADER;
534 goto failure;
535 }
536 if(fTLSFixups) {
537 setTLSCallBackAddr((PIMAGE_TLS_CALLBACK *)tlsDir->AddressOfCallBacks); //no fixup required
538 }
539 else {//need to add a manual fixup
540 setTLSCallBackAddr((PIMAGE_TLS_CALLBACK *)(sect->realvirtaddr + ((ULONG)tlsDir->AddressOfCallBacks - sect->virtaddr)));
541 }
542 //modify tls callback pointers for new image base address
543 int i = 0;
544 while(tlsCallBackAddr[i])
545 {
546 fTLSFixups = FALSE;
547
548 sect = findSectionByAddr((ULONG)tlsCallBackAddr[i]);
549 //There might be fixups for the TLS structure, so search the sections
550 //by the OS/2 virtual address too
551 if(sect == NULL) {
552 sect = findSectionByOS2Addr((ULONG)tlsCallBackAddr[i]);
553 fTLSFixups = TRUE;
554 }
555 if(sect == NULL) {
556 dprintf((LOG, "Couldn't find TLS callback section!!" ));
557 lasterror = LDRERROR_INVALID_HEADER;
558 goto failure;
559 }
560 if(fTLSFixups) {
561 tlsCallBackAddr[i] = tlsCallBackAddr[i];
562 }
563 else tlsCallBackAddr[i] = (PIMAGE_TLS_CALLBACK)(realBaseAddress + ((ULONG)tlsCallBackAddr[i] - oh.ImageBase));
564 i++;
565 }
566 }
567 }
568
569#ifdef DEBUG
570 dprintf((LOG, "Image directories: "));
571 for (i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++)
572 {
573 char *pszName;
574
575 if(oh.DataDirectory[i].VirtualAddress && oh.DataDirectory[i].Size) {
576 switch (i)
577 {
578 case IMAGE_DIRECTORY_ENTRY_EXPORT: pszName = "Export Directory (IMAGE_DIRECTORY_ENTRY_EXPORT)"; break;
579 case IMAGE_DIRECTORY_ENTRY_IMPORT: pszName = "Import Directory (IMAGE_DIRECTORY_ENTRY_IMPORT)"; break;
580 case IMAGE_DIRECTORY_ENTRY_RESOURCE: pszName = "Resource Directory (IMAGE_DIRECTORY_ENTRY_RESOURCE)"; break;
581 case IMAGE_DIRECTORY_ENTRY_EXCEPTION: pszName = "Exception Directory (IMAGE_DIRECTORY_ENTRY_EXCEPTION)"; break;
582 case IMAGE_DIRECTORY_ENTRY_SECURITY: pszName = "Security Directory (IMAGE_DIRECTORY_ENTRY_SECURITY)"; break;
583 case IMAGE_DIRECTORY_ENTRY_BASERELOC: pszName = "Base Relocation Table (IMAGE_DIRECTORY_ENTRY_BASERELOC)"; break;
584 case IMAGE_DIRECTORY_ENTRY_DEBUG: pszName = "Debug Directory (IMAGE_DIRECTORY_ENTRY_DEBUG)"; break;
585 case IMAGE_DIRECTORY_ENTRY_COPYRIGHT: pszName = "Description String (IMAGE_DIRECTORY_ENTRY_COPYRIGHT)"; break;
586 case IMAGE_DIRECTORY_ENTRY_GLOBALPTR: pszName = "Machine Value (MIPS GP) (IMAGE_DIRECTORY_ENTRY_GLOBALPTR)"; break;
587 case IMAGE_DIRECTORY_ENTRY_TLS: pszName = "TLS Directory (IMAGE_DIRECTORY_ENTRY_TLS)"; break;
588 case IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG: pszName = "Load Configuration Directory (IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG)"; break;
589 case IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT:pszName = "Bound Import Directory in headers (IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT)"; break;
590 case IMAGE_DIRECTORY_ENTRY_IAT: pszName = "Import Address Table (IMAGE_DIRECTORY_ENTRY_IAT)"; break;
591 default:
592 pszName = "unknown";
593 }
594 dprintf((LOG, "directory %s", pszName));
595 dprintf((LOG, " Address 0x%08x", oh.DataDirectory[i].VirtualAddress));
596 dprintf((LOG, " Size 0x%08x", oh.DataDirectory[i].Size));
597 }
598 }
599 dprintf((LOG, "\n\n"));
600#endif
601
602#ifdef COMMIT_ALL
603 for (i=0; i<nSections; i++) {
604 commitPage((ULONG)section[i].realvirtaddr, FALSE, COMPLETE_SECTION);
605 }
606#else
607 for (i=0; i<nSections; i++) {
608 switch(section[i].type)
609 {
610 case SECTION_IMPORT:
611 case SECTION_RELOC:
612 case SECTION_EXPORT:
613 commitPage((ULONG)section[i].realvirtaddr, FALSE, COMPLETE_SECTION);
614 break;
615 }
616 }
617#endif
618 if(processExports((char *)win32file) == FALSE) {
619 dprintf((LOG, "Failed to process exported apis" ));
620 lasterror = LDRERROR_EXPORTS;
621 goto failure;
622 }
623 }
624
625#ifndef COMMIT_ALL
626 if(entryPoint) {
627 //commit code at entrypoint, since we going to call it anyway
628 commitPage((ULONG)entryPoint, FALSE);
629 }
630#endif
631
632 //SvL: Use pointer to image header as module handle now. Some apps needs this
633 hinstance = (HINSTANCE)realBaseAddress;
634
635 //SvL: Set instance handle in process database structure
636 SetPDBInstance(hinstance);
637
638 //PH: get pResRootDir pointer correct first, since processImports may
639 // implicitly call functions depending on it.
640 if(oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress && oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size)
641 {
642 //get offset in resource object of directory entry
643 pResRootDir = (PIMAGE_RESOURCE_DIRECTORY)(oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress + realBaseAddress);
644 ulRVAResourceSection = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
645 }
646
647 //Allocate TLS index for this module
648 //Must do this before dlls are loaded for this module. Some apps assume
649 //they get TLS index 0 for their main executable
650 {
651 USHORT sel = SetWin32TIB(TIB_SWITCH_FORCE_WIN32);
652 tlsAlloc();
653 tlsAttachThread(); //setup TLS (main thread)
654 SetFS(sel);
655 }
656
657 if(!(dwFlags & (FLAG_PELDR_LOADASDATAFILE | FLAG_PELDR_SKIPIMPORTS)))
658 {
659 if(processImports((char *)win32file) == FALSE) {
660 dprintf((LOG, "Failed to process imports!" ));
661 lasterror = LDRERROR_IMPORTS;
662 goto failure;
663 }
664 }
665 return LDRERROR_SUCCESS;
666
667failure:
668 if(memmap) {
669 delete memmap;
670 memmap = NULL;
671 }
672 if(hFile) {
673 OSLibDosClose(hFile);
674 hFile = 0;
675 }
676 errorState = ERROR_INTERNAL;
677 return lasterror;
678}
679//******************************************************************************
680//******************************************************************************
681#define DOSREAD_IDEAL_SIZE 61440
682static inline APIRET _Optlink fastDosRead(HFILE hFile,
683 PVOID pAddress,
684 ULONG ulSize,
685 PULONG pulBytesRead)
686{
687 /* we better break the DosRead into multiple calls */
688 PBYTE p = (PBYTE)pAddress;
689 ULONG ulReadBytes;
690 APIRET rc;
691
692 *pulBytesRead = ulSize;
693
694 do
695 {
696 rc = DosRead(hFile,
697 p,
698 min(DOSREAD_IDEAL_SIZE, ulSize),
699 &ulReadBytes);
700 if (rc != NO_ERROR)
701 {
702 /* in case of errors bail out */
703 *pulBytesRead = 0;
704 return rc;
705 }
706
707 // PH 2001-11-15
708 // For corrupt or misinterpreted PE headers,
709 // the preceeding DosSetFilePtr may have moved the
710 // file pointer at or behind the file's end.
711 // DosRead will then return rc=0 and ulReadBytes=0.
712 // This must NOT lead to an infinite loop.
713 if (ulReadBytes == 0)
714 {
715 return ERROR_INTERNAL;
716 }
717
718 ulSize -= ulReadBytes;
719 p += ulReadBytes;
720 }
721 while (ulSize > 0);
722
723 return NO_ERROR;
724}
725
726//******************************************************************************
727// commitPage:
728// commits image page(s) when an access violation exception is received
729// (usually called from exception.cpp; also from other methods in this file)
730//
731// Parameters:
732// virtAddress - address of exception (rounded down to page boundary)
733// fWriteAccess - type of access violation (read or write)
734// fPageCmd - SINGLE_PAGE -> commit single page
735// SECTION_PAGES -> commit default nr of pages
736// COMPLETE_SECTION -> commit entire section
737//
738// Remarks:
739// DosEnterCritSec/DosExitCritSec is used to make sure the other threads in
740// the application can't touch the pages before they are loaded from disk and
741// fixups are applied.
742//
743// TODO:
744// SECTION_PAGES: - don't load pages starting at access violation address, but
745// a region surrounding it (e.g. -32k -> + 32k)
746// this will prevent many pagefaults when the app uses
747// pages with a lower addr.
748//
749//******************************************************************************
750BOOL Win32PeLdrImage::commitPage(ULONG virtAddress, BOOL fWriteAccess, int fPageCmd)
751{
752 Section *section;
753 ULONG offset, size, sectionsize, protflags, fileoffset, range, attr;
754 ULONG ulNewPos, ulRead, orgVirtAddress = virtAddress;
755 APIRET rc;
756 BOOL fCriticalSection = FALSE;
757
758 dprintf((LOG, "Win32PeLdrImage::commitPage %x %d %d", virtAddress, fWriteAccess, fPageCmd));
759 if(virtAddress == 0) {
760 return FALSE;
761 }
762
763 //Round down to nearest page boundary
764 virtAddress = virtAddress & ~0xFFF;
765
766 section = findSectionByOS2Addr(virtAddress);
767 if(section == NULL) {
768 section = findSectionByOS2Addr(orgVirtAddress);
769 if(section) {
770 virtAddress = orgVirtAddress;
771 }
772 }
773 if(section == NULL) {
774 size = 4096;
775 sectionsize = 4096;
776 //Header page must be readonly (same as in NT)
777 protflags = PAG_READ;
778 section = findPreviousSectionByOS2Addr(virtAddress);
779 if(section == NULL) {//access to header
780 offset = 0;
781 fileoffset = virtAddress - realBaseAddress;
782 }
783 else {
784 offset = virtAddress - (section->realvirtaddr + section->virtualsize);
785 fileoffset = section->rawoffset + section->rawsize + offset;
786 }
787 }
788 else {
789 protflags = section->pageflags;
790 offset = virtAddress - section->realvirtaddr;
791 sectionsize = section->virtualsize - offset;
792
793 if(offset > section->rawsize || section->type == SECTION_UNINITDATA) {
794 //unintialized data (set to 0)
795 size = 0;
796 fileoffset = -1;
797 }
798 else {
799 size = section->rawsize-offset;
800 fileoffset = section->rawoffset + offset;
801 }
802 if(fWriteAccess & !(section->pageflags & PAG_WRITE)) {
803 dprintf((LOG, "Win32PeLdrImage::commitPage: No write access to 0%x!", virtAddress));
804 return FALSE;
805 }
806 }
807 if(fPageCmd == COMPLETE_SECTION && (section && section->type == SECTION_DEBUG)) {//ignore
808 return TRUE;
809 }
810 rc = DosEnterCritSec();
811 if(rc) {
812 dprintf((LOG, "DosEnterCritSec failed with rc %d", rc));
813 goto fail;
814 }
815 //tell fail handler to call DosExitCritSec
816 fCriticalSection = TRUE;
817
818 //Check range of pages with the same attributes starting at virtAddress
819 //(some pages might already have been loaded)
820 range = sectionsize;
821 rc = DosQueryMem((PVOID)virtAddress, &range, &attr);
822 if(rc) {
823 dprintf((LOG, "Win32PeLdrImage::commitPage: DosQueryMem for %x returned %d", virtAddress, rc));
824 goto fail;
825 }
826 if(attr & PAG_COMMIT) {
827 dprintf((LOG, "Win32PeLdrImage::commitPage: Memory at 0x%x already committed!", virtAddress));
828 goto fail;
829 }
830
831 if(fPageCmd == SINGLE_PAGE) {
832 size = min(size, PAGE_SIZE);
833 sectionsize = min(sectionsize, PAGE_SIZE);
834 }
835 else
836 if(fPageCmd == SECTION_PAGES) {
837 size = min(size, DEFAULT_NR_PAGES*PAGE_SIZE);
838 sectionsize = min(sectionsize, DEFAULT_NR_PAGES*PAGE_SIZE);
839 }
840 //else complete section
841
842 size = min(size, range);
843 sectionsize = min(sectionsize, range);
844
845 if(size && fileoffset != -1) {
846 rc = DosSetMem((PVOID)virtAddress, sectionsize, PAG_READ|PAG_WRITE|PAG_COMMIT);
847 if(rc) {
848 dprintf((LOG, "Win32PeLdrImage::commitPage: DosSetMem failed (%d)!", rc));
849 goto fail;
850 }
851
852 if(DosSetFilePtr(hFile, ulPEOffset+fileoffset, FILE_BEGIN, &ulNewPos) == -1) {
853 dprintf((LOG, "Win32PeLdrImage::commitPage: DosSetFilePtr failed for 0x%x!", fileoffset));
854 goto fail;
855 }
856#if 1
857 // 2001-05-31 PH
858 // ensure DosRead() does not have to read more
859 // than 65535 bytes, otherwise split into two requests!
860 rc = fastDosRead(hFile, (PVOID)virtAddress, size, &ulRead);
861#else
862 rc = DosRead(hFile, (PVOID)virtAddress, size, &ulRead);
863#endif
864 if(rc) {
865 dprintf((LOG, "Win32PeLdrImage::commitPage: DosRead failed for 0x%x %x %x %x (rc=%d)!", virtAddress, size, ulRead, fileoffset, rc));
866 goto fail;
867 }
868 if(ulRead != size) {
869 dprintf((LOG, "Win32PeLdrImage::commitPage: DosRead failed to read %x (%x) bytes at %x for 0x%x!", size, ulRead, fileoffset, virtAddress));
870 goto fail;
871 }
872 setFixups(virtAddress, sectionsize);
873
874 rc = DosSetMem((PVOID)virtAddress, sectionsize, protflags);
875 if(rc) {
876 dprintf((LOG, "Win32PeLdrImage::commitPage: DosSetMem failed (%d)!", rc));
877 goto fail;
878 }
879 }
880 else {
881 rc = DosSetMem((PVOID)virtAddress, sectionsize, PAG_READ|PAG_WRITE|PAG_COMMIT);
882 if(rc) {
883 dprintf((LOG, "Win32PeLdrImage::commitPage: DosSetMem failed (%d)!", rc));
884 goto fail;
885 }
886 setFixups(virtAddress, sectionsize);
887
888 rc = DosSetMem((PVOID)virtAddress, sectionsize, protflags);
889 if(rc) {
890 dprintf((LOG, "Win32PeLdrImage::commitPage: DosSetMem failed (%d)!", rc));
891 goto fail;
892 }
893 }
894 DosExitCritSec();
895 return TRUE;
896
897fail:
898 if(fCriticalSection) DosExitCritSec();
899 return FALSE;
900}
901//******************************************************************************
902//******************************************************************************
903void Win32PeLdrImage::addSection(ULONG type, ULONG rawoffset, ULONG rawsize, ULONG virtaddress, ULONG virtsize, ULONG flags)
904{
905 virtsize = max(rawsize, virtsize);
906
907 section[nrsections].rawoffset = rawoffset;
908 section[nrsections].type = type;
909 section[nrsections].rawsize = rawsize;
910 section[nrsections].virtaddr = virtaddress;
911 section[nrsections].flags = flags;
912
913 virtsize = ((virtsize - 1) & ~0xFFF) + PAGE_SIZE;
914 imageSize += virtsize;
915 section[nrsections].virtualsize = virtsize;
916
917 if(virtaddress < imageVirtBase)
918 imageVirtBase = virtaddress;
919 if(virtaddress + virtsize > imageVirtEnd)
920 imageVirtEnd = virtaddress + virtsize;
921
922 nrsections++;
923}
924//******************************************************************************
925//******************************************************************************
926BOOL Win32PeLdrImage::allocSections(ULONG reservedMem)
927{
928 APIRET rc;
929 ULONG baseAddress;
930
931 realBaseAddress = 0;
932
933 //Allocated in by pe.exe
934 if(reservedMem && reservedMem == oh.ImageBase) {
935 realBaseAddress = oh.ImageBase;
936 return TRUE;
937 }
938
939 //SvL: We don't care where the image is loaded for resource lookup
940 if(fh.Characteristics & IMAGE_FILE_RELOCS_STRIPPED && !(dwFlags & FLAG_PELDR_LOADASDATAFILE)) {
941 return allocFixedMem(reservedMem);
942 }
943 rc = OSLibDosAllocMem((PPVOID)&baseAddress, imageSize, PAG_READ | PAG_WRITE);
944 if(rc) {
945 dprintf((LOG, "Win32PeLdrImage::allocSections, DosAllocMem returned %d", rc));
946 errorState = rc;
947 return(FALSE);
948 }
949 realBaseAddress = baseAddress;
950 return(TRUE);
951}
952//******************************************************************************
953//******************************************************************************
954Section *Win32PeLdrImage::findSection(ULONG type)
955{
956 for(int i=0;i<nrsections;i++) {
957 if(section[i].type == type) {
958 return &section[i];
959 }
960 }
961 return NULL;
962}
963//******************************************************************************
964//******************************************************************************
965Section *Win32PeLdrImage::findSectionByAddr(ULONG addr)
966{
967 for(int i=0;i<nrsections;i++) {
968 if(section[i].virtaddr <= addr && section[i].virtaddr + section[i].virtualsize > addr) {
969 return &section[i];
970 }
971 }
972 return NULL;
973}
974//******************************************************************************
975//******************************************************************************
976Section *Win32PeLdrImage::findSectionByOS2Addr(ULONG addr)
977{
978 for(int i=0;i<nrsections;i++) {
979 if(section[i].realvirtaddr <= addr && section[i].realvirtaddr + section[i].virtualsize > addr) {
980 return &section[i];
981 }
982 }
983 return NULL;
984}
985//******************************************************************************
986//******************************************************************************
987Section *Win32PeLdrImage::findPreviousSectionByOS2Addr(ULONG addr)
988{
989 ULONG lowestAddr = 0xffffffff;
990 LONG index = -1;
991
992 for(int i=0;i<nrsections;i++) {
993 if(section[i].realvirtaddr <= addr) {
994 if(section[i].realvirtaddr < lowestAddr) {
995 lowestAddr = section[i].realvirtaddr;
996 index = i;
997 }
998 }
999 }
1000 if(index == -1)
1001 return NULL;
1002
1003 return &section[index];
1004}
1005//******************************************************************************
1006#define FALLOC_SIZE (1024*1024)
1007//NOTE: Needs testing (while loop)
1008//TODO: Free unused (parts of) reservedMem
1009//******************************************************************************
1010BOOL Win32PeLdrImage::allocFixedMem(ULONG reservedMem)
1011{
1012 ULONG address = 0;
1013 ULONG *memallocs;
1014 ULONG alloccnt = 0;
1015 ULONG diff, i, baseAddress;
1016 APIRET rc;
1017 BOOL fLowMemory = FALSE;
1018
1019 //Reserve enough space to store 4096 pointers to 1MB memory chunks
1020 memallocs = (ULONG *)malloc(4096*sizeof(ULONG *));
1021 if(memallocs == NULL) {
1022 dprintf((LOG, "allocFixedMem: MALLOC FAILED for memallocs" ));
1023 return FALSE;
1024 }
1025
1026 if(oh.ImageBase < 512*1024*1024) {
1027 fLowMemory = TRUE;
1028 }
1029 while(TRUE) {
1030 rc = OSLibDosAllocMem((PPVOID)&address, FALLOC_SIZE, PAG_READ, fLowMemory);
1031 if(rc) break;
1032
1033 dprintf((LOG, "DosAllocMem returned %x", address ));
1034 if(address + FALLOC_SIZE >= oh.ImageBase) {
1035 if(address > oh.ImageBase) {//we've passed it!
1036 OSLibDosFreeMem((PVOID)address);
1037 break;
1038 }
1039 //found the right address
1040 OSLibDosFreeMem((PVOID)address);
1041
1042 diff = oh.ImageBase - address;
1043 if(diff) {
1044 rc = OSLibDosAllocMem((PPVOID)&address, diff, PAG_READ, fLowMemory);
1045 if(rc) break;
1046 }
1047 rc = OSLibDosAllocMem((PPVOID)&baseAddress, imageSize, PAG_READ | PAG_WRITE, fLowMemory);
1048 if(rc) break;
1049
1050 if(diff) OSLibDosFreeMem((PVOID)address);
1051
1052 realBaseAddress = baseAddress;
1053 break;
1054 }
1055 memallocs[alloccnt++] = address;
1056 }
1057 for(i=0;i<alloccnt;i++) {
1058 OSLibDosFreeMem((PVOID)memallocs[i]);
1059 }
1060 free(memallocs);
1061
1062 if(realBaseAddress == 0) //Let me guess.. MS Office app?
1063 return(FALSE);
1064
1065 return(TRUE);
1066}
1067//******************************************************************************
1068//******************************************************************************
1069BOOL Win32PeLdrImage::setMemFlags()
1070{
1071 int i;
1072
1073 // Process all the image sections
1074 for(i=0;i<nrsections;i++) {
1075 section[i].realvirtaddr = realBaseAddress + (section[i].virtaddr - oh.ImageBase);
1076 }
1077
1078 for(i=0;i<nrsections;i++) {
1079 switch(section[i].type)
1080 {
1081 case SECTION_CODE:
1082 case (SECTION_CODE | SECTION_IMPORT):
1083 section[i].pageflags = PAG_EXECUTE | PAG_READ;
1084 if(section[i].flags & IMAGE_SCN_MEM_WRITE)
1085 section[i].pageflags |= PAG_WRITE;
1086 break;
1087 case SECTION_INITDATA:
1088 case SECTION_UNINITDATA:
1089 case SECTION_IMPORT:
1090 case SECTION_TLS:
1091 section[i].pageflags = PAG_WRITE | PAG_READ;
1092 break;
1093
1094 case SECTION_RESOURCE:
1095 //TODO: GDI32 changes some bitmap structures to avoid problems in Open32
1096 // -> causes crashes if resource section is readonly
1097 // -> make it readonly again when gdi32 has been rewritten
1098 section[i].pageflags = PAG_WRITE | PAG_READ;
1099 break;
1100
1101 case SECTION_READONLYDATA:
1102 case SECTION_EXPORT:
1103 default:
1104 section[i].pageflags = PAG_READ;
1105 break;
1106 }
1107 if(section[i].flags & (IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA)) {
1108 //SvL: sometimes i.e. import/export sections also contain data
1109 // must make them read/write
1110 section[i].pageflags = PAG_WRITE;
1111 }
1112 }
1113 return(TRUE);
1114}
1115//******************************************************************************
1116//******************************************************************************
1117BOOL Win32PeLdrImage::setFixups(ULONG virtAddress, ULONG size)
1118{
1119 int i, j;
1120 char *page;
1121 ULONG count, newpage;
1122 Section *section;
1123 PIMAGE_BASE_RELOCATION prel = pFixups;
1124
1125 if(realBaseAddress == oh.ImageBase || fh.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) {
1126 return(TRUE);
1127 }
1128
1129 virtAddress -= realBaseAddress;
1130 //round size to next page boundary
1131 size = (size-1) & ~0xFFF;
1132 size += PAGE_SIZE;
1133
1134 if(prel) {
1135 j = 1;
1136 while(((ULONG)prel < (ULONG)pFixups+dwFixupSize) &&
1137 prel->VirtualAddress && prel->VirtualAddress < virtAddress)
1138 {
1139 prel = (PIMAGE_BASE_RELOCATION)((char*)prel + prel->SizeOfBlock);
1140 }
1141 while(((ULONG)prel < (ULONG)pFixups+dwFixupSize) &&
1142 prel->VirtualAddress && prel->VirtualAddress < virtAddress + size)
1143 {
1144 page = (char *)((char *)prel + (ULONG)prel->VirtualAddress);
1145 count = (prel->SizeOfBlock - 8)/2;
1146 j++;
1147 for(i=0;i<count;i++) {
1148 int type = prel->TypeOffset[i] >> 12;
1149 int offset = prel->TypeOffset[i] & 0xFFF;
1150 int fixupsize = 0;
1151
1152 switch(type)
1153 {
1154 case IMAGE_REL_BASED_HIGHLOW:
1155 fixupsize = 4;
1156 break;
1157 case IMAGE_REL_BASED_HIGH:
1158 case IMAGE_REL_BASED_LOW:
1159 fixupsize = 2;
1160 break;
1161 }
1162 //If the fixup crosses the final page boundary,
1163 //then we have to load another page
1164 if(prel->VirtualAddress + offset + fixupsize > virtAddress + size)
1165 {
1166 newpage = realBaseAddress + prel->VirtualAddress + offset + fixupsize;
1167 newpage &= ~0xFFF;
1168
1169 section = findSectionByOS2Addr(newpage);
1170 if(section == NULL) {
1171 //should never happen
1172 dprintf((LOG, "::setFixups -> section == NULL!!"));
1173 return FALSE;
1174 }
1175 //SvL: Read page from disk
1176 commitPage(newpage, FALSE, SINGLE_PAGE);
1177
1178 //SvL: Enable write access (TODO: may need to prevent other threads from being active)
1179 DosSetMem((PVOID)newpage, PAGE_SIZE, PAG_READ|PAG_WRITE);
1180 }
1181
1182 switch(type)
1183 {
1184 case IMAGE_REL_BASED_ABSOLUTE:
1185 break; //skip
1186 case IMAGE_REL_BASED_HIGHLOW:
1187 AddOff32Fixup(prel->VirtualAddress + offset);
1188 break;
1189 case IMAGE_REL_BASED_HIGH:
1190 AddOff16Fixup(prel->VirtualAddress + offset, TRUE);
1191 break;
1192 case IMAGE_REL_BASED_LOW:
1193 AddOff16Fixup(prel->VirtualAddress + offset, FALSE);
1194 break;
1195 case IMAGE_REL_BASED_HIGHADJ:
1196 case IMAGE_REL_BASED_MIPS_JMPADDR:
1197 default:
1198 break;
1199 }
1200 if(prel->VirtualAddress + offset + fixupsize > virtAddress + size)
1201 {
1202 //SvL: Restore original page protection flags (TODO: may need to prevent other threads from being active)
1203 DosSetMem((PVOID)newpage, PAGE_SIZE, section->pageflags);
1204 }
1205 }
1206 prel = (PIMAGE_BASE_RELOCATION)((char*)prel + prel->SizeOfBlock);
1207 }//while
1208 }
1209 else {
1210 dprintf((LOG, "Win32PeLdrImage::setFixups, no fixups at %x, %d", virtAddress, size));
1211 return(FALSE);
1212 }
1213 return(TRUE);
1214}
1215//******************************************************************************
1216//******************************************************************************
1217BOOL Win32PeLdrImage::setFixups(PIMAGE_BASE_RELOCATION prel)
1218{
1219 int i, j;
1220 char *page;
1221 ULONG count;
1222
1223 if(fh.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) {
1224 return(TRUE);
1225 }
1226
1227 if(prel) {
1228 j = 1;
1229 while(prel->VirtualAddress) {
1230 page = (char *)((char *)prel + (ULONG)prel->VirtualAddress);
1231 count = (prel->SizeOfBlock - 8)/2;
1232 dprintf((LOG, "Page %d Address %x Count %d", j, prel->VirtualAddress, count ));
1233 j++;
1234 for(i=0;i<count;i++) {
1235 int type = prel->TypeOffset[i] >> 12;
1236 int offset = prel->TypeOffset[i] & 0xFFF;
1237 switch(type) {
1238 case IMAGE_REL_BASED_ABSOLUTE:
1239//// dprintf((LOG, "absolute fixup; unused" ));
1240 break; //skip
1241 case IMAGE_REL_BASED_HIGHLOW:
1242//// dprintf((LOG, "address ", offset << " type ", type ));
1243 AddOff32Fixup(prel->VirtualAddress + offset);
1244 break;
1245 case IMAGE_REL_BASED_HIGH:
1246 AddOff16Fixup(prel->VirtualAddress + offset, TRUE);
1247 break;
1248 case IMAGE_REL_BASED_LOW:
1249 AddOff16Fixup(prel->VirtualAddress + offset, FALSE);
1250 break;
1251 case IMAGE_REL_BASED_HIGHADJ:
1252 case IMAGE_REL_BASED_MIPS_JMPADDR:
1253 default:
1254 dprintf((LOG, "Unknown/unsupported fixup type!" ));
1255 break;
1256 }
1257 }
1258 prel = (PIMAGE_BASE_RELOCATION)((char*)prel + prel->SizeOfBlock);
1259 }//while
1260 }
1261 else {
1262 dprintf((LOG, "No internal fixups found!" ));
1263 errorState = ERROR_INTERNAL;
1264 return(FALSE);
1265 }
1266 return(TRUE);
1267}
1268//******************************************************************************
1269//******************************************************************************
1270void Win32PeLdrImage::AddOff32Fixup(ULONG fixupaddr)
1271{
1272 ULONG orgaddr;
1273 ULONG *fixup;
1274
1275 fixup = (ULONG *)(fixupaddr + realBaseAddress);
1276 orgaddr = *fixup;
1277// dprintf((LOG, "AddOff32Fixup 0x%x org 0x%x -> new 0x%x", fixup, orgaddr, realBaseAddress + (*fixup - oh.ImageBase)));
1278 *fixup = realBaseAddress + (*fixup - oh.ImageBase);
1279}
1280//******************************************************************************
1281//******************************************************************************
1282void Win32PeLdrImage::AddOff16Fixup(ULONG fixupaddr, BOOL fHighFixup)
1283{
1284 ULONG orgaddr;
1285 USHORT *fixup;
1286
1287 fixup = (USHORT *)(fixupaddr + realBaseAddress);
1288 orgaddr = *fixup;
1289 if(fHighFixup) {
1290 *fixup += (USHORT)((realBaseAddress - oh.ImageBase) >> 16);
1291// dprintf((LOG, "AddOff16FixupH 0x%x org 0x%x -> new 0x%x", fixup, orgaddr, *fixup));
1292 }
1293 else {
1294 *fixup += (USHORT)((realBaseAddress - oh.ImageBase) & 0xFFFF);
1295// dprintf((LOG, "AddOff16FixupL 0x%x org 0x%x -> new 0x%x", fixup, orgaddr, *fixup));
1296 }
1297}
1298//******************************************************************************
1299#define MISSINGOFFSET_PUSHNAME 1
1300#define MISSINGOFFSET_PUSHORDINAL 1
1301#define MISSINGOFFSET_PUSHDLLNAME 6
1302#define MISSINGOFFSET_PUSHIMPORTIMAGE 11
1303#define MISSINGOFFSET_FUNCTION 16
1304
1305char missingapicode[23] = {
1306//push ordinal/name
1307 0x68, 0x00, 0x00, 0x00, 0x00,
1308//push dllname
1309 0x68, 0x00, 0x00, 0x00, 0x00,
1310//push image loading api
1311 0x68, 0x00, 0x00, 0x00, 0x00,
1312//mov ecx, MissingApiOrd/Name
1313 0xB9, 0x99, 0x99, 0x99, 0x99,
1314//call ecx
1315 0xFF, 0xD1,
1316//ret
1317 0xC3};
1318
1319//******************************************************************************
1320void Win32PeLdrImage::StoreImportByOrd(Win32ImageBase *WinImage, ULONG ordinal, ULONG impaddr)
1321{
1322 ULONG *import;
1323 ULONG apiaddr;
1324
1325 import = (ULONG *)impaddr;
1326 apiaddr = WinImage->getApi(ordinal);
1327 if(apiaddr == 0)
1328 {
1329 dprintf((LOG, "KERNEL32:Win32PeLdrImage - %s.%u not found\n",
1330 WinImage->getModuleName(),
1331 ordinal));
1332
1333 dprintf((LOG, "--->>> NOT FOUND!" ));
1334 char *code = (char *)_cmalloc(sizeof(missingapicode));
1335
1336 memcpy(code, missingapicode, sizeof(missingapicode));
1337 *(DWORD *)&code[MISSINGOFFSET_PUSHIMPORTIMAGE] = (DWORD)getModuleName();
1338 *(DWORD *)&code[MISSINGOFFSET_PUSHDLLNAME] = (DWORD)WinImage->getModuleName();
1339 *(DWORD *)&code[MISSINGOFFSET_PUSHORDINAL] = ordinal;
1340 *(DWORD *)&code[MISSINGOFFSET_FUNCTION] = (DWORD)MissingApiOrd;
1341 *import = (ULONG)code;
1342 }
1343 else *import = apiaddr;
1344}
1345//******************************************************************************
1346//******************************************************************************
1347void Win32PeLdrImage::StoreImportByName(Win32ImageBase *WinImage, char *impname, ULONG impaddr)
1348{
1349 ULONG *import;
1350 ULONG apiaddr;
1351
1352 import = (ULONG *)impaddr;
1353 apiaddr = WinImage->getApi(impname);
1354 if(apiaddr == 0)
1355 {
1356 dprintf((LOG, "KERNEL32:Win32PeLdrImage - %s.%s not found\n",
1357 WinImage->getModuleName(),
1358 impname));
1359
1360 dprintf((LOG, "--->>> NOT FOUND!" ));
1361
1362 char *code = (char *)_cmalloc(sizeof(missingapicode));
1363
1364 memcpy(code, missingapicode, sizeof(missingapicode));
1365 *(DWORD *)&code[MISSINGOFFSET_PUSHIMPORTIMAGE] = (DWORD)getModuleName();
1366 *(DWORD *)&code[MISSINGOFFSET_PUSHDLLNAME] = (DWORD)WinImage->getModuleName();
1367 *(DWORD *)&code[MISSINGOFFSET_PUSHNAME] = (DWORD)impname;
1368 *(DWORD *)&code[MISSINGOFFSET_FUNCTION] = (DWORD)MissingApiName;
1369 *import = (ULONG)code;
1370 }
1371 else *import = apiaddr;
1372}
1373//******************************************************************************
1374//******************************************************************************
1375BOOL Win32PeLdrImage::processExports(char *win32file)
1376{
1377 IMAGE_SECTION_HEADER sh;
1378 PIMAGE_EXPORT_DIRECTORY ped;
1379 ULONG *ptrNames, *ptrAddress;
1380 USHORT *ptrOrd;
1381 BOOL fForwarder;
1382 int i;
1383
1384 /* get section header and pointer to data directory for .edata section */
1385 if((ped = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryOffset
1386 (win32file, IMAGE_DIRECTORY_ENTRY_EXPORT)) != NULL &&
1387 GetSectionHdrByImageDir(win32file, IMAGE_DIRECTORY_ENTRY_EXPORT, &sh) ) {
1388
1389 dprintf((LOG, "Exported Functions: " ));
1390 ptrOrd = (USHORT *)((ULONG)ped->AddressOfNameOrdinals +
1391 (ULONG)win32file);
1392 ptrNames = (ULONG *)((ULONG)ped->AddressOfNames +
1393 (ULONG)win32file);
1394 ptrAddress = (ULONG *)((ULONG)ped->AddressOfFunctions +
1395 (ULONG)win32file);
1396 nrOrdExports = ped->NumberOfFunctions;
1397 nrNameExports = ped->NumberOfNames;
1398
1399 int ord, RVAExport;
1400 char *name;
1401 for(i=0;i<ped->NumberOfNames;i++)
1402 {
1403 fForwarder = FALSE;
1404 ord = ptrOrd[i] + ped->Base;
1405 name = (char *)((ULONG)ptrNames[i] + (ULONG)win32file);
1406 RVAExport = ptrAddress[ptrOrd[i]];
1407
1408 /* forwarder? ulRVA within export directory. */
1409 if(RVAExport > oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress &&
1410 RVAExport < oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
1411 + oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
1412 {
1413 fForwarder = AddForwarder(oh.ImageBase + RVAExport, name, ord);
1414 }
1415 if(!fForwarder) {
1416 //points to code (virtual address relative to oh.ImageBase
1417 AddNameExport(oh.ImageBase + RVAExport, name, ord);
1418 dprintf((LOG, "address 0x%x %s @%d (0x%08x)", RVAExport, name, ord, realBaseAddress + RVAExport));
1419 }
1420 }
1421 for(i=0;i<max(ped->NumberOfNames,ped->NumberOfFunctions);i++)
1422 {
1423 fForwarder = FALSE;
1424 ord = ped->Base + i; //Correct??
1425 RVAExport = ptrAddress[i];
1426 /* forwarder? ulRVA within export directory. */
1427 if(RVAExport > oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress &&
1428 RVAExport < oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
1429 + oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
1430 {
1431 fForwarder = AddForwarder(oh.ImageBase + RVAExport, NULL, ord);
1432 }
1433 if(!fForwarder && RVAExport) {
1434 //points to code (virtual address relative to oh.ImageBase
1435 dprintf((LOG, "ord %d at 0x%08x (0x%08x)", ord, RVAExport, realBaseAddress + RVAExport));
1436 AddOrdExport(oh.ImageBase + RVAExport, ord);
1437 }
1438 }
1439 }
1440
1441 return(TRUE);
1442}
1443//******************************************************************************
1444//******************************************************************************
1445void Win32PeLdrImage::AddNameExport(ULONG virtaddr, char *apiname, ULONG ordinal, BOOL fAbsoluteAddress)
1446{
1447 ULONG nsize;
1448 int iApiNameLength = strlen(apiname);
1449
1450 if(nameexports == NULL) {
1451 // think of a maximum of bytes per export name,
1452 // verify if this is true for MFC-DLLs, etc.
1453 nameExportSize = nrNameExports * (sizeof(NameExport) + 32);
1454
1455 nameexports = (NameExport *)malloc(nameExportSize);
1456 curnameexport = nameexports;
1457 }
1458 nsize = (ULONG)curnameexport - (ULONG)nameexports;
1459 if(nsize + sizeof(NameExport) + iApiNameLength > nameExportSize) {
1460 nameExportSize += 4096;
1461 char *tmp = (char *)nameexports;
1462 nameexports = (NameExport *)malloc(nameExportSize);
1463 memcpy(nameexports, tmp, nsize);
1464 curnameexport = (NameExport *)((ULONG)nameexports + nsize);
1465 free(tmp);
1466 }
1467 if(fAbsoluteAddress) {//forwarders use absolute address
1468 curnameexport->virtaddr = virtaddr;
1469 }
1470 else curnameexport->virtaddr = realBaseAddress + (virtaddr - oh.ImageBase);
1471 curnameexport->ordinal = ordinal;
1472 *(ULONG *)curnameexport->name = 0;
1473
1474 curnameexport->nlength = iApiNameLength + 1;
1475 memcpy(curnameexport->name, apiname, curnameexport->nlength);
1476
1477 if(curnameexport->nlength < sizeof(curnameexport->name))
1478 curnameexport->nlength = sizeof(curnameexport->name);
1479
1480 curnameexport = (NameExport *)((ULONG)curnameexport->name + curnameexport->nlength);
1481}
1482//******************************************************************************
1483//******************************************************************************
1484void Win32PeLdrImage::AddOrdExport(ULONG virtaddr, ULONG ordinal, BOOL fAbsoluteAddress)
1485{
1486 if(ordexports == NULL) {
1487 ordexports = (OrdExport *)malloc(nrOrdExports * sizeof(OrdExport));
1488 curordexport = ordexports;
1489 }
1490 if(fAbsoluteAddress) {//forwarders use absolute address
1491 curordexport->virtaddr = virtaddr;
1492 }
1493 else curordexport->virtaddr = realBaseAddress + (virtaddr - oh.ImageBase);
1494
1495 curordexport->ordinal = ordinal;
1496 curordexport++;
1497 nrOrdExportsRegistered++;
1498}
1499//******************************************************************************
1500//******************************************************************************
1501BOOL Win32PeLdrImage::AddForwarder(ULONG virtaddr, char *apiname, ULONG ordinal)
1502{
1503 char *forward = (char *)(realBaseAddress + (virtaddr - oh.ImageBase));
1504 char *forwarddll, *forwardapi;
1505 Win32DllBase *WinDll;
1506 DWORD exportaddr;
1507 int forwardord;
1508 int iForwardDllLength = strlen(forward);
1509 int iForwardApiLength;
1510
1511 if(iForwardDllLength == 0)
1512 return FALSE;
1513
1514 forwarddll = (char*)alloca(iForwardDllLength);
1515 if(forwarddll == NULL) {
1516 DebugInt3();
1517 return FALSE;
1518 }
1519 memcpy(forwarddll, forward, iForwardDllLength + 1);
1520
1521 forwardapi = strchr(forwarddll, '.');
1522 if(forwardapi == NULL) {
1523 return FALSE;
1524 }
1525 *forwardapi++ = 0;
1526 iForwardApiLength = strlen(forwardapi);
1527 if(iForwardApiLength == 0) {
1528 return FALSE;
1529 }
1530 WinDll = Win32DllBase::findModule(forwarddll);
1531 if(WinDll == NULL) {
1532 WinDll = loadDll(forwarddll);
1533 if(WinDll == NULL) {
1534 dprintf((LOG, "ERROR: couldn't find forwarder %s.%s", forwarddll, forwardapi));
1535 return FALSE;
1536 }
1537 }
1538 //check if name or ordinal forwarder
1539 forwardord = 0;
1540 if(*forwardapi >= '0' && *forwardapi <= '9') {
1541 forwardord = atoi(forwardapi);
1542 }
1543 if(forwardord != 0 || (iForwardApiLength == 1 && *forwardapi == '0')) {
1544 exportaddr = WinDll->getApi(forwardord);
1545 }
1546 else exportaddr = WinDll->getApi(forwardapi);
1547
1548 if(apiname) {
1549 dprintf((LOG, "address 0x%x %s @%d (0x%08x) forwarder %s.%s", virtaddr - oh.ImageBase, apiname, ordinal, virtaddr, forwarddll, forwardapi));
1550 AddNameExport(exportaddr, apiname, ordinal, TRUE);
1551 }
1552 else {
1553 dprintf((LOG, "address 0x%x @%d (0x%08x) forwarder %s.%s", virtaddr - oh.ImageBase, ordinal, virtaddr, forwarddll, forwardapi));
1554 AddOrdExport(exportaddr, ordinal, TRUE);
1555 }
1556 return TRUE;
1557}
1558//******************************************************************************
1559//******************************************************************************
1560Win32DllBase *Win32PeLdrImage::loadDll(char *pszCurModule)
1561{
1562 Win32DllBase *WinDll = NULL;
1563 char modname[CCHMAXPATH];
1564
1565 strcpy(modname, pszCurModule);
1566
1567 //rename dll if necessary (i.e. OLE32 -> OLE32OS2)
1568 Win32DllBase::renameDll(modname);
1569
1570 char szModName2[CCHMAXPATH];
1571 strcpy(szModName2, modname);
1572 if (!Win32ImageBase::findDll(szModName2, modname, sizeof(modname)))
1573 {
1574 dprintf((LOG, "Module %s not found!", modname));
1575 sprintf(szErrorModule, "%s", modname);
1576 errorState = 2;
1577 return NULL;
1578 }
1579
1580 if(isPEImage(modname, NULL, NULL) != ERROR_SUCCESS_W)
1581 {//LX image, so let OS/2 do all the work for us
1582 APIRET rc;
1583 char szModuleFailure[CCHMAXPATH] = "";
1584 ULONG hInstanceNewDll;
1585 Win32LxDll *lxdll;
1586
1587 char *dot = strchr(modname, '.');
1588 if(dot == NULL) {
1589 strcat(modname, DLL_EXTENSION);
1590 }
1591 rc = DosLoadModule(szModuleFailure, sizeof(szModuleFailure), modname, (HMODULE *)&hInstanceNewDll);
1592 if(rc) {
1593 dprintf((LOG, "DosLoadModule returned %X for %s", rc, szModuleFailure));
1594 sprintf(szErrorModule, "%s", szModuleFailure);
1595 errorState = rc;
1596 return NULL;
1597 }
1598 lxdll = Win32LxDll::findModuleByOS2Handle(hInstanceNewDll);
1599 if(lxdll == NULL) {//shouldn't happen!
1600 dprintf((LOG, "Just loaded the dll, but can't find it anywhere?!!?"));
1601 errorState = ERROR_INTERNAL;
1602 return NULL;
1603 }
1604 lxdll->setDllHandleOS2(hInstanceNewDll);
1605 if(lxdll->AddRef() == -1) {//-1 -> load failed (attachProcess)
1606 dprintf((LOG, "Dll %s refused to be loaded; aborting", modname));
1607 delete lxdll;
1608 errorState = ERROR_INTERNAL;
1609 return NULL;
1610 }
1611 WinDll = (Win32DllBase*)lxdll;
1612 }
1613 else {
1614 Win32PeLdrDll *pedll;
1615
1616 pedll = new Win32PeLdrDll(modname, this);
1617 if(pedll == NULL) {
1618 dprintf((LOG, "pedll: Error allocating memory" ));
1619 errorState = ERROR_INTERNAL;
1620 return NULL;
1621 }
1622 dprintf((LOG, "**********************************************************************" ));
1623 dprintf((LOG, "********************** Loading Module *********************" ));
1624 dprintf((LOG, "**********************************************************************" ));
1625 if(pedll->init(0) != LDRERROR_SUCCESS) {
1626 dprintf((LOG, "Internal WinDll error ", pedll->getError() ));
1627 delete pedll;
1628 return NULL;
1629 }
1630#ifdef DEBUG
1631 pedll->AddRef(getModuleName());
1632#else
1633 pedll->AddRef();
1634#endif
1635 if(pedll->attachProcess() == FALSE) {
1636 dprintf((LOG, "attachProcess failed!" ));
1637 delete pedll;
1638 errorState = ERROR_INTERNAL;
1639 return NULL;
1640 }
1641 WinDll = (Win32DllBase*)pedll;
1642 }
1643
1644 dprintf((LOG, "**********************************************************************" ));
1645 dprintf((LOG, "********************** Finished Loading Module %s ", modname ));
1646 dprintf((LOG, "**********************************************************************" ));
1647
1648 return WinDll;
1649}
1650
1651//******************************************************************************
1652/** All initial processing of imports is done here
1653 * Should now detect most Borland styled files including the GifCon32.exe and
1654 * loader32 from SoftIce. (Stupid Borland!!!)
1655 *
1656 * knut [Jul 22 1998 2:44am]
1657 **/
1658//******************************************************************************
1659BOOL Win32PeLdrImage::processImports(char *win32file)
1660{
1661 PIMAGE_IMPORT_DESCRIPTOR pID;
1662 IMAGE_SECTION_HEADER shID;
1663 IMAGE_SECTION_HEADER shExtra = {0};
1664 PIMAGE_OPTIONAL_HEADER pOH;
1665 int i,j, nrPages;
1666 BOOL fBorland = 0;
1667 int cModules;
1668 char *pszModules;
1669 char *pszCurModule;
1670 char *pszTmp;
1671 ULONG *pulImport;
1672 ULONG ulCurFixup;
1673 int Size;
1674 Win32DllBase *WinDll;
1675 Win32ImageBase *WinImage = NULL;
1676 Section *section;
1677
1678 /* "algorithm:"
1679 * 1) get module names and store them
1680 * a) check dwRVAModuleName is within .idata seg - if not find section
1681 * 2) iterate thru functions of each module
1682 * a) check OriginalFirstThunk is not 0 and that it points to a RVA.
1683 * b) if not a) borland-styled PE-file - ARG!!!
1684 * check FirstThunk
1685 * c) check OriginalFirstThunk/FirstThunk ok RVAs and find right section
1686 * d) store ordinal/name import
1687 * 3) finished
1688 */
1689
1690 /* 1) get module names */
1691 pID = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryOffset(win32file, IMAGE_DIRECTORY_ENTRY_IMPORT);
1692 if (pID == NULL)
1693 return TRUE;
1694 if (!GetSectionHdrByImageDir(win32file, IMAGE_DIRECTORY_ENTRY_IMPORT, &shID))
1695 return TRUE;
1696
1697 //calc size of module list
1698 i = Size = cModules = 0;
1699 while (pID[i].Name != 0)
1700 {
1701 //test RVA inside ID-Section
1702 if (pID[i].Name >= shID.VirtualAddress && pID[i].Name < shID.VirtualAddress + max(shID.Misc.VirtualSize, shID.SizeOfRawData)) {
1703 pszTmp = (char*)(pID[i].Name + (ULONG)win32file);
1704 }
1705 else {
1706 //is the "Extra"-section already found or do we have to find it?
1707 if (pID[i].Name < shExtra.VirtualAddress || pID[i].Name >= shExtra.VirtualAddress + max(shExtra.Misc.VirtualSize, shExtra.SizeOfRawData)) {
1708 if (!GetSectionHdrByRVA(win32file, &shExtra, pID[i].Name))
1709 return FALSE;
1710 }
1711 pszTmp = (char*)(pID[i].Name + (ULONG)win32file);
1712 }
1713 Size += strlen(pszTmp) + 1;
1714 i++;
1715 cModules++;
1716 }
1717
1718 pszModules = (char*)alloca(Size);
1719 if(pszModules == NULL) {
1720 DebugInt3();
1721 return FALSE;
1722 }
1723 j = 0;
1724 for (i = 0; i < cModules; i++)
1725 {
1726 //test RVA inside ID-Section
1727 if (pID[i].Name >= shID.VirtualAddress && pID[i].Name < shID.VirtualAddress + max(shID.Misc.VirtualSize, shID.SizeOfRawData)) {
1728 pszTmp = (char*)(pID[i].Name + (ULONG)win32file);
1729 }
1730 else {
1731 fBorland = TRUE;
1732 //is the "Extra"-section already found or do we have to find it?
1733 if (pID[i].Name < shExtra.VirtualAddress || pID[i].Name >= shExtra.VirtualAddress + max(shExtra.Misc.VirtualSize, shExtra.SizeOfRawData))
1734 {
1735 if (GetSectionHdrByRVA(win32file, &shExtra, pID[i].Name)) {
1736 return FALSE;
1737 }
1738 }
1739 pszTmp = (char*)(pID[i].Name + (ULONG)win32file);
1740 }
1741
1742 int iTmpLength = strlen(pszTmp) + 1;
1743 memcpy(pszModules+j, pszTmp, iTmpLength);
1744 j += iTmpLength;
1745 }
1746 if (fBorland)
1747 dprintf((LOG, "Borland-styled PE-File." ));
1748
1749 //Store modules
1750 dprintf((LOG, "%d imported Modules: ", cModules ));
1751
1752 /* 2) functions */
1753 pszCurModule = pszModules;
1754 pOH = (PIMAGE_OPTIONAL_HEADER)OPTHEADEROFF(win32file);
1755 for (i = 0; i < cModules; i++)
1756 {
1757 dprintf((LOG, "Module %s", pszCurModule ));
1758 if(pID[i].ForwarderChain) {
1759 dprintf((LOG, "ForwarderChain: %x", pID[i].ForwarderChain));
1760 }
1761 // a) check that OriginalFirstThunk not is 0 and look for Borland-styled PE
1762 if (i == 0)
1763 {
1764 //heavy borland-style test - assume array of thunks is within that style does not change
1765 if((ULONG)pID[i].u.OriginalFirstThunk == 0 ||
1766 (ULONG)pID[i].u.OriginalFirstThunk < shID.VirtualAddress ||
1767 (ULONG)pID[i].u.OriginalFirstThunk >= shID.VirtualAddress + max(shID.Misc.VirtualSize, shID.SizeOfRawData) ||
1768 (ULONG)pID[i].u.OriginalFirstThunk >= pOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress &&
1769 (ULONG)pID[i].u.OriginalFirstThunk < sizeof(*pID)*cModules + pOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
1770 {
1771 fBorland = TRUE;
1772 }
1773 }
1774 //light borland-style test
1775 if (pID[i].u.OriginalFirstThunk == 0 || fBorland) {
1776 pulImport = (ULONG*)pID[i].FirstThunk;
1777 }
1778 else pulImport = (ULONG*)pID[i].u.OriginalFirstThunk;
1779
1780 // b) check if RVA ok
1781 if (!(pulImport > 0 && (ULONG)pulImport < pOH->SizeOfImage)) {
1782 dprintf((LOG, "Invalid RVA %x", pulImport ));
1783 break;
1784 }
1785 // check section
1786 if ((ULONG)pulImport < shExtra.VirtualAddress || (ULONG)pulImport >= shExtra.VirtualAddress + max(shExtra.Misc.VirtualSize, shExtra.SizeOfRawData))
1787 {
1788 if (!GetSectionHdrByRVA(win32file, &shExtra, (ULONG)pulImport))
1789 {
1790 dprintf((LOG, "warning: could not find section for Thunk RVA %x", pulImport ));
1791 break;
1792 }
1793 }
1794
1795 //Load dll if needed
1796 dprintf((LOG, "**********************************************************************" ));
1797 dprintf((LOG, "************** Import Module %s ", pszCurModule ));
1798 dprintf((LOG, "**********************************************************************" ));
1799 WinDll = Win32DllBase::findModule(pszCurModule);
1800
1801 if(WinDll == NULL)
1802 { //not found, so load it
1803 if (WinExe != NULL && WinExe->matchModName(pszCurModule)) {
1804 WinImage = (Win32ImageBase *)WinExe;
1805 }
1806 else {
1807 WinDll = loadDll(pszCurModule);
1808 if(WinDll == NULL) {
1809 return FALSE;
1810 }
1811 }
1812 }
1813 else {
1814 WinDll->AddRef();
1815 dprintf((LOG, "Already found ", pszCurModule));
1816 }
1817 if(WinDll != NULL) {
1818 //add the dll we just loaded to dependency list for this image
1819 addDependency(WinDll);
1820
1821 //Make sure the dependency list is correct (already done
1822 //in the ctor of Win32DllBase, but for LX dlls the parent is
1823 //then set to NULL; so change it here again
1824 WinDll->setUnloadOrder(this);
1825 WinImage = (Win32ImageBase *)WinDll;
1826 }
1827 else
1828 if(WinImage == NULL) {
1829 dprintf((LOG, "Unable to load dll %s", pszCurModule ));
1830 return FALSE;
1831 }
1832
1833 pulImport = (PULONG)((ULONG)pulImport + (ULONG)win32file);
1834 j = 0;
1835 ulCurFixup = (ULONG)pID[i].FirstThunk + (ULONG)win32file;
1836
1837 section = findSectionByOS2Addr(ulCurFixup);
1838 if(section == NULL) {
1839 dprintf((LOG, "Unable to find section for %x", ulCurFixup ));
1840 return FALSE;
1841 }
1842 //Read page from disk
1843 commitPage(ulCurFixup & ~0xfff, FALSE, SINGLE_PAGE);
1844 //Enable write access
1845 DosSetMem((PVOID)(ulCurFixup & ~0xfff), PAGE_SIZE, PAG_READ|PAG_WRITE);
1846 nrPages = 1;
1847
1848 while (pulImport[j] != 0) {
1849 if (pulImport[j] & IMAGE_ORDINAL_FLAG) { //ordinal
1850 dprintf((LOG, "0x%08x Imported function %s @%d", ulCurFixup , pszCurModule, (pulImport[j] & ~IMAGE_ORDINAL_FLAG) ));
1851 StoreImportByOrd(WinImage, pulImport[j] & ~IMAGE_ORDINAL_FLAG, ulCurFixup);
1852 }
1853 else { //name
1854 //check
1855 if (pulImport[j] < shExtra.VirtualAddress || pulImport[j] >= shExtra.VirtualAddress + max(shExtra.Misc.VirtualSize, shExtra.SizeOfRawData))
1856 {
1857 if (!GetSectionHdrByRVA(win32file, &shExtra, pulImport[j]))
1858 {
1859 dprintf((LOG, "warning: could not find section for Import Name RVA ", pulImport[j] ));
1860 break;
1861 }
1862 }
1863 //KSO - Aug 6 1998 1:15am:this eases comparing...
1864 char *pszFunctionName = (char*)(pulImport[j] + (ULONG)win32file + 2);
1865 dprintf((LOG, "0x%08x Imported function %s (0x%08x)", ulCurFixup, pszFunctionName, WinImage->getApi(pszFunctionName)));
1866 StoreImportByName(WinImage, pszFunctionName, ulCurFixup);
1867 }
1868 ulCurFixup += sizeof(IMAGE_THUNK_DATA);
1869 j++;
1870 if((ulCurFixup & 0xfff) == 0) {
1871 commitPage(ulCurFixup & ~0xfff, FALSE, SINGLE_PAGE);
1872 DosSetMem((PVOID)(ulCurFixup & ~0xfff), PAGE_SIZE, PAG_READ|PAG_WRITE);
1873 nrPages++;
1874 }
1875 }
1876 //SvL: And restore original protection flags
1877 ulCurFixup = (ULONG)pID[i].FirstThunk + pOH->ImageBase;
1878 DosSetMem((PVOID)(ulCurFixup & ~0xfff), PAGE_SIZE*nrPages, section->pageflags);
1879
1880 dprintf((LOG, "**********************************************************************" ));
1881 dprintf((LOG, "************** End Import Module %s ", pszCurModule ));
1882 dprintf((LOG, "**********************************************************************" ));
1883
1884 pszCurModule += strlen(pszCurModule) + 1;
1885 }//for (i = 0; i < cModules; i++)
1886 return TRUE;
1887}
1888//******************************************************************************
1889//******************************************************************************
1890BOOL Win32PeLdrImage::insideModule(ULONG address)
1891{
1892 if((address >= realBaseAddress) && (address < realBaseAddress + imageSize)) {
1893 return TRUE;
1894 }
1895 return FALSE;
1896}
1897//******************************************************************************
1898//******************************************************************************
1899BOOL Win32PeLdrImage::insideModuleCode(ULONG address)
1900{
1901 Section *sect;
1902
1903 sect = findSectionByOS2Addr(address);
1904 if(sect && (sect->pageflags & PAG_EXECUTE)) {
1905 return TRUE;
1906 }
1907 return FALSE;
1908}
1909//******************************************************************************
1910//******************************************************************************
1911ULONG Win32PeLdrImage::getImageSize()
1912{
1913 return imageSize;
1914}
1915//******************************************************************************
1916//******************************************************************************
1917ULONG Win32PeLdrImage::getApi(char *name)
1918{
1919 ULONG apiaddr, i, apilen;
1920 char *apiname;
1921 char tmp[4];
1922 NameExport *curexport;
1923 ULONG ulAPIOrdinal; /* api requested by ordinal */
1924
1925 apilen = strlen(name) + 1;
1926 if(apilen < 4)
1927 {
1928 *(ULONG *)tmp = 0;
1929 strcpy(tmp, name);
1930 apiname = tmp;
1931 apilen = 4;
1932 }
1933 else apiname = name;
1934
1935 curexport = nameexports;
1936 for(i=0; i<nrNameExports; i++)
1937 {
1938 if(apilen == curexport->nlength &&
1939 *(ULONG *)curexport->name == *(ULONG *)apiname)
1940 {
1941 if(strcmp(curexport->name, apiname) == 0)
1942 return(curexport->virtaddr);
1943 }
1944 curexport = (NameExport *)((ULONG)curexport->name + curexport->nlength);
1945 }
1946 return(0);
1947}
1948//******************************************************************************
1949//******************************************************************************
1950ULONG Win32PeLdrImage::getApi(int ordinal)
1951{
1952 ULONG apiaddr, i;
1953 OrdExport *curexport;
1954 NameExport *nexport;
1955
1956 curexport = ordexports;
1957
1958 /* accelerated resolving of ordinal exports
1959 * is based on the assumption the ordinal export
1960 * table is always sorted ascending.
1961 *
1962 * When the step size is too small, we continue
1963 * with the linear search.
1964 */
1965
1966 // start in the middle of the tree
1967 i = nrOrdExportsRegistered >> 1;
1968 int iStep = i;
1969
1970 for(;;)
1971 {
1972 int iThisExport = curexport[i].ordinal;
1973
1974 iStep >>= 1; // next step will be narrower
1975
1976 if (iThisExport < ordinal)
1977 i += min(iStep, (ordinal-iThisExport)); // move farther down the list
1978 else
1979 if (iThisExport == ordinal) // found the export?
1980 return curexport[i].virtaddr;
1981 else
1982 i -= min(iStep, (iThisExport-ordinal)); // move farther up the list
1983
1984 // if we're in the direct neighbourhood search linearly
1985 if (iStep <= 1)
1986 {
1987 // decide if we're to search backward or forward
1988 if (ordinal > curexport[i].ordinal)
1989 {
1990 // As a certain number of exports are 0 at the end
1991 // of the array, this case will hit fairly often.
1992 // the last comparison will send the loop off into the
1993 // wrong direction!
1994#ifdef DEBUG
1995 if (curexport[i].ordinal == 0)
1996 {
1997 DebugInt3();
1998 }
1999#endif
2000
2001 for (;i<nrOrdExports;i++) // scan forward
2002 {
2003 iThisExport = curexport[i].ordinal;
2004 if(iThisExport == ordinal)
2005 return(curexport[i].virtaddr);
2006 else
2007 if (iThisExport > ordinal)
2008 {
2009 // Oops, cannot find the ordinal in the sorted list
2010 break;
2011 }
2012 }
2013 }
2014 else
2015 {
2016 for (;i>=0;i--) // scan backward
2017 {
2018 iThisExport = curexport[i].ordinal;
2019 if(curexport[i].ordinal == ordinal)
2020 return(curexport[i].virtaddr);
2021 else
2022 if (iThisExport < ordinal)
2023 // Oops, cannot find the ordinal in the sorted list
2024 break;
2025 }
2026 }
2027
2028 // not found yet.
2029 break;
2030 }
2031 }
2032
2033 //Name exports also contain an ordinal, so check this
2034 nexport = nameexports;
2035 for(i=0;i<nrNameExports;i++) {
2036 if(nexport->ordinal == ordinal)
2037 return(nexport->virtaddr);
2038
2039 nexport = (NameExport *)((ULONG)nexport->name + nexport->nlength);
2040 }
2041 return(0);
2042}
2043//******************************************************************************
2044//Returns required OS version for this image
2045//******************************************************************************
2046ULONG Win32PeLdrImage::getVersion()
2047{
2048 return (oh.MajorOperatingSystemVersion << 16) | oh.MinorOperatingSystemVersion;
2049}
2050//******************************************************************************
2051//******************************************************************************
2052ULONG WIN32API MissingApiOrd(char *parentimage, char *dllname, int ordinal)
2053{
2054 char message[256];
2055
2056 sprintf(message, "The application has called the non-existing api %s->%d (loaded by %s)", dllname, ordinal, parentimage);
2057 return MissingApi(message);
2058}
2059//******************************************************************************
2060//******************************************************************************
2061ULONG WIN32API MissingApiName(char *parentimage, char *dllname, char *functionname)
2062{
2063 char message[256];
2064
2065 sprintf(message, "The application has called the non-existing api %s->%s (loaded by %s)", dllname, functionname, parentimage);
2066 return MissingApi(message);
2067}
2068//******************************************************************************
2069//******************************************************************************
2070ULONG WIN32API MissingApi(char *message)
2071{
2072 static BOOL fIgnore = FALSE;
2073 int r;
2074
2075 dprintf((LOG, "Missing api called!\n"));
2076 if(fIgnore)
2077 return(0);
2078
2079 do {
2080 r = WinMessageBox(HWND_DESKTOP, NULLHANDLE, message,
2081 "Internal Error", 0, MB_ABORTRETRYIGNORE | MB_ICONEXCLAMATION | MB_MOVEABLE);
2082 }
2083 while(r == MBID_RETRY); //giggle
2084
2085 if( r != MBID_IGNORE )
2086 ExitProcess(987);
2087
2088 fIgnore = TRUE;
2089 return(0);
2090}
2091/******************************************************************************/
2092/******************************************************************************/
Note: See TracBrowser for help on using the repository browser.