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

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

.

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