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

Last change on this file since 5832 was 5832, checked in by phaller, 24 years ago

.

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