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

Last change on this file since 8883 was 8883, checked in by achimha, 23 years ago

added more comments, documentation

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