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

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

memory map fixes

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