source: branches/gcc-kmk/src/kernel32/winimagepeldr.cpp@ 21837

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

Use pid instead of the ordinal number in log file names.

This in particular fixes the problem when WGSS50 writes to the log
before the ordinal is correctly initialized by KERNEL32 which resulted
into two processes writing to the same log file.

This also guarantees that a subsequent re-run will not vanish the
previous log file which is also useful sometimes.

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