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

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

GetProcessVersion changes

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