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

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

Enhanced PE loader class to support files with PE image starting at an offset ..= 0 (custom build) & Fixes for memory map view with offset

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