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

Last change on this file since 5448 was 5448, checked in by sandervl, 24 years ago

check executable type in CreateProcess and use PEC for VIO and PE for GUI apps

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