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

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

added dll load hook and function to override named or ordinal exports

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