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

Last change on this file since 2687 was 2687, checked in by sandervl, 26 years ago

Search path for executables when they can't be found in the current directory.

File size: 53.5 KB
Line 
1/* $Id: winimagepeldr.cpp,v 1.30 2000-02-08 22:29:16 sandervl Exp $ */
2
3/*
4 * Win32 PE loader Image base class
5 *
6 * Copyright 1998-1999 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 *
13 * NOTE: RSRC_LOAD is a special flag to only load the resource directory
14 * of a PE image. Processing imports, sections etc is not done.
15 * Nor is it put into the linked list of dlls (if it's a dll).
16 * This is useful for GetVersionSize/Resource in case it wants to
17 * get version info of an image that is not loaded.
18 * So an instance of this type can't be used for anything but resource lookup!
19 *
20 */
21
22#define INCL_DOSFILEMGR /* File Manager values */
23#define INCL_DOSMODULEMGR
24#define INCL_DOSERRORS /* DOS Error values */
25#define INCL_DOSPROCESS /* DOS Process values */
26#define INCL_DOSMISC /* DOS Miscellanous values */
27#define INCL_WIN
28#define INCL_BASE
29#include <os2wrap.h> //Odin32 OS/2 api wrappers
30
31#include <stdio.h>
32#include <string.h>
33#include <stdlib.h>
34
35#include <assert.h>
36//use a different logfile
37#define PRIVATE_LOGGING
38#include <misc.h>
39#include <win32type.h>
40#include <winimagebase.h>
41#include <winimagepeldr.h>
42#include <windllpeldr.h>
43#include <pefile.h>
44#include <unicode.h>
45#include <winres.h>
46#include "oslibmisc.h"
47#include "initterm.h"
48#include <win\virtual.h>
49#include "oslibdos.h"
50#include "mmap.h"
51#include <wprocess.h>
52
53//Define COMMIT_ALL to let the pe loader commit all sections of the image
54//This is very useful during debugging as you'll get lots of exceptions
55//otherwise.
56#define COMMIT_ALL
57
58char szErrorTitle[] = "Odin";
59char szMemErrorMsg[] = "Memory allocation failure";
60char szFileErrorMsg[] = "File IO error";
61char szPEErrorMsg[] = "Not a valid win32 exe. (perhaps 16 bits windows)";
62char szCPUErrorMsg[] = "Executable doesn't run on x86 machines";
63char szExeErrorMsg[] = "File isn't an executable";
64char szInteralErrorMsg[]= "Internal Error";
65char szErrorModule[128] = "";
66
67#ifndef max
68#define max(a, b) ((a>b) ? a : b)
69#endif
70
71static FILE *_privateLogFile = NULL;
72
73ULONG MissingApi();
74extern ULONG flAllocMem; /*Tue 03.03.1998: knut */
75
76//******************************************************************************
77//******************************************************************************
78void OpenPrivateLogFilePE()
79{
80 char logname[CCHMAXPATH];
81
82 sprintf(logname, "pe_%d.log", loadNr);
83 _privateLogFile = fopen(logname, "w");
84 if(_privateLogFile == NULL) {
85 sprintf(logname, "%spe_%d.log", kernel32Path, loadNr);
86 _privateLogFile = fopen(logname, "w");
87 }
88 dprintfGlobal(("PE LOGFILE : %s", logname));
89}
90//******************************************************************************
91//******************************************************************************
92void ClosePrivateLogFilePE()
93{
94 if(_privateLogFile) {
95 fclose(_privateLogFile);
96 _privateLogFile = NULL;
97 }
98}
99//******************************************************************************
100//******************************************************************************
101Win32PeLdrImage::Win32PeLdrImage(char *pszFileName, BOOL isExe, int loadtype) :
102 Win32ImageBase(-1),
103 nrsections(0), imageSize(0),
104 imageVirtBase(-1), realBaseAddress(0), imageVirtEnd(0),
105 nrNameExports(0), nrOrdExports(0), nameexports(NULL), ordexports(NULL),
106 memmap(NULL), pFixups(NULL)
107{
108 HFILE dllfile;
109
110 loadType = loadtype;
111
112 strcpy(szFileName, pszFileName);
113 strupr(szFileName);
114 if(isExe) {
115 if(!strchr(szFileName, '.')) {
116 strcat(szFileName,".EXE");
117 }
118 dllfile = OSLibDosOpen(szFileName, OSLIB_ACCESS_READONLY|OSLIB_ACCESS_SHAREDENYNONE);
119 if(dllfile == NULL) {
120 if(!strstr(szFileName, ".EXE")) {
121 strcat(szFileName,".EXE");
122 }
123 dllfile = OSLibDosOpen(szFileName, OSLIB_ACCESS_READONLY|OSLIB_ACCESS_SHAREDENYNONE);
124 if(dllfile == NULL) {
125 OSLibDosSearchPath(OSLIB_SEARCHENV, "PATH", szFileName, szFileName, sizeof(szFileName));
126 }
127 }
128 else OSLibDosClose(dllfile);
129 }
130 else {
131 if(!strchr(szFileName, '.')) {
132 strcat(szFileName,".DLL");
133 }
134 dllfile = OSLibDosOpen(szFileName, OSLIB_ACCESS_READONLY|OSLIB_ACCESS_SHAREDENYNONE);
135 if(dllfile == NULL) {//search in libpath for dll
136 strcpy(szModule, kernel32Path);
137 strcat(szModule, szFileName);
138 strcpy(szFileName, szModule);
139
140 dllfile = OSLibDosOpen(szFileName, OSLIB_ACCESS_READONLY|OSLIB_ACCESS_SHAREDENYNONE);
141 if(dllfile == NULL) {
142 if(!strstr(szFileName, ".DLL")) {
143 strcat(szFileName,".DLL");
144 dllfile = OSLibDosOpen(szFileName, OSLIB_ACCESS_READONLY|OSLIB_ACCESS_SHAREDENYNONE);
145 if(dllfile == NULL) {
146 strcpy(szModule, kernel32Path);
147 strcat(szModule, szFileName);
148 strcpy(szFileName, szModule);
149 }
150 else OSLibDosClose(dllfile);
151 }
152 }
153 else OSLibDosClose(dllfile);
154 }
155 else OSLibDosClose(dllfile);
156 }
157 strcpy(szModule, OSLibStripPath(szFileName));
158 strupr(szModule);
159 char *dot = strstr(szModule, ".");
160 while(dot) {
161 char *newdot = strstr(dot+1, ".");
162 if(newdot == NULL) break;
163 dot = newdot;
164 }
165 if(dot)
166 *dot = 0;
167}
168//******************************************************************************
169//******************************************************************************
170Win32PeLdrImage::~Win32PeLdrImage()
171{
172 if(memmap)
173 delete memmap;
174
175 if(hFile) {
176 OSLibDosClose(hFile);
177 hFile = 0;
178 }
179
180 if(realBaseAddress)
181 DosFreeMem((PVOID)realBaseAddress);
182
183 if(nameexports)
184 free(nameexports);
185
186 if(ordexports)
187 free(ordexports);
188}
189//******************************************************************************
190//******************************************************************************
191BOOL Win32PeLdrImage::init(ULONG reservedMem)
192{
193 LPVOID win32file = NULL;
194 ULONG filesize, ulRead, ulNewPos;
195 PIMAGE_SECTION_HEADER psh;
196 IMAGE_SECTION_HEADER sh;
197 IMAGE_TLS_DIRECTORY *tlsDir = NULL;
198 int nSections, i;
199 char szFullPath[CCHMAXPATH] = "";
200 IMAGE_DOS_HEADER doshdr;
201 ULONG signature;
202
203 hFile = OSLibDosOpen(szFileName, OSLIB_ACCESS_READONLY|OSLIB_ACCESS_SHAREDENYNONE);
204
205 //default error:
206 strcpy(szErrorModule, OSLibStripPath(szFileName));
207 if(hFile == NULL) {
208 goto failure;
209 }
210 //read dos header
211 if(DosRead(hFile, (LPVOID)&doshdr, sizeof(doshdr), &ulRead)) {
212 goto failure;
213 }
214 if(OSLibDosSetFilePtr(hFile, doshdr.e_lfanew, OSLIB_SETPTR_FILE_BEGIN) == -1) {
215 goto failure;
216 }
217 //read signature dword
218 if(DosRead(hFile, (LPVOID)&signature, sizeof(signature), &ulRead)) {
219 goto failure;
220 }
221 //read pe header
222 if(DosRead(hFile, (LPVOID)&fh, sizeof(fh), &ulRead)) {
223 goto failure;
224 }
225 //read optional header
226 if(DosRead(hFile, (LPVOID)&oh, sizeof(oh), &ulRead)) {
227 goto failure;
228 }
229 if(doshdr.e_magic != IMAGE_DOS_SIGNATURE || signature != IMAGE_NT_SIGNATURE) {
230 dprintf((LOG, "Not a valid PE file (probably a 16 bits windows exe/dll)!"));
231 WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, szPEErrorMsg, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
232 goto failure;
233 }
234
235 if(oh.SizeOfImage == 0) {//just in case
236 oh.SizeOfImage = OSLibDosGetFileSize(hFile);
237 }
238
239 imageSize = oh.SizeOfImage;
240 //Allocate memory to hold the entire image
241 if(allocSections(reservedMem) == FALSE) {
242 dprintf((LOG, "Failed to allocate image memory, rc %d", errorState));;
243 goto failure;
244 }
245
246 memmap = new Win32MemMap(this, realBaseAddress, imageSize);
247 if(memmap == NULL || !memmap->Init(0)) {
248 goto failure;
249 }
250 win32file = memmap->mapViewOfFile(0, 0, 2);
251
252 if(DosQueryPathInfo(szFileName, FIL_QUERYFULLNAME, szFullPath, sizeof(szFullPath)) == 0) {
253 setFullPath(szFullPath);
254 }
255
256 if(!(fh.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)) {//not valid
257 dprintf((LOG, "Not a valid PE file!"));
258 WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, szPEErrorMsg, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
259 goto failure;
260 }
261 if(fh.Machine != IMAGE_FILE_MACHINE_I386) {
262 dprintf((LOG, "Doesn't run on x86 processors!"));
263 WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, szCPUErrorMsg, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
264 goto failure;
265 }
266 //IMAGE_FILE_SYSTEM == only drivers (device/file system/video etc)?
267 if(fh.Characteristics & IMAGE_FILE_SYSTEM) {
268 dprintf((LOG, "Can't convert system files"));
269 WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, szExeErrorMsg, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
270 goto failure;
271 }
272
273 if(fh.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) {
274 dprintf((LOG, "No fixups, might not run!"));
275 }
276
277 dprintf((LOG, "PE file : %s", szFileName));
278 dprintf((LOG, "PE Optional header: "));
279 dprintf((LOG, "Preferred address : %d", oh.ImageBase ));
280 dprintf((LOG, "Base Of Code : %d", oh.BaseOfCode ));
281 dprintf((LOG, "CodeSize : %d", oh.SizeOfCode ));
282 dprintf((LOG, "Base Of Data : %d", oh.BaseOfData ));
283 dprintf((LOG, "Data Size (uninit): %d", oh.SizeOfUninitializedData ));
284 dprintf((LOG, "Data Size (init) : %d", oh.SizeOfInitializedData ));
285 dprintf((LOG, "Entry Point : %d", oh.AddressOfEntryPoint ));
286 dprintf((LOG, "Section Alignment : %d", oh.SectionAlignment ));
287 dprintf((LOG, "Stack Reserve size: %d", oh.SizeOfStackReserve ));
288 dprintf((LOG, "Stack Commit size : %d", oh.SizeOfStackCommit ));
289 dprintf((LOG, "SizeOfHeapReserve : %d", oh.SizeOfHeapReserve ));
290 dprintf((LOG, "SizeOfHeapCommit : %d", oh.SizeOfHeapCommit ));
291 dprintf((LOG, "FileAlignment : %d", oh.FileAlignment ));
292 dprintf((LOG, "Subsystem : %d", oh.Subsystem ));
293 dprintf((LOG, "Image Size : %d", oh.SizeOfImage ));
294 dprintf((LOG, "Header Size : %d", oh.SizeOfHeaders ));
295 dprintf((LOG, "MajorImageVersion : %d", oh.MajorImageVersion ));
296 dprintf((LOG, "MinorImageVersion : %d", oh.MinorImageVersion ));
297
298 //get header page
299 commitPage(realBaseAddress, FALSE);
300
301 nSections = NR_SECTIONS(win32file);
302
303 if(loadType == REAL_LOAD)
304 {
305 imageSize = 0;
306 if ((psh = (PIMAGE_SECTION_HEADER)SECTIONHDROFF (win32file)) != NULL) {
307 dprintf((LOG, "*************************PE SECTIONS START**************************" ));
308 for (i=0; i<nSections; i++) {
309 dprintf((LOG, "Raw data size: %x", psh[i].SizeOfRawData ));
310 dprintf((LOG, "Virtual Address: %x", psh[i].VirtualAddress ));
311 dprintf((LOG, "Virtual Address Start:%x", psh[i].VirtualAddress+oh.ImageBase ));
312 dprintf((LOG, "Virtual Address End: %x", psh[i].VirtualAddress+oh.ImageBase+psh[i].Misc.VirtualSize ));
313 dprintf((LOG, "Virtual Size: %x", psh[i].Misc.VirtualSize ));
314 dprintf((LOG, "Pointer to raw data: %x", psh[i].PointerToRawData ));
315 dprintf((LOG, "Section flags: %x\n\n", psh[i].Characteristics ));
316 if(strcmp(psh[i].Name, ".reloc") == 0) {
317 dprintf((LOG, ".reloc" ));
318 addSection(SECTION_RELOC, psh[i].PointerToRawData,
319 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
320 psh[i].Misc.VirtualSize, psh[i].Characteristics);
321 continue;
322 }
323 if(strcmp(psh[i].Name, ".edata") == 0) {
324 dprintf((LOG, ".edata" ));
325 addSection(SECTION_EXPORT, psh[i].PointerToRawData,
326 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
327 psh[i].Misc.VirtualSize, psh[i].Characteristics);
328 continue;
329 }
330 if(strcmp(psh[i].Name, ".rsrc") == 0) {
331 dprintf((LOG, ".rsrc" ));
332 addSection(SECTION_RESOURCE, psh[i].PointerToRawData,
333 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
334 psh[i].Misc.VirtualSize, psh[i].Characteristics);
335 continue;
336 }
337 if(strcmp(psh[i].Name, ".tls") == 0)
338 {
339 tlsDir = (IMAGE_TLS_DIRECTORY *)ImageDirectoryOffset(win32file, IMAGE_DIRECTORY_ENTRY_TLS);
340 if(tlsDir) {
341 addSection(SECTION_TLS, psh[i].PointerToRawData,
342 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
343 psh[i].Misc.VirtualSize, psh[i].Characteristics);
344 }
345 continue;
346 }
347
348 if(strcmp(psh[i].Name, ".debug") == 0) {
349 dprintf((LOG, ".rdebug" ));
350 addSection(SECTION_DEBUG, psh[i].PointerToRawData,
351 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
352 psh[i].Misc.VirtualSize, psh[i].Characteristics);
353 continue;
354 }
355 if(IsImportSection(win32file, &psh[i]))
356 {
357 int type = SECTION_IMPORT;
358 dprintf((LOG, "Import Data Section" ));
359 if(psh[i].Characteristics & IMAGE_SCN_CNT_CODE) {
360 dprintf((LOG, "Also Code Section"));
361 type |= SECTION_CODE;
362 }
363 addSection(type, psh[i].PointerToRawData,
364 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
365 psh[i].Misc.VirtualSize, psh[i].Characteristics);
366 continue;
367 }
368
369 //KSO Sun 1998-08-09: Borland does not alway set the CODE flag for its "CODE" section
370 if( psh[i].Characteristics & IMAGE_SCN_CNT_CODE ||
371 (psh[i].Characteristics & IMAGE_SCN_MEM_EXECUTE &&
372 !(psh[i].Characteristics & (IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_CNT_INITIALIZED_DATA))) //KSO: make sure its not marked as a datasection
373 )
374 {
375 dprintf((LOG, "Code Section"));
376 addSection(SECTION_CODE, psh[i].PointerToRawData,
377 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
378 psh[i].Misc.VirtualSize, psh[i].Characteristics);
379 continue;
380 }
381 if(!(psh[i].Characteristics & IMAGE_SCN_MEM_WRITE)) { //read only data section
382 dprintf((LOG, "Read Only Data Section" ));
383 addSection(SECTION_READONLYDATA, psh[i].PointerToRawData,
384 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
385 psh[i].Misc.VirtualSize, psh[i].Characteristics);
386 continue;
387 }
388 if(psh[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
389 dprintf((LOG, "Uninitialized Data Section" ));
390 addSection(SECTION_UNINITDATA, psh[i].PointerToRawData,
391 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
392 psh[i].Misc.VirtualSize, psh[i].Characteristics);
393 continue;
394 }
395 if(psh[i].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) {
396 dprintf((LOG, "Initialized Data Section" ));
397 addSection(SECTION_INITDATA, psh[i].PointerToRawData,
398 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
399 psh[i].Misc.VirtualSize, psh[i].Characteristics);
400 continue;
401 }
402 if(psh[i].Characteristics & (IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ)) {
403 dprintf((LOG, "Other Section, stored as read/write uninit data" ));
404 addSection(SECTION_UNINITDATA, psh[i].PointerToRawData,
405 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
406 psh[i].Misc.VirtualSize, psh[i].Characteristics);
407 continue;
408 }
409 dprintf((LOG, "Unknown section" ));
410 goto failure;
411 }
412 }
413 }
414 else {
415 if(GetSectionHdrByName (win32file, &sh, ".rsrc"))
416 {
417 addSection(SECTION_RESOURCE, sh.PointerToRawData,
418 sh.SizeOfRawData, sh.VirtualAddress + oh.ImageBase,
419 sh.Misc.VirtualSize, sh.Characteristics);
420 }
421 }
422 dprintf((LOG, "*************************PE SECTIONS END **************************" ));
423 imageSize += imageVirtBase - oh.ImageBase;
424 dprintf((LOG, "Total size of Image %x", imageSize ));
425 dprintf((LOG, "imageVirtBase %x", imageVirtBase ));
426 dprintf((LOG, "imageVirtEnd %x", imageVirtEnd ));
427
428 //In case there are any gaps between sections, adjust size
429 if(imageSize != imageVirtEnd - oh.ImageBase) {
430 dprintf((LOG, "imageSize != imageVirtEnd - oh.ImageBase!" ));
431 imageSize = imageVirtEnd - oh.ImageBase;
432 }
433 if(imageSize < oh.SizeOfImage) {
434 imageSize = oh.SizeOfImage;
435 }
436
437 dprintf((LOG, "OS/2 base address %x", realBaseAddress ));
438 if(oh.AddressOfEntryPoint) {
439 entryPoint = realBaseAddress + oh.AddressOfEntryPoint;
440 }
441 else {
442 dprintf((LOG, "EntryPoint == NULL" ));
443 entryPoint = NULL;
444 }
445
446 //set memory protection flags
447 if(setMemFlags() == FALSE) {
448 dprintf((LOG, "Failed to set memory protection" ));
449 goto failure;
450 }
451
452 if(loadType == REAL_LOAD)
453 {
454 if(tlsDir != NULL) {
455 Section *sect = findSection(SECTION_TLS);
456
457 if(sect == NULL) {
458 dprintf((LOG, "Couldn't find TLS section!!" ));
459 goto failure;
460 }
461 dprintf((LOG, "TLS Directory" ));
462 dprintf((LOG, "TLS Address of Index %x", tlsDir->AddressOfIndex ));
463 dprintf((LOG, "TLS Address of Callbacks %x", tlsDir->AddressOfCallBacks ));
464 dprintf((LOG, "TLS SizeOfZeroFill %x", tlsDir->SizeOfZeroFill ));
465 dprintf((LOG, "TLS Characteristics %x", tlsDir->Characteristics ));
466 setTLSAddress((char *)sect->realvirtaddr);
467 setTLSInitSize(tlsDir->EndAddressOfRawData - tlsDir->StartAddressOfRawData);
468 setTLSTotalSize(tlsDir->EndAddressOfRawData - tlsDir->StartAddressOfRawData + tlsDir->SizeOfZeroFill);
469
470 sect = findSectionByAddr((ULONG)tlsDir->AddressOfIndex);
471 if(sect == NULL) {
472 dprintf((LOG, "Couldn't find TLS AddressOfIndex section!!" ));
473 goto failure;
474 }
475 setTLSIndexAddr((LPDWORD)(sect->realvirtaddr + ((ULONG)tlsDir->AddressOfIndex - sect->virtaddr)));
476
477 if((ULONG)tlsDir->AddressOfCallBacks != 0) {
478 sect = findSectionByAddr((ULONG)tlsDir->AddressOfCallBacks);
479 if(sect == NULL) {
480 dprintf((LOG, "Couldn't find TLS AddressOfCallBacks section!!" ));
481 goto failure;
482 }
483 setTLSCallBackAddr((PIMAGE_TLS_CALLBACK *)(sect->realvirtaddr + ((ULONG)tlsDir->AddressOfCallBacks - sect->virtaddr)));
484 }
485 }
486
487 if(realBaseAddress != oh.ImageBase) {
488 pFixups = (PIMAGE_BASE_RELOCATION)ImageDirectoryOffset(win32file, IMAGE_DIRECTORY_ENTRY_BASERELOC);
489 commitPage((ULONG)pFixups, FALSE);
490 }
491#ifdef COMMIT_ALL
492 for (i=0; i<nSections; i++) {
493 commitPage((ULONG)section[i].realvirtaddr, FALSE, COMPLETE_SECTION);
494 }
495#else
496 for (i=0; i<nSections; i++) {
497 switch(section[i].type)
498 {
499 case SECTION_IMPORT:
500 case SECTION_RELOC:
501 case SECTION_EXPORT:
502 commitPage((ULONG)section[i].realvirtaddr, FALSE, COMPLETE_SECTION);
503 break;
504 }
505 }
506#endif
507 if(processExports((char *)win32file) == FALSE) {
508 dprintf((LOG, "Failed to process exported apis" ));
509 goto failure;
510 }
511 }
512#ifdef COMMIT_ALL
513 else {
514 commitPage((ULONG)section[0].realvirtaddr, FALSE, COMPLETE_SECTION);
515 }
516#endif
517
518 //SvL: Use pointer to image header as module handle now. Some apps needs this
519 hinstance = (HINSTANCE)realBaseAddress;
520
521 //SvL: Set instance handle in process database structure
522 SetPDBInstance(hinstance);
523
524 //PH: get pResDir pointer correct first, since processImports may
525 // implicitly call functions depending on it.
526 if(GetSectionHdrByName (win32file, &sh, ".rsrc")) {
527 //get offset in resource object of directory entry
528 pResDir = (PIMAGE_RESOURCE_DIRECTORY)(sh.VirtualAddress + realBaseAddress);
529 ulRVAResourceSection = sh.VirtualAddress;
530 }
531
532 if (loadType == REAL_LOAD)
533 {
534 if(processImports((char *)win32file) == FALSE) {
535 dprintf((LOG, "Failed to process imports!" ));
536 goto failure;
537 }
538 }
539
540 return(TRUE);
541failure:
542 if(memmap) {
543 delete memmap;
544 memmap = NULL;
545 }
546 if(hFile) {
547 OSLibDosClose(hFile);
548 hFile = 0;
549 }
550 errorState = ERROR_INTERNAL;
551 return FALSE;
552}
553//******************************************************************************
554//commits image page(s) when an access violation exception is dispatched
555//virtAddress = address of exception (rounded down to page boundary)
556//******************************************************************************
557BOOL Win32PeLdrImage::commitPage(ULONG virtAddress, BOOL fWriteAccess, int fPageCmd)
558{
559 Section *section;
560 ULONG offset, size, sectionsize, protflags, fileoffset, range, attr;
561 ULONG ulNewPos, ulRead;
562 APIRET rc;
563
564 rc = DosQueryMem((PVOID)virtAddress, &range, &attr);
565 if(rc) {
566 dprintf((LOG, "Win32PeLdrImage::commitPage: DosQueryMem for %x returned %d", virtAddress, rc));
567 return FALSE;
568 }
569 if(attr & PAG_COMMIT) {
570 dprintf((LOG, "Win32PeLdrImage::commitPage: Memory at 0x%x already committed!", virtAddress));
571 return FALSE;
572 }
573
574 section = findSectionByOS2Addr(virtAddress);
575 if(section == NULL) {
576 size = 4096;
577 sectionsize = 4096;
578 protflags = PAG_READ|PAG_WRITE; //readonly?
579 section = findPreviousSectionByOS2Addr(virtAddress);
580 if(section == NULL) {//access to header
581 fileoffset = virtAddress - realBaseAddress;
582 }
583 else {
584 offset = virtAddress - (section->realvirtaddr + section->virtualsize);
585 fileoffset = section->rawoffset + section->rawsize + offset;
586 }
587 }
588 else {
589 protflags = section->pageflags;
590 offset = virtAddress - section->realvirtaddr;
591 sectionsize = section->virtualsize - offset;
592 if(offset > section->rawsize || section->type == SECTION_UNINITDATA) {
593 //unintialized data (set to 0)
594 size = 0;
595 fileoffset = -1;
596 }
597 else {
598 size = section->rawsize-offset;
599 fileoffset = section->rawoffset + offset;
600 }
601 if(fWriteAccess & !(section->pageflags & PAG_WRITE)) {
602 dprintf((LOG, "Win32PeLdrImage::commitPage: No write access to 0%x!", virtAddress));
603 return FALSE;
604 }
605 }
606 if(fPageCmd == SINGLE_PAGE) {
607 size = min(size, PAGE_SIZE);
608 sectionsize = min(sectionsize, PAGE_SIZE);
609 }
610 else
611 if(fPageCmd == SECTION_PAGES) {
612 size = min(size, DEFAULT_NR_PAGES*PAGE_SIZE);
613 sectionsize = min(sectionsize, DEFAULT_NR_PAGES*PAGE_SIZE);
614 }
615 size = min(size, range);
616 sectionsize = min(sectionsize, range);
617
618 if(fileoffset != -1) {
619 rc = DosSetMem((PVOID)virtAddress, sectionsize, PAG_READ|PAG_WRITE|PAG_COMMIT);
620 if(rc) {
621 dprintf((LOG, "Win32PeLdrImage::commitPage: DosSetMem failed (%d)!", rc));
622 return FALSE;
623 }
624
625 if(DosSetFilePtr(hFile, fileoffset, FILE_BEGIN, &ulNewPos) == -1) {
626 dprintf((LOG, "Win32PeLdrImage::commitPage: DosSetFilePtr failed for 0x%x!", fileoffset));
627 return FALSE;
628 }
629 if(DosRead(hFile, (PVOID)virtAddress, size, &ulRead)) {
630 dprintf((LOG, "Win32PeLdrImage::commitPage: DosRead failed for 0x%x!", virtAddress));
631 return FALSE;
632 }
633 if(ulRead != size) {
634 dprintf((LOG, "Win32PeLdrImage::commitPage: DosRead failed to read %x (%x) bytes at %x for 0x%x!", size, ulRead, fileoffset, virtAddress));
635 return FALSE;
636 }
637 if(realBaseAddress != oh.ImageBase) {
638 setFixups(virtAddress, sectionsize);
639 }
640
641 rc = DosSetMem((PVOID)virtAddress, sectionsize, protflags);
642 if(rc) {
643 dprintf((LOG, "Win32PeLdrImage::commitPage: DosSetMem failed (%d)!", rc));
644 return FALSE;
645 }
646 }
647 else {
648 rc = DosSetMem((PVOID)virtAddress, sectionsize, PAG_READ|PAG_WRITE|PAG_COMMIT);
649 if(rc) {
650 dprintf((LOG, "Win32PeLdrImage::commitPage: DosSetMem failed (%d)!", rc));
651 return FALSE;
652 }
653 if(realBaseAddress != oh.ImageBase) {
654 setFixups(virtAddress, sectionsize);
655 }
656 rc = DosSetMem((PVOID)virtAddress, sectionsize, protflags);
657 if(rc) {
658 dprintf((LOG, "Win32PeLdrImage::commitPage: DosSetMem failed (%d)!", rc));
659 return FALSE;
660 }
661 }
662 return TRUE;
663}
664//******************************************************************************
665//******************************************************************************
666void Win32PeLdrImage::addSection(ULONG type, ULONG rawoffset, ULONG rawsize, ULONG virtaddress, ULONG virtsize, ULONG flags)
667{
668 virtsize = max(rawsize, virtsize);
669
670 section[nrsections].rawoffset = rawoffset;
671 section[nrsections].type = type;
672 section[nrsections].rawsize = rawsize;
673 section[nrsections].virtaddr = virtaddress;
674 section[nrsections].flags = flags;
675
676 virtsize = ((virtsize - 1) & ~0xFFF) + PAGE_SIZE;
677 imageSize += virtsize;
678 section[nrsections].virtualsize = virtsize;
679
680 if(virtaddress < imageVirtBase)
681 imageVirtBase = virtaddress;
682 if(virtaddress + virtsize > imageVirtEnd)
683 imageVirtEnd = virtaddress + virtsize;
684
685 nrsections++;
686}
687//******************************************************************************
688//******************************************************************************
689BOOL Win32PeLdrImage::allocSections(ULONG reservedMem)
690{
691 APIRET rc;
692 ULONG baseAddress;
693
694 //SvL: We don't care where the image is loaded for resource lookup
695 if(fh.Characteristics & IMAGE_FILE_RELOCS_STRIPPED && loadType == REAL_LOAD) {
696 return allocFixedMem(reservedMem);
697 }
698 rc = DosAllocMem((PPVOID)&baseAddress, imageSize, PAG_READ | PAG_WRITE | flAllocMem);
699 if(rc) {
700 dprintf((LOG, "Win32PeLdrImage::allocSections, DosAllocMem returned %d", rc));
701 errorState = rc;
702 return(FALSE);
703 }
704 realBaseAddress = baseAddress;
705 return(TRUE);
706}
707//******************************************************************************
708//******************************************************************************
709Section *Win32PeLdrImage::findSection(ULONG type)
710{
711 for(int i=0;i<nrsections;i++) {
712 if(section[i].type == type) {
713 return &section[i];
714 }
715 }
716 return NULL;
717}
718//******************************************************************************
719//******************************************************************************
720Section *Win32PeLdrImage::findSectionByAddr(ULONG addr)
721{
722 for(int i=0;i<nrsections;i++) {
723 if(section[i].virtaddr <= addr && section[i].virtaddr + section[i].virtualsize > addr) {
724 return &section[i];
725 }
726 }
727 return NULL;
728}
729//******************************************************************************
730//******************************************************************************
731Section *Win32PeLdrImage::findSectionByOS2Addr(ULONG addr)
732{
733 for(int i=0;i<nrsections;i++) {
734 if(section[i].realvirtaddr <= addr && section[i].realvirtaddr + section[i].virtualsize > addr) {
735 return &section[i];
736 }
737 }
738 return NULL;
739}
740//******************************************************************************
741//******************************************************************************
742Section *Win32PeLdrImage::findPreviousSectionByOS2Addr(ULONG addr)
743{
744 ULONG lowestAddr = 0xffffffff;
745 ULONG index = -1;
746
747 for(int i=0;i<nrsections;i++) {
748 if(section[i].realvirtaddr > addr) {
749 if(section[i].realvirtaddr < lowestAddr) {
750 lowestAddr = section[i].realvirtaddr;
751 index = i;
752 }
753 }
754 }
755 if(index == -1)
756 return NULL;
757
758 return &section[index];
759}
760//******************************************************************************
761#define FALLOC_SIZE (1024*1024)
762//NOTE: Needs testing (while loop)
763//TODO: Free unused (parts of) reservedMem
764//******************************************************************************
765BOOL Win32PeLdrImage::allocFixedMem(ULONG reservedMem)
766{
767 ULONG address = 0;
768 ULONG *memallocs;
769 ULONG alloccnt = 0;
770 ULONG diff, i, baseAddress;
771 APIRET rc;
772 BOOL allocFlags = flAllocMem;
773
774 realBaseAddress = 0;
775
776#if 1
777 //Allocated in peldr.dll
778 if(reservedMem && reservedMem == oh.ImageBase) {
779 realBaseAddress = oh.ImageBase;
780 return TRUE;
781 }
782#else
783 if(reservedMem && reservedMem <= oh.ImageBase &&
784 ((oh.ImageBase - reservedMem) + imageSize < PELDR_RESERVEDMEMSIZE))
785 {
786 //ok, it fits perfectly; free it now and allocate it below
787 DosFreeMem((PVOID)reservedMem);
788// realBaseAddress = oh.ImageBase;
789// return TRUE;
790 }
791#endif
792
793 //Reserve enough space to store 4096 pointers to 1MB memory chunks
794 memallocs = (ULONG *)malloc(4096*sizeof(ULONG *));
795 if(memallocs == NULL) {
796 dprintf((LOG, "allocFixedMem: MALLOC FAILED for memallocs" ));
797 return FALSE;
798 }
799
800 if(oh.ImageBase < 512*1024*124) {
801 allocFlags = 0;
802 }
803 while(TRUE) {
804 rc = DosAllocMem((PPVOID)&address, FALLOC_SIZE, PAG_READ | allocFlags);
805 if(rc) break;
806
807 dprintf((LOG, "DosAllocMem returned %x", address ));
808 if(address + FALLOC_SIZE >= oh.ImageBase) {
809 if(address > oh.ImageBase) {//we've passed it!
810 DosFreeMem((PVOID)address);
811 break;
812 }
813 //found the right address
814 DosFreeMem((PVOID)address);
815
816 diff = oh.ImageBase - address;
817 if(diff) {
818 rc = DosAllocMem((PPVOID)&address, diff, PAG_READ | allocFlags);
819 if(rc) break;
820 }
821 rc = DosAllocMem((PPVOID)&baseAddress, imageSize, PAG_READ | PAG_WRITE | allocFlags);
822 if(rc) break;
823
824 if(diff) DosFreeMem((PVOID)address);
825
826 realBaseAddress = baseAddress;
827 break;
828 }
829 memallocs[alloccnt++] = address;
830 }
831 for(i=0;i<alloccnt;i++) {
832 DosFreeMem((PVOID)memallocs[i]);
833 }
834 free(memallocs);
835
836 if(realBaseAddress == 0) //Let me guess.. MS Office app?
837 return(FALSE);
838
839 return(TRUE);
840}
841//******************************************************************************
842//******************************************************************************
843BOOL Win32PeLdrImage::setMemFlags()
844{
845 int i;
846 WINIMAGE_LOOKUP *imgLookup;
847
848 imgLookup = WINIMAGE_LOOKUPADDR(realBaseAddress);
849 imgLookup->magic1 = MAGIC_WINIMAGE;
850 imgLookup->image = this;
851 imgLookup->magic2 = MAGIC_WINIMAGE;
852
853 // Process all the image sections
854 for(i=0;i<nrsections;i++) {
855 section[i].realvirtaddr = realBaseAddress + (section[i].virtaddr - oh.ImageBase);
856 }
857
858 for(i=0;i<nrsections;i++) {
859 switch(section[i].type)
860 {
861 case SECTION_CODE:
862 case (SECTION_CODE | SECTION_IMPORT):
863 section[i].pageflags = PAG_EXECUTE | PAG_READ;
864 if(section[i].flags & IMAGE_SCN_MEM_WRITE)
865 section[i].pageflags |= PAG_WRITE;
866 break;
867 case SECTION_INITDATA:
868 case SECTION_UNINITDATA:
869 case SECTION_IMPORT: //TODO: read only?
870 section[i].pageflags = PAG_WRITE | PAG_READ;
871 break;
872 case SECTION_READONLYDATA:
873 case SECTION_RESOURCE:
874 case SECTION_TLS:
875 default:
876 section[i].pageflags = PAG_READ;
877 break;
878 }
879 }
880 return(TRUE);
881}
882//******************************************************************************
883//******************************************************************************
884BOOL Win32PeLdrImage::setFixups(ULONG virtAddress, ULONG size)
885{
886 int i, j;
887 char *page;
888 ULONG count, newpage;
889 Section *section;
890 PIMAGE_BASE_RELOCATION prel = pFixups;
891
892 if(fh.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) {
893 return(TRUE);
894 }
895
896 virtAddress -= realBaseAddress;
897
898 if(prel) {
899 j = 1;
900 while(prel->VirtualAddress && prel->VirtualAddress < virtAddress) {
901 prel = (PIMAGE_BASE_RELOCATION)((char*)prel + prel->SizeOfBlock);
902 }
903 while(prel->VirtualAddress && prel->VirtualAddress < virtAddress + size) {
904 page = (char *)((char *)prel + (ULONG)prel->VirtualAddress);
905 count = (prel->SizeOfBlock - 8)/2;
906 j++;
907 for(i=0;i<count;i++) {
908 int type = prel->TypeOffset[i] >> 12;
909 int offset = prel->TypeOffset[i] & 0xFFF;
910 int fixupsize = 0;
911
912 switch(type)
913 {
914 case IMAGE_REL_BASED_HIGHLOW:
915 fixupsize = 4;
916 break;
917 case IMAGE_REL_BASED_HIGH:
918 case IMAGE_REL_BASED_LOW:
919 fixupsize = 2;
920 break;
921 }
922 //If the fixup crosses the final page boundary,
923 //then we have to load another page
924 if(prel->VirtualAddress + offset + fixupsize > virtAddress + size)
925 {
926 newpage = realBaseAddress + prel->VirtualAddress + offset + fixupsize;
927 newpage &= ~0xFFF;
928
929 section = findSectionByOS2Addr(newpage);
930 if(section == NULL) {
931 //should never happen
932 dprintf((LOG, "::setFixups -> section == NULL!!"));
933 return FALSE;
934 }
935 //SvL: Read page from disk
936 commitPage(newpage, FALSE, SINGLE_PAGE);
937
938 //SvL: Enable write access
939 DosSetMem((PVOID)newpage, PAGE_SIZE, PAG_READ|PAG_WRITE);
940 }
941
942 switch(type)
943 {
944 case IMAGE_REL_BASED_ABSOLUTE:
945 break; //skip
946 case IMAGE_REL_BASED_HIGHLOW:
947 AddOff32Fixup(prel->VirtualAddress + offset);
948 break;
949 case IMAGE_REL_BASED_HIGH:
950 AddOff16Fixup(prel->VirtualAddress + offset, TRUE);
951 break;
952 case IMAGE_REL_BASED_LOW:
953 AddOff16Fixup(prel->VirtualAddress + offset, FALSE);
954 break;
955 case IMAGE_REL_BASED_HIGHADJ:
956 case IMAGE_REL_BASED_MIPS_JMPADDR:
957 default:
958 break;
959 }
960 if(prel->VirtualAddress + offset + fixupsize > virtAddress + size)
961 {
962 //SvL: Restore original page protection flags
963 DosSetMem((PVOID)newpage, PAGE_SIZE, section->pageflags);
964 }
965
966 }
967 prel = (PIMAGE_BASE_RELOCATION)((char*)prel + prel->SizeOfBlock);
968 }//while
969 }
970 else {
971 dprintf((LOG, "Win32PeLdrImage::setFixups, no fixups at %x, %d", virtAddress, size));
972 return(FALSE);
973 }
974 return(TRUE);
975}
976//******************************************************************************
977//******************************************************************************
978BOOL Win32PeLdrImage::setFixups(PIMAGE_BASE_RELOCATION prel)
979{
980 int i, j;
981 char *page;
982 ULONG count;
983
984 if(fh.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) {
985 return(TRUE);
986 }
987
988 if(prel) {
989 j = 1;
990 while(prel->VirtualAddress) {
991 page = (char *)((char *)prel + (ULONG)prel->VirtualAddress);
992 count = (prel->SizeOfBlock - 8)/2;
993 dprintf((LOG, "Page %d Address %x Count %d", j, prel->VirtualAddress, count ));
994 j++;
995 for(i=0;i<count;i++) {
996 int type = prel->TypeOffset[i] >> 12;
997 int offset = prel->TypeOffset[i] & 0xFFF;
998 switch(type) {
999 case IMAGE_REL_BASED_ABSOLUTE:
1000//// dprintf((LOG, "absolute fixup; unused" ));
1001 break; //skip
1002 case IMAGE_REL_BASED_HIGHLOW:
1003//// dprintf((LOG, "address ", offset << " type ", type ));
1004 AddOff32Fixup(prel->VirtualAddress + offset);
1005 break;
1006 case IMAGE_REL_BASED_HIGH:
1007 AddOff16Fixup(prel->VirtualAddress + offset, TRUE);
1008 break;
1009 case IMAGE_REL_BASED_LOW:
1010 AddOff16Fixup(prel->VirtualAddress + offset, FALSE);
1011 break;
1012 case IMAGE_REL_BASED_HIGHADJ:
1013 case IMAGE_REL_BASED_MIPS_JMPADDR:
1014 default:
1015 dprintf((LOG, "Unknown/unsupported fixup type!" ));
1016 break;
1017 }
1018 }
1019 prel = (PIMAGE_BASE_RELOCATION)((char*)prel + prel->SizeOfBlock);
1020 }//while
1021 }
1022 else {
1023 dprintf((LOG, "No internal fixups found!" ));
1024 errorState = ERROR_INTERNAL;
1025 return(FALSE);
1026 }
1027 return(TRUE);
1028}
1029//******************************************************************************
1030//******************************************************************************
1031void Win32PeLdrImage::AddOff32Fixup(ULONG fixupaddr)
1032{
1033 ULONG orgaddr;
1034 ULONG *fixup;
1035
1036 fixup = (ULONG *)(fixupaddr + realBaseAddress);
1037 orgaddr = *fixup;
1038// dprintf((LOG, "AddOff32Fixup 0x%x org 0x%x -> new 0x%x", fixup, orgaddr, realBaseAddress + (*fixup - oh.ImageBase)));
1039 *fixup = realBaseAddress + (*fixup - oh.ImageBase);
1040}
1041//******************************************************************************
1042//******************************************************************************
1043void Win32PeLdrImage::AddOff16Fixup(ULONG fixupaddr, BOOL fHighFixup)
1044{
1045 ULONG orgaddr;
1046 USHORT *fixup;
1047
1048 fixup = (USHORT *)(fixupaddr + realBaseAddress);
1049 orgaddr = *fixup;
1050 if(fHighFixup) {
1051 *fixup += (USHORT)((realBaseAddress - oh.ImageBase) >> 16);
1052// dprintf((LOG, "AddOff16FixupH 0x%x org 0x%x -> new 0x%x", fixup, orgaddr, *fixup));
1053 }
1054 else {
1055 *fixup += (USHORT)((realBaseAddress - oh.ImageBase) & 0xFFFF);
1056// dprintf((LOG, "AddOff16FixupL 0x%x org 0x%x -> new 0x%x", fixup, orgaddr, *fixup));
1057 }
1058}
1059//******************************************************************************
1060//******************************************************************************
1061void Win32PeLdrImage::StoreImportByOrd(Win32DllBase *WinDll, ULONG ordinal, ULONG impaddr)
1062{
1063 ULONG *import;
1064 ULONG apiaddr;
1065
1066 import = (ULONG *)impaddr;
1067 apiaddr = WinDll->getApi(ordinal);
1068 if(apiaddr == 0)
1069 {
1070 dprintf((LOG, "KERNEL32:Win32PeLdrImage - %s.%u not found\n",
1071 WinDll->getName(),
1072 ordinal));
1073
1074 dprintf((LOG, "--->>> NOT FOUND!" ));
1075 *import = (ULONG)MissingApi;
1076 }
1077 else *import = apiaddr;
1078}
1079//******************************************************************************
1080//******************************************************************************
1081void Win32PeLdrImage::StoreImportByName(Win32DllBase *WinDll, char *impname, ULONG impaddr)
1082{
1083 ULONG *import;
1084 ULONG apiaddr;
1085
1086 import = (ULONG *)impaddr;
1087 apiaddr = WinDll->getApi(impname);
1088 if(apiaddr == 0)
1089 {
1090 dprintf((LOG, "KERNEL32:Win32PeLdrImage - %s.%s not found\n",
1091 WinDll->getName(),
1092 impname));
1093
1094 dprintf((LOG, "--->>> NOT FOUND!" ));
1095 *import = (ULONG)MissingApi;
1096 }
1097 else *import = apiaddr;
1098}
1099//******************************************************************************
1100//******************************************************************************
1101BOOL Win32PeLdrImage::processExports(char *win32file)
1102{
1103 IMAGE_SECTION_HEADER sh;
1104 PIMAGE_EXPORT_DIRECTORY ped;
1105 ULONG *ptrNames, *ptrAddress;
1106 USHORT *ptrOrd;
1107 int i;
1108
1109 /* get section header and pointer to data directory for .edata section */
1110 if((ped = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryOffset
1111 (win32file, IMAGE_DIRECTORY_ENTRY_EXPORT)) != NULL &&
1112 GetSectionHdrByImageDir(win32file, IMAGE_DIRECTORY_ENTRY_EXPORT, &sh) ) {
1113
1114 dprintf((LOG, "Exported Functions: " ));
1115 ptrOrd = (USHORT *)((ULONG)ped->AddressOfNameOrdinals +
1116 (ULONG)win32file);
1117 ptrNames = (ULONG *)((ULONG)ped->AddressOfNames +
1118 (ULONG)win32file);
1119 ptrAddress = (ULONG *)((ULONG)ped->AddressOfFunctions +
1120 (ULONG)win32file);
1121 nrOrdExports = ped->NumberOfFunctions;
1122 nrNameExports = ped->NumberOfNames;
1123
1124 int ord, RVAExport;
1125 char *name;
1126 for(i=0;i<ped->NumberOfNames;i++) {
1127 ord = ptrOrd[i] + ped->Base;
1128 name = (char *)((ULONG)ptrNames[i] + (ULONG)win32file);
1129 RVAExport = ptrAddress[ptrOrd[i]];
1130#ifdef FORWARDERS
1131 if(RVAExport < sh.VirtualAddress || RVAExport > sh.VirtualAddress + sh.SizeOfRawData) {
1132#endif
1133 //points to code (virtual address relative to oh.ImageBase
1134 AddNameExport(oh.ImageBase + RVAExport, name, ord);
1135 dprintf((LOG, "address 0x%x %s @%d", RVAExport, name, ord));
1136#ifdef FORWARDERS
1137
1138 }
1139 else {//forwarder
1140 char *forward = (char *)((ULONG)RVAExport + (ULONG)win32file);
1141 fout << RVAExport << " ", name << " @", ord << " is forwarder to ", (int)forward ));
1142 }
1143#endif
1144 }
1145 for(i=0;i<max(ped->NumberOfNames,ped->NumberOfFunctions);i++) {
1146 ord = ped->Base + i; //Correct??
1147 RVAExport = ptrAddress[i];
1148#ifdef FORWARDERS
1149 if(RVAExport < sh.VirtualAddress || RVAExport > sh.VirtualAddress + sh.SizeOfRawData) {
1150#endif
1151 if(RVAExport) {
1152 //points to code (virtual address relative to oh.ImageBase
1153 dprintf((LOG, "ord %d at 0x%x", ord, RVAExport));
1154 AddOrdExport(oh.ImageBase + RVAExport, ord);
1155 }
1156#ifdef FORWARDERS
1157 }
1158 else {//forwarder or empty
1159 char *forward = (char *)((ULONG)RVAExport + (ULONG)win32file);
1160 dprintf((LOG, "ord ", ord << " at 0x";
1161 fout << RVAExport << " is forwarder to 0x", (int)forward ));
1162 }
1163#endif
1164 }
1165 }
1166 return(TRUE);
1167}
1168//******************************************************************************
1169//******************************************************************************
1170void Win32PeLdrImage::AddNameExport(ULONG virtaddr, char *apiname, ULONG ordinal)
1171{
1172 ULONG nsize;
1173
1174 if(nameexports == NULL) {
1175 nameExportSize= 4096;
1176 nameexports = (NameExport *)malloc(nameExportSize);
1177 curnameexport = nameexports;
1178 }
1179 nsize = (ULONG)curnameexport - (ULONG)nameexports;
1180 if(nsize + sizeof(NameExport) + strlen(apiname) > nameExportSize) {
1181 nameExportSize += 4096;
1182 char *tmp = (char *)nameexports;
1183 nameexports = (NameExport *)malloc(nameExportSize);
1184 memcpy(nameexports, tmp, nsize);
1185 curnameexport = (NameExport *)((ULONG)nameexports + nsize);
1186 free(tmp);
1187 }
1188 curnameexport->virtaddr = realBaseAddress + (virtaddr - oh.ImageBase);
1189 curnameexport->ordinal = ordinal;
1190 *(ULONG *)curnameexport->name = 0;
1191 strcpy(curnameexport->name, apiname);
1192
1193 curnameexport->nlength = strlen(apiname) + 1;
1194 if(curnameexport->nlength < sizeof(curnameexport->name))
1195 curnameexport->nlength = sizeof(curnameexport->name);
1196
1197 curnameexport = (NameExport *)((ULONG)curnameexport->name + curnameexport->nlength);
1198}
1199//******************************************************************************
1200//******************************************************************************
1201void Win32PeLdrImage::AddOrdExport(ULONG virtaddr, ULONG ordinal)
1202{
1203 if(ordexports == NULL) {
1204 ordexports = (OrdExport *)malloc(nrOrdExports * sizeof(OrdExport));
1205 curordexport = ordexports;
1206 }
1207 curordexport->virtaddr = realBaseAddress + (virtaddr - oh.ImageBase);
1208 curordexport->ordinal = ordinal;
1209 curordexport++;
1210}
1211//******************************************************************************
1212/** All initial processing of imports is done here
1213 * Should now detect most Borland styled files including the GifCon32.exe and
1214 * loader32 from SoftIce. (Stupid Borland!!!)
1215 *
1216 * knut [Jul 22 1998 2:44am]
1217 **/
1218//******************************************************************************
1219BOOL Win32PeLdrImage::processImports(char *win32file)
1220{
1221 PIMAGE_IMPORT_DESCRIPTOR pID;
1222 IMAGE_SECTION_HEADER shID;
1223 IMAGE_SECTION_HEADER shExtra = {0};
1224 PIMAGE_OPTIONAL_HEADER pOH;
1225 int i,j, nrPages;
1226 BOOL fBorland = 0;
1227 int cModules;
1228 char *pszModules;
1229 char *pszCurModule;
1230 char *pszTmp;
1231 ULONG *pulImport;
1232 ULONG ulCurFixup;
1233 int Size;
1234 Win32PeLdrDll *WinDll;
1235 Section *section;
1236
1237/* "algorithm:"
1238 * 1) get module names and store them
1239 * a) check dwRVAModuleName is within .idata seg - if not find section
1240 * 2) iterate thru functions of each module
1241 * a) check OriginalFirstThunk is not 0 and that it points to a RVA.
1242 * b) if not a) borland-styled PE-file - ARG!!!
1243 * check FirstThunk
1244 * c) check OriginalFirstThunk/FirstThunk ok RVAs and find right section
1245 * d) store ordinal/name import
1246 * 3) finished
1247 */
1248
1249 /* 1) get module names */
1250 pID = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryOffset(win32file, IMAGE_DIRECTORY_ENTRY_IMPORT);
1251 if (pID == NULL)
1252 return TRUE;
1253 if (!GetSectionHdrByImageDir(win32file, IMAGE_DIRECTORY_ENTRY_IMPORT, &shID))
1254 return TRUE;
1255
1256 //calc size of module list
1257 i = Size = cModules = 0;
1258 while (pID[i].Name != 0)
1259 {
1260 //test RVA inside ID-Section
1261 if (pID[i].Name >= shID.VirtualAddress && pID[i].Name < shID.VirtualAddress + max(shID.Misc.VirtualSize, shID.SizeOfRawData)) {
1262 pszTmp = (char*)(pID[i].Name + (ULONG)win32file);
1263 }
1264 else {
1265 //is the "Extra"-section already found or do we have to find it?
1266 if (pID[i].Name < shExtra.VirtualAddress || pID[i].Name >= shExtra.VirtualAddress + max(shExtra.Misc.VirtualSize, shExtra.SizeOfRawData)) {
1267 if (!GetSectionHdrByRVA(win32file, &shExtra, pID[i].Name))
1268 return FALSE;
1269 }
1270 pszTmp = (char*)(pID[i].Name + (ULONG)win32file);
1271 }
1272 Size += strlen(pszTmp) + 1;
1273 i++;
1274 cModules++;
1275 }
1276
1277 pszModules = (char*)malloc(Size);
1278 assert(pszModules != NULL);
1279 j = 0;
1280 for (i = 0; i < cModules; i++)
1281 {
1282 //test RVA inside ID-Section
1283 if (pID[i].Name >= shID.VirtualAddress && pID[i].Name < shID.VirtualAddress + max(shID.Misc.VirtualSize, shID.SizeOfRawData)) {
1284 pszTmp = (char*)(pID[i].Name + (ULONG)win32file);
1285 }
1286 else {
1287 fBorland = TRUE;
1288 //is the "Extra"-section already found or do we have to find it?
1289 if (pID[i].Name < shExtra.VirtualAddress || pID[i].Name >= shExtra.VirtualAddress + max(shExtra.Misc.VirtualSize, shExtra.SizeOfRawData))
1290 {
1291 if (GetSectionHdrByRVA(win32file, &shExtra, pID[i].Name)) {
1292 free(pszModules);
1293 return FALSE;
1294 }
1295 }
1296 pszTmp = (char*)(pID[i].Name + (ULONG)win32file);
1297 }
1298
1299 strcpy(pszModules+j, pszTmp);
1300 j += strlen(pszTmp) + 1;
1301 }
1302 if (fBorland)
1303 dprintf((LOG, "Borland-styled PE-File." ));
1304 //Store modules
1305 dprintf((LOG, "%d imported Modules: ", cModules ));
1306
1307 /* 2) functions */
1308 pszCurModule = pszModules;
1309 pOH = (PIMAGE_OPTIONAL_HEADER)OPTHEADEROFF(win32file);
1310 for (i = 0; i < cModules; i++)
1311 {
1312 dprintf((LOG, "Module %s", pszCurModule ));
1313 // a) check that OriginalFirstThunk not is 0 and look for Borland-styled PE
1314 if (i == 0)
1315 {
1316 //heavy borland-style test - assume array of thunks is within that style does not change
1317 if((ULONG)pID[i].u.OriginalFirstThunk == 0 ||
1318 (ULONG)pID[i].u.OriginalFirstThunk < shID.VirtualAddress ||
1319 (ULONG)pID[i].u.OriginalFirstThunk >= shID.VirtualAddress + max(shID.Misc.VirtualSize, shID.SizeOfRawData) ||
1320 (ULONG)pID[i].u.OriginalFirstThunk >= pOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress &&
1321 (ULONG)pID[i].u.OriginalFirstThunk < sizeof(*pID)*cModules + pOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
1322 {
1323 fBorland = TRUE;
1324 }
1325 }
1326 //light borland-style test
1327 if (pID[i].u.OriginalFirstThunk == 0 || fBorland) {
1328 pulImport = (ULONG*)pID[i].FirstThunk;
1329 }
1330 else pulImport = (ULONG*)pID[i].u.OriginalFirstThunk;
1331
1332 // b) check if RVA ok
1333 if (!(pulImport > 0 && (ULONG)pulImport < pOH->SizeOfImage)) {
1334 dprintf((LOG, "Invalid RVA %x", pulImport ));
1335 break;
1336 }
1337 // check section
1338 if ((ULONG)pulImport < shExtra.VirtualAddress || (ULONG)pulImport >= shExtra.VirtualAddress + max(shExtra.Misc.VirtualSize, shExtra.SizeOfRawData))
1339 {
1340 if (!GetSectionHdrByRVA(win32file, &shExtra, (ULONG)pulImport))
1341 {
1342 dprintf((LOG, "warning: could not find section for Thunk RVA %x", pulImport ));
1343 break;
1344 }
1345 }
1346
1347 //SvL: Load dll if needed
1348 dprintf((LOG, "**********************************************************************" ));
1349 dprintf((LOG, "************** Import Module %s ", pszCurModule ));
1350 dprintf((LOG, "**********************************************************************" ));
1351 WinDll = (Win32PeLdrDll *)Win32DllBase::findModule(pszCurModule);
1352
1353 if(WinDll == NULL)
1354 { //not found, so load it
1355 char modname[CCHMAXPATH];
1356
1357 strcpy(modname, pszCurModule);
1358 //rename dll if necessary (i.e. OLE32 -> OLE32OS2)
1359 Win32DllBase::renameDll(modname);
1360
1361 if(isPEImage(modname) == FALSE)
1362 {//LX image, so let OS/2 do all the work for us
1363 APIRET rc;
1364 char szModuleFailure[CCHMAXPATH] = "";
1365 ULONG hInstanceNewDll;
1366
1367 char *dot = strchr(modname, '.');
1368 if(dot) {
1369 *dot = 0;
1370 }
1371 strcat(modname, ".DLL");
1372 rc = DosLoadModule(szModuleFailure, sizeof(szModuleFailure), modname, (HMODULE *)&hInstanceNewDll);
1373 if(rc) {
1374 dprintf((LOG, "DosLoadModule returned %X for %s\n", rc, szModuleFailure));
1375 sprintf(szErrorModule, "%s.DLL", szModuleFailure);
1376 errorState = rc;
1377 return(FALSE);
1378 }
1379 WinDll = (Win32PeLdrDll *)Win32DllBase::findModule(hInstanceNewDll);
1380 if(WinDll == NULL) {//shouldn't happen!
1381 dprintf((LOG, "Just loaded the dll, but can't find it anywhere?!!?"));
1382 errorState = ERROR_INTERNAL;
1383 return(FALSE);
1384 }
1385 }
1386 else {
1387 WinDll = new Win32PeLdrDll(modname, this);
1388
1389 if(WinDll == NULL) {
1390 dprintf((LOG, "WinDll: Error allocating memory" ));
1391 WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, szMemErrorMsg, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
1392 errorState = ERROR_INTERNAL;
1393 return(FALSE);
1394 }
1395 dprintf((LOG, "**********************************************************************" ));
1396 dprintf((LOG, "********************** Loading Module *********************" ));
1397 dprintf((LOG, "**********************************************************************" ));
1398 if(WinDll->init(0) == FALSE) {
1399 dprintf((LOG, "Internal WinDll error ", WinDll->getError() ));
1400 return(FALSE);
1401 }
1402 if(WinDll->attachProcess() == FALSE) {
1403 dprintf((LOG, "attachProcess failed!" ));
1404 errorState = ERROR_INTERNAL;
1405 return(FALSE);
1406 }
1407 WinDll->AddRef();
1408 }
1409 dprintf((LOG, "**********************************************************************" ));
1410 dprintf((LOG, "********************** Finished Loading Module *********************" ));
1411 dprintf((LOG, "**********************************************************************" ));
1412 }
1413 else dprintf((LOG, "Already found ", pszCurModule ));
1414
1415 WinDll->AddRef();
1416
1417 pulImport = (PULONG)((ULONG)pulImport + (ULONG)win32file);
1418 j = 0;
1419 ulCurFixup = (ULONG)pID[i].FirstThunk + (ULONG)win32file;
1420
1421 section = findSectionByOS2Addr(ulCurFixup);
1422 if(section == NULL) {
1423 dprintf((LOG, "Unable to find section for %x", ulCurFixup ));
1424 return FALSE;
1425 }
1426 //SvL: Read page from disk
1427 commitPage(ulCurFixup & ~0xfff, FALSE, SINGLE_PAGE);
1428 //SvL: Enable write access
1429 DosSetMem((PVOID)(ulCurFixup & ~0xfff), PAGE_SIZE, PAG_READ|PAG_WRITE);
1430 nrPages = 1;
1431
1432 while (pulImport[j] != 0) {
1433 if (pulImport[j] & IMAGE_ORDINAL_FLAG) { //ordinal
1434 dprintf((LOG, "0x%08x Imported function %s @%d", ulCurFixup , pszCurModule, (pulImport[j] & ~IMAGE_ORDINAL_FLAG) ));
1435 StoreImportByOrd(WinDll, pulImport[j] & ~IMAGE_ORDINAL_FLAG, ulCurFixup);
1436 }
1437 else { //name
1438 //check
1439 if (pulImport[j] < shExtra.VirtualAddress || pulImport[j] >= shExtra.VirtualAddress + max(shExtra.Misc.VirtualSize, shExtra.SizeOfRawData)) {
1440 if (!GetSectionHdrByRVA(win32file, &shExtra, pulImport[j]))
1441 {
1442 dprintf((LOG, "warning: could not find section for Import Name RVA ", pulImport[j] ));
1443 break;
1444 }
1445 }
1446 //KSO - Aug 6 1998 1:15am:this eases comparing...
1447 char *pszFunctionName = (char*)(pulImport[j] + (ULONG)win32file + 2);
1448 dprintf((LOG, "0x%08x Imported function %s", ulCurFixup, pszFunctionName ));
1449 StoreImportByName(WinDll, pszFunctionName, ulCurFixup);
1450 }
1451 ulCurFixup += sizeof(IMAGE_THUNK_DATA);
1452 j++;
1453 if((ulCurFixup & 0xfff) == 0) {
1454 commitPage(ulCurFixup & ~0xfff, FALSE, SINGLE_PAGE);
1455 DosSetMem((PVOID)(ulCurFixup & ~0xfff), PAGE_SIZE, PAG_READ|PAG_WRITE);
1456 nrPages++;
1457 }
1458 }
1459 //SvL: And restore original protection flags
1460 ulCurFixup = (ULONG)pID[i].FirstThunk + pOH->ImageBase;
1461 DosSetMem((PVOID)(ulCurFixup & ~0xfff), PAGE_SIZE*nrPages, section->pageflags);
1462
1463 dprintf((LOG, "**********************************************************************" ));
1464 dprintf((LOG, "************** End Import Module %s ", pszCurModule ));
1465 dprintf((LOG, "**********************************************************************" ));
1466
1467 pszCurModule += strlen(pszCurModule) + 1;
1468 }//for (i = 0; i < cModules; i++)
1469
1470 free(pszModules);
1471 return TRUE;
1472}
1473//******************************************************************************
1474//******************************************************************************
1475ULONG Win32PeLdrImage::getApi(char *name)
1476{
1477 ULONG apiaddr, i, apilen;
1478 char *apiname;
1479 char tmp[4];
1480 NameExport *curexport;
1481 ULONG ulAPIOrdinal; /* api requested by ordinal */
1482
1483 apilen = strlen(name) + 1;
1484 if(apilen < 4)
1485 {
1486 *(ULONG *)tmp = 0;
1487 strcpy(tmp, name);
1488 apiname = tmp;
1489 }
1490 else apiname = name;
1491
1492 curexport = nameexports;
1493 for(i=0; i<nrNameExports; i++)
1494 {
1495 if(apilen == curexport->nlength &&
1496 *(ULONG *)curexport->name == *(ULONG *)name)
1497 {
1498 if(strcmp(curexport->name, name) == 0)
1499 return(curexport->virtaddr);
1500 }
1501 curexport = (NameExport *)((ULONG)curexport->name + curexport->nlength);
1502 }
1503 return(0);
1504}
1505//******************************************************************************
1506//******************************************************************************
1507ULONG Win32PeLdrImage::getApi(int ordinal)
1508{
1509 ULONG apiaddr, i;
1510 OrdExport *curexport;
1511 NameExport *nexport;
1512
1513 curexport = ordexports;
1514 for(i=0;i<nrOrdExports;i++) {
1515 if(curexport->ordinal == ordinal)
1516 return(curexport->virtaddr);
1517 curexport++;
1518 }
1519 //Name exports also contain an ordinal, so check this
1520 nexport = nameexports;
1521 for(i=0;i<nrNameExports;i++) {
1522 if(nexport->ordinal == ordinal)
1523 return(nexport->virtaddr);
1524
1525 nexport = (NameExport *)((ULONG)nexport->name + nexport->nlength);
1526 }
1527 return(0);
1528}
1529//******************************************************************************
1530//Returns required OS version for this image
1531//******************************************************************************
1532ULONG Win32PeLdrImage::getVersion()
1533{
1534 return (oh.MajorOperatingSystemVersion << 16) | oh.MinorOperatingSystemVersion;
1535}
1536//******************************************************************************
1537//******************************************************************************
1538ULONG MissingApi()
1539{
1540 static BOOL fIgnore = FALSE;
1541 int r;
1542
1543 dprintf((LOG, "Missing api called!\n"));
1544 if(fIgnore)
1545 return(0);
1546
1547 do {
1548 r = WinMessageBox(HWND_DESKTOP, NULLHANDLE, "The application has called a non-existing api\n",
1549 "Internal Odin Error", 0, MB_ABORTRETRYIGNORE | MB_ICONEXCLAMATION | MB_MOVEABLE);
1550 }
1551 while(r == MBID_RETRY); //giggle
1552
1553 if( r != MBID_IGNORE )
1554 exit(987);
1555
1556 fIgnore = TRUE;
1557 return(0);
1558}
1559/******************************************************************************/
1560/******************************************************************************/
Note: See TracBrowser for help on using the repository browser.