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

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

print missing api name & dll when called

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