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

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

.

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