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

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

Allocate low memory at right address and with right size in peldr.dll (fixes install of Windows Media Player)

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