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

Last change on this file since 1146 was 1146, checked in by phaller, 26 years ago

Fix: problems while initializing SHELL32/NEW

File size: 41.9 KB
Line 
1/* $Id: winimagepeldr.cpp,v 1.4 1999-10-05 23:23:47 phaller 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
13#define INCL_DOSFILEMGR /* File Manager values */
14#define INCL_DOSMODULEMGR
15#define INCL_DOSERRORS /* DOS Error values */
16#define INCL_DOSPROCESS /* DOS Process values */
17#define INCL_DOSMISC /* DOS Miscellanous values */
18#define INCL_WIN
19#define INCL_BASE
20#include <os2wrap.h> //Odin32 OS/2 api wrappers
21
22#include <stdio.h>
23#include <string.h>
24#include <stdlib.h>
25
26#include <assert.h>
27#include <misc.h>
28#include <win32type.h>
29#include <winimagebase.h>
30#include <winimagepeldr.h>
31#include <windllpeldr.h>
32#include <pefile.h>
33#include <unicode.h>
34#include <winres.h>
35#include "oslibmisc.h"
36#include "initterm.h"
37#include <win\virtual.h>
38
39char szErrorTitle[] = "Odin";
40char szMemErrorMsg[] = "Memory allocation failure";
41char szFileErrorMsg[] = "File IO error";
42char szPEErrorMsg[] = "Not a valid win32 exe. (perhaps 16 bits windows)";
43char szCPUErrorMsg[] = "Executable doesn't run on x86 machines";
44char szExeErrorMsg[] = "File isn't an executable";
45char szInteralErrorMsg[]= "Internal Error";
46
47#ifndef max
48#define max(a, b) ((a>b) ? a : b)
49#endif
50
51BOOL foutInit = FALSE;
52ofstream fout;
53
54ULONG MissingApi();
55char *hex(ULONG num);
56
57extern ULONG flAllocMem; /*Tue 03.03.1998: knut */
58
59//******************************************************************************
60//******************************************************************************
61Win32PeLdrImage::Win32PeLdrImage(char *szFileName) :
62 Win32ImageBase(-1),
63 nrsections(0), imageSize(0),
64 imageVirtBase(-1), realBaseAddress(0), imageVirtEnd(0),
65 nrNameExports(0), nrOrdExports(0), nameexports(NULL), ordexports(NULL),
66 pResSection(NULL)
67{
68 strcpy(this->szFileName, szFileName);
69
70 strcpy(szModule, OSLibStripPath(szFileName));
71 strupr(szModule);
72 char *dot = strstr(szModule, ".");
73 while(dot) {
74 char *newdot = strstr(dot+1, ".");
75 if(newdot == NULL) break;
76 dot = newdot;
77 }
78 if(dot)
79 *dot = 0;
80
81 if(foutInit == FALSE) {
82 char logname[32];
83 sprintf(logname, "pe_%d.log", loadNr);
84 fout.open(logname, ios::out | ios::trunc);
85 dprintf(("PE LOGFILE for %s: %s", szModule, logname));
86 foutInit = TRUE;
87 }
88}
89//******************************************************************************
90//******************************************************************************
91Win32PeLdrImage::~Win32PeLdrImage()
92{
93 if(realBaseAddress)
94 DosFreeMem((PVOID)realBaseAddress);
95
96 if(nameexports)
97 free(nameexports);
98
99 if(ordexports)
100 free(ordexports);
101}
102//******************************************************************************
103//******************************************************************************
104BOOL Win32PeLdrImage::init(ULONG reservedMem)
105{
106 HANDLE fImgMapping = 0;
107 char szErrorMsg[64];
108 LPVOID win32file = NULL;
109 ULONG filesize, ulRead;
110 PIMAGE_SECTION_HEADER psh;
111 IMAGE_TLS_DIRECTORY *tlsDir = NULL;
112 int nSections, i;
113 char szFullPath[CCHMAXPATH] = "";
114
115 fImgMapping = VIRTUAL_MapFileA(szFileName, &win32file);
116
117 if (fImgMapping == -1) {
118 sprintf(szErrorMsg, "Unable to open %32s\n", szFileName);
119 WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, szErrorMsg, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
120 goto failure;
121 }
122
123 if(DosQueryPathInfo(szFileName, FIL_QUERYFULLNAME, szFullPath, sizeof(szFullPath)) == 0) {
124 setFullPath(szFullPath);
125 }
126
127 if(GetPEFileHeader (win32file, &fh) == FALSE) {
128 fout << "Not a valid PE file (probably a 16 bits windows exe/dll)!" << endl;
129 WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, szPEErrorMsg, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
130 goto failure;
131 }
132
133 if(!(fh.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)) {//not valid
134 fout << "Not a valid PE file!" << endl;
135 WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, szPEErrorMsg, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
136 goto failure;
137 }
138 if(fh.Machine != IMAGE_FILE_MACHINE_I386) {
139 fout << "You need a REAL CPU to run this code" << endl;
140 WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, szCPUErrorMsg, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
141 goto failure;
142 }
143 //IMAGE_FILE_SYSTEM == only drivers (device/file system/video etc)?
144 if(fh.Characteristics & IMAGE_FILE_SYSTEM) {
145 fout << "Can't convert system files" << endl;
146 WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, szExeErrorMsg, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
147 goto failure;
148 }
149
150 if(fh.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) {
151 fout << "No fixups, might not run!" << endl;
152 }
153
154 GetPEOptionalHeader (win32file, &oh);
155 fout << "PE file : " << szFileName << endl;
156 fout << "PE Optional header: " << endl;
157 fout << "Preferred address : " << oh.ImageBase << endl;
158 fout << "Base Of Code : " << oh.BaseOfCode << endl;
159 fout << "CodeSize : " << oh.SizeOfCode << endl;
160 fout << "Base Of Data : " << oh.BaseOfData << endl;
161 fout << "Data Size (uninit): " << oh.SizeOfUninitializedData << endl;
162 fout << "Data Size (init) : " << oh.SizeOfInitializedData << endl;
163 fout << "Entry Point : " << oh.AddressOfEntryPoint << endl;
164 fout << "Section Alignment : " << oh.SectionAlignment << endl;
165 fout << "Stack Reserve size: " << oh.SizeOfStackReserve << endl;
166 fout << "Stack Commit size : " << oh.SizeOfStackCommit << endl;
167 fout << "SizeOfHeapReserve : " << oh.SizeOfHeapReserve << endl;
168 fout << "SizeOfHeapCommit : " << oh.SizeOfHeapCommit << endl;
169 fout << "FileAlignment : " << oh.FileAlignment << endl;
170
171 nSections = NR_SECTIONS(win32file);
172
173 if ((psh = (PIMAGE_SECTION_HEADER)SECTIONHDROFF (win32file)) != NULL) {
174 fout << endl << "*************************PE SECTIONS START**************************" << endl;
175 for (i=0; i<nSections; i++) {
176 fout << "Raw data size: " << hex(psh[i].SizeOfRawData) << endl;
177 fout << "Virtual Address: " << hex(psh[i].VirtualAddress) << endl;
178 fout << "Virtual Size: " << hex(psh[i].Misc.VirtualSize) << endl;
179 fout << "Pointer to raw data: " << hex(psh[i].PointerToRawData) << endl;
180 fout << "Section flags: " << hex(psh[i].Characteristics) << endl << endl;
181 if(strcmp(psh[i].Name, ".reloc") == 0) {
182 fout << ".reloc" << endl << endl;
183 addSection(SECTION_RELOC, (char *)win32file+psh[i].PointerToRawData,
184 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
185 psh[i].Misc.VirtualSize);
186 continue;
187 }
188 if(strcmp(psh[i].Name, ".edata") == 0) {
189 fout << ".edata" << endl << endl;
190 addSection(SECTION_EXPORT, (char *)win32file+psh[i].PointerToRawData,
191 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
192 psh[i].Misc.VirtualSize);
193 continue;
194 }
195 if(strcmp(psh[i].Name, ".rsrc") == 0) {
196 fout << ".rsrc" << endl << endl;
197 addSection(SECTION_RESOURCE, (char *)win32file+psh[i].PointerToRawData,
198 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
199 psh[i].Misc.VirtualSize);
200 continue;
201 }
202 if(strcmp(psh[i].Name, ".tls") == 0)
203 {
204 tlsDir = (IMAGE_TLS_DIRECTORY *)ImageDirectoryOffset(win32file, IMAGE_DIRECTORY_ENTRY_TLS);
205 if(tlsDir) {
206 fout << "TLS Directory" << endl;
207 fout << "TLS Address of Index " << hex((ULONG)tlsDir->AddressOfIndex) << endl;
208 fout << "TLS Address of Callbacks " << hex((ULONG)tlsDir->AddressOfCallBacks) << endl;
209 fout << "TLS SizeOfZeroFill " << hex(tlsDir->SizeOfZeroFill) << endl;
210 fout << "TLS Characteristics " << hex(tlsDir->Characteristics) << endl;
211 addSection(SECTION_TLS, (char *)win32file+psh[i].PointerToRawData,
212 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
213 psh[i].Misc.VirtualSize);
214 }
215 continue;
216 }
217
218 if(strcmp(psh[i].Name, ".debug") == 0) {
219 fout << ".rdebug" << endl << endl;
220 addSection(SECTION_DEBUG, (char *)win32file+psh[i].PointerToRawData,
221 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
222 psh[i].Misc.VirtualSize);
223 continue;
224 }
225 if(IsImportSection(win32file, &psh[i]))
226 {
227 int type = SECTION_IMPORT;
228 fout << "Import Data Section" << endl << endl;
229 if(psh[i].Characteristics & IMAGE_SCN_CNT_CODE) {
230 fout << "Also Code Section" << endl << endl;
231 type |= SECTION_CODE;
232 }
233 addSection(type, (char *)win32file+psh[i].PointerToRawData,
234 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
235 psh[i].Misc.VirtualSize);
236 continue;
237 }
238
239 //KSO Sun 1998-08-09: Borland does not alway set the CODE flag for its "CODE" section
240 if( psh[i].Characteristics & IMAGE_SCN_CNT_CODE ||
241 (psh[i].Characteristics & IMAGE_SCN_MEM_EXECUTE &&
242 !(psh[i].Characteristics & (IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_CNT_INITIALIZED_DATA))) //KSO: make sure its not marked as a datasection
243 )
244 {
245 fout << "Code Section" << endl << endl;
246 addSection(SECTION_CODE, (char *)win32file+psh[i].PointerToRawData,
247 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
248 psh[i].Misc.VirtualSize);
249 continue;
250 }
251 if(!(psh[i].Characteristics & IMAGE_SCN_MEM_WRITE)) { //read only data section
252 fout << "Read Only Data Section" << endl << endl;
253 addSection(SECTION_READONLYDATA, (char *)win32file+psh[i].PointerToRawData,
254 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
255 psh[i].Misc.VirtualSize);
256 continue;
257 }
258 if(psh[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
259 fout << "Uninitialized Data Section" << endl << endl;
260 addSection(SECTION_UNINITDATA, (char *)win32file+psh[i].PointerToRawData,
261 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
262 psh[i].Misc.VirtualSize);
263 continue;
264 }
265 if(psh[i].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) {
266 fout << "Initialized Data Section" << endl << endl;
267 addSection(SECTION_INITDATA, (char *)win32file+psh[i].PointerToRawData,
268 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
269 psh[i].Misc.VirtualSize);
270 continue;
271 }
272 if(psh[i].Characteristics & (IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ)) {
273 fout << "Other Section, stored as read/write uninit data" << endl << endl;
274 addSection(SECTION_UNINITDATA, (char *)win32file+psh[i].PointerToRawData,
275 psh[i].SizeOfRawData, psh[i].VirtualAddress + oh.ImageBase,
276 psh[i].Misc.VirtualSize);
277 continue;
278 }
279 fout << "Unknown section" << endl;
280 goto failure;
281 }
282 }
283 fout << "*************************PE SECTIONS END **************************" << endl;
284 imageSize += imageVirtBase - oh.ImageBase;
285 fout << "Total size of Image " << imageSize << endl;
286 fout << "imageVirtBase " << imageVirtBase << endl;
287 fout << "imageVirtEnd " << imageVirtEnd << endl;
288
289 //In case there are any gaps between sections, adjust size
290 if(imageSize != imageVirtEnd - oh.ImageBase) {
291 fout << "imageSize != imageVirtEnd - oh.ImageBase!" << endl;
292 imageSize = imageVirtEnd - oh.ImageBase;
293 }
294 if(allocSections(reservedMem) == FALSE) {
295 fout << "Failed to allocate image memory, rc " << errorState << endl;
296 goto failure;
297 }
298 fout << "OS/2 base address " << realBaseAddress << endl;
299 if(storeSections((char *)win32file) == FALSE) {
300 fout << "Failed to store sections, rc " << errorState << endl;
301 goto failure;
302 }
303 if(oh.AddressOfEntryPoint) {
304 entryPoint = realBaseAddress + oh.AddressOfEntryPoint;
305 }
306 else {
307 fout << "EntryPoint == NULL" << endl;
308 entryPoint = NULL;
309 }
310
311 if(tlsDir != NULL) {
312 Section *sect = findSection(SECTION_TLS);
313
314 if(sect == NULL) {
315 fout << "Couldn't find TLS section!!" << endl;
316 goto failure;
317 }
318 setTLSAddress((char *)(sect->realvirtaddr + (tlsDir->StartAddressOfRawData - sect->virtaddr)));
319 setTLSInitSize(tlsDir->EndAddressOfRawData - tlsDir->StartAddressOfRawData);
320 setTLSTotalSize(tlsDir->EndAddressOfRawData - tlsDir->StartAddressOfRawData + tlsDir->SizeOfZeroFill);
321
322 sect = findSectionByAddr((ULONG)tlsDir->AddressOfIndex);
323 if(sect == NULL) {
324 fout << "Couldn't find TLS AddressOfIndex section!!" << endl;
325 goto failure;
326 }
327 setTLSIndexAddr((LPDWORD)(sect->realvirtaddr + ((ULONG)tlsDir->AddressOfIndex - sect->virtaddr)));
328
329 sect = findSectionByAddr((ULONG)tlsDir->AddressOfCallBacks);
330 if(sect == NULL) {
331 fout << "Couldn't find TLS AddressOfCallBacks section!!" << endl;
332 goto failure;
333 }
334 setTLSCallBackAddr((PIMAGE_TLS_CALLBACK *)(sect->realvirtaddr + ((ULONG)tlsDir->AddressOfCallBacks - sect->virtaddr)));
335 }
336
337 if(realBaseAddress != oh.ImageBase) {
338 if(setFixups((PIMAGE_BASE_RELOCATION)ImageDirectoryOffset(win32file, IMAGE_DIRECTORY_ENTRY_BASERELOC)) == FALSE) {
339 fout << "Failed to set fixups" << endl;
340 goto failure;
341 }
342 }
343 if(fh.Characteristics & IMAGE_FILE_DLL) {
344 if(processExports((char *)win32file) == FALSE) {
345 fout << "Failed to process exported apis" << endl;
346 goto failure;
347 }
348 }
349
350 //SvL: Use pointer to image header as module handle now. Some apps needs this
351 hinstance = (HINSTANCE)realBaseAddress;
352
353 //PH: get pResDir pointer correct first, since processImports may
354 // implicitly call functions depending on it.
355 IMAGE_SECTION_HEADER sh;
356 if(GetSectionHdrByName (win32file, &sh, ".rsrc")) {
357 //get offset in resource object of directory entry
358 pResDir = (PIMAGE_RESOURCE_DIRECTORY)(sh.VirtualAddress + realBaseAddress);
359 pResourceSectionStart = (ULONG)pResSection->virtaddr - oh.ImageBase;
360 }
361
362 if(processImports((char *)win32file) == FALSE) {
363 fout << "Failed to process imports!" << endl;
364 goto failure;
365 }
366
367 //set final memory protection flags (storeSections sets them to read/write)
368 if(setMemFlags() == FALSE) {
369 fout << "Failed to set memory protection" << endl;
370 goto failure;
371 }
372
373 CloseHandle(fImgMapping);
374 return(TRUE);
375failure:
376 if(fImgMapping) CloseHandle(fImgMapping);
377 errorState = ERROR_INTERNAL;
378 return FALSE;
379}
380//******************************************************************************
381//******************************************************************************
382void Win32PeLdrImage::addSection(ULONG type, char *rawdata, ULONG rawsize, ULONG virtaddress, ULONG virtsize)
383{
384 virtsize = max(rawsize, virtsize);
385
386 section[nrsections].type = type;
387 section[nrsections].rawdata = rawdata;
388 section[nrsections].rawsize = rawsize;
389 section[nrsections].virtaddr = virtaddress;
390
391 if(type == SECTION_RESOURCE) {
392 pResSection = &section[nrsections];
393 }
394 virtsize = ((virtsize - 1) & ~0xFFF) + PAGE_SIZE;
395 imageSize += virtsize;
396 section[nrsections].virtualsize = virtsize;
397
398 if(virtaddress < imageVirtBase)
399 imageVirtBase = virtaddress;
400 if(virtaddress + virtsize > imageVirtEnd)
401 imageVirtEnd = virtaddress + virtsize;
402
403 nrsections++;
404}
405//******************************************************************************
406//******************************************************************************
407BOOL Win32PeLdrImage::allocSections(ULONG reservedMem)
408{
409 APIRET rc;
410 ULONG baseAddress;
411
412 if(fh.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) {
413 fout << "No fixups, might not run!" << endl;
414 return allocFixedMem(reservedMem);
415 }
416 rc = DosAllocMem((PPVOID)&baseAddress, imageSize, PAG_READ | flAllocMem);
417 if(rc) {
418 errorState = rc;
419 return(FALSE);
420 }
421 realBaseAddress = baseAddress;
422 return(TRUE);
423}
424//******************************************************************************
425//******************************************************************************
426Section *Win32PeLdrImage::findSection(ULONG type)
427{
428 for(int i=0;i<nrsections;i++) {
429 if(section[i].type == type) {
430 return &section[i];
431 }
432 }
433 return NULL;
434}
435//******************************************************************************
436//******************************************************************************
437Section *Win32PeLdrImage::findSectionByAddr(ULONG addr)
438{
439 for(int i=0;i<nrsections;i++) {
440 if(section[i].virtaddr <= addr && section[i].virtaddr + section[i].virtualsize > addr) {
441 return &section[i];
442 }
443 }
444 return NULL;
445}
446//******************************************************************************
447#define FALLOC_SIZE (1024*1024)
448//NOTE: Needs testing (while loop)
449//TODO: Free unused (parts of) reservedMem
450//******************************************************************************
451BOOL Win32PeLdrImage::allocFixedMem(ULONG reservedMem)
452{
453 ULONG address = 0;
454 ULONG *memallocs;
455 ULONG alloccnt = 0;
456 ULONG diff, i, baseAddress;
457 APIRET rc;
458
459 realBaseAddress = 0;
460
461 if(reservedMem && reservedMem <= oh.ImageBase &&
462 ((oh.ImageBase - reservedMem) + imageSize < PELDR_RESERVEDMEMSIZE))
463 {
464 //ok, it fits perfectly
465 realBaseAddress = oh.ImageBase;
466 return TRUE;
467 }
468
469 //Reserve enough space to store 4096 pointers to 1MB memory chunks
470 memallocs = (ULONG *)malloc(4096*sizeof(ULONG *));
471 if(memallocs == NULL) {
472 fout << "allocFixedMem: MALLOC FAILED for memallocs" << endl;
473 return FALSE;
474 }
475
476 while(TRUE) {
477 rc = DosAllocMem((PPVOID)&address, FALLOC_SIZE, PAG_READ | flAllocMem);
478 if(rc) break;
479
480 fout << "DosAllocMem returned " << address << endl;
481 if(address + FALLOC_SIZE >= oh.ImageBase) {
482 if(address > oh.ImageBase) {//we've passed it!
483 DosFreeMem((PVOID)address);
484 break;
485 }
486 //found the right address
487 DosFreeMem((PVOID)address);
488
489 diff = oh.ImageBase - address;
490 if(diff) {
491 rc = DosAllocMem((PPVOID)&address, diff, PAG_READ | flAllocMem);
492 if(rc) break;
493 }
494 rc = DosAllocMem((PPVOID)&baseAddress, imageSize, PAG_READ | flAllocMem);
495 if(rc) break;
496
497 if(diff) DosFreeMem((PVOID)address);
498
499 realBaseAddress = baseAddress;
500 break;
501 }
502 memallocs[alloccnt++] = address;
503 }
504 for(i=0;i<alloccnt;i++) {
505 DosFreeMem((PVOID)memallocs[i]);
506 }
507 free(memallocs);
508
509 if(realBaseAddress == 0) //Let me guess.. MS Office app?
510 return(FALSE);
511
512 return(TRUE);
513}
514//******************************************************************************
515//******************************************************************************
516BOOL Win32PeLdrImage::storeSections(char *win32file)
517{
518 int i;
519 APIRET rc;
520 ULONG pagFlags = PAG_COMMIT;
521 ULONG headersize;
522 WINIMAGE_LOOKUP *imgLookup;
523
524 //Commit memory for image header
525 headersize = sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS) +
526 sizeof(IMAGE_SECTION_HEADER) * fh.NumberOfSections;
527
528 if(headersize + sizeof(WINIMAGE_LOOKUP) < PAGE_SIZE) {
529 headersize = PAGE_SIZE;
530 }
531 else {//ooops, just in case this doesn't work
532 fout << "ERROR: storeSections: header too big!!!!!! Fatal error" << endl;
533 return FALSE;
534 }
535
536 rc = DosSetMem((PVOID)realBaseAddress, headersize, pagFlags | PAG_WRITE | PAG_READ);
537 if(rc) {
538 fout << "DosSetMem failed for Image header! " << rc << endl;
539 return FALSE;
540 }
541 // Store the NT header at the load addr
542 memcpy((char *)realBaseAddress, win32file, sizeof(IMAGE_DOS_HEADER));
543 memcpy((char *)PE_HEADER(realBaseAddress), PE_HEADER(win32file), sizeof(IMAGE_NT_HEADERS));
544 memcpy(PE_SECTIONS(realBaseAddress), PE_SECTIONS(win32file),
545 sizeof(IMAGE_SECTION_HEADER) * fh.NumberOfSections );
546
547 imgLookup = WINIMAGE_LOOKUPADDR(realBaseAddress);
548 imgLookup->image = this;
549#ifdef DEBUG
550 imgLookup->magic = MAGIC_WINIMAGE;
551#endif
552
553 // Process all the image sections
554 for(i=0;i<nrsections;i++) {
555 section[i].realvirtaddr = realBaseAddress + (section[i].virtaddr - oh.ImageBase);
556 }
557 for(i=0;i<nrsections;i++) {
558 pagFlags = PAG_COMMIT;
559 switch(section[i].type) {
560 case SECTION_CODE:
561 case (SECTION_CODE | SECTION_IMPORT):
562 case SECTION_INITDATA:
563 case SECTION_UNINITDATA:
564 case SECTION_IMPORT:
565 case SECTION_READONLYDATA:
566 case SECTION_RESOURCE:
567 case SECTION_TLS:
568 pagFlags |= PAG_WRITE | PAG_READ;
569 break;
570 case SECTION_EXPORT:
571 case SECTION_DEBUG:
572 case SECTION_RELOC:
573 pagFlags = 0; //don't commit
574 break;
575 }
576 if(pagFlags == 0) continue; //debug or export section
577
578 rc = DosSetMem((PVOID)section[i].realvirtaddr, section[i].virtualsize, pagFlags);
579 if(rc) {
580 errorState = rc;
581 return(FALSE);
582 }
583 if(section[i].type != SECTION_UNINITDATA) {
584 assert(section[i].rawdata);
585 memcpy((char *)section[i].realvirtaddr, section[i].rawdata, section[i].rawsize);
586 }
587 }
588 return(TRUE);
589}
590//******************************************************************************
591//******************************************************************************
592BOOL Win32PeLdrImage::setMemFlags()
593{
594 int i;
595 APIRET rc;
596 ULONG pagFlags = 0;
597
598 for(i=0;i<nrsections;i++) {
599 pagFlags = 0;
600 switch(section[i].type) {
601 case SECTION_CODE:
602 case (SECTION_CODE | SECTION_IMPORT):
603 pagFlags |= PAG_EXECUTE | PAG_READ;
604 break;
605 case SECTION_INITDATA:
606 case SECTION_UNINITDATA:
607 case SECTION_IMPORT: //TODO: read only?
608 pagFlags |= PAG_WRITE | PAG_READ;
609 break;
610 case SECTION_READONLYDATA:
611 case SECTION_RESOURCE:
612 case SECTION_TLS:
613 pagFlags |= PAG_READ;
614 break;
615 default:
616 continue;
617 }
618 rc = DosSetMem((PVOID)section[i].realvirtaddr, section[i].virtualsize, pagFlags);
619 if(rc) {
620 errorState = rc;
621 return(FALSE);
622 }
623 }
624 return(TRUE);
625}
626//******************************************************************************
627//******************************************************************************
628BOOL Win32PeLdrImage::setFixups(PIMAGE_BASE_RELOCATION prel)
629{
630 int i, j;
631 char *page;
632 ULONG count;
633
634 if(fh.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) {
635 return(TRUE);
636 }
637
638 if(prel) {
639 j = 1;
640 while(prel->VirtualAddress) {
641 page = (char *)((char *)prel + (ULONG)prel->VirtualAddress);
642 count = (prel->SizeOfBlock - 8)/2;
643 fout.setf(ios::hex, ios::basefield);
644 fout << "Page " << j << " Address " << (ULONG)prel->VirtualAddress << " Count " << count << endl;
645 fout.setf(ios::dec, ios::basefield);
646 j++;
647 for(i=0;i<count;i++) {
648 int type = prel->TypeOffset[i] >> 12;
649 int offset = prel->TypeOffset[i] & 0xFFF;
650 switch(type) {
651 case IMAGE_REL_BASED_ABSOLUTE:
652//// fout << "absolute fixup; unused" << endl;
653 break; //skip
654 case IMAGE_REL_BASED_HIGHLOW:
655//// fout << "address " << offset << " type " << type << endl;
656 AddOff32Fixup(oh.ImageBase +
657 prel->VirtualAddress + offset);
658 break;
659 case IMAGE_REL_BASED_HIGH:
660 AddOff16Fixup(oh.ImageBase + prel->VirtualAddress + offset, TRUE);
661 break;
662 case IMAGE_REL_BASED_LOW:
663 AddOff16Fixup(oh.ImageBase + prel->VirtualAddress + offset, FALSE);
664 break;
665 case IMAGE_REL_BASED_HIGHADJ:
666 case IMAGE_REL_BASED_MIPS_JMPADDR:
667 default:
668 fout << "Unknown/unsupported fixup type!" << endl;
669 break;
670 }
671 }
672 prel = (PIMAGE_BASE_RELOCATION)((char*)prel + prel->SizeOfBlock);
673 }//while
674 }
675 else {
676 fout << "No internal fixups found!\n" << endl;
677 errorState = ERROR_INTERNAL;
678 return(FALSE);
679 }
680 return(TRUE);
681}
682//******************************************************************************
683//******************************************************************************
684void Win32PeLdrImage::AddOff32Fixup(ULONG fixupaddr)
685{
686 ULONG orgaddr;
687 ULONG *fixup;
688
689 fixup = (ULONG *)(fixupaddr - oh.ImageBase + realBaseAddress);
690 orgaddr = *fixup;
691 *fixup = realBaseAddress + (*fixup - oh.ImageBase);
692}
693//******************************************************************************
694//******************************************************************************
695void Win32PeLdrImage::AddOff16Fixup(ULONG fixupaddr, BOOL fHighFixup)
696{
697 ULONG orgaddr;
698 USHORT *fixup;
699
700 fixup = (USHORT *)(fixupaddr - oh.ImageBase + realBaseAddress);
701 orgaddr = *fixup;
702 if(fHighFixup) {
703 *fixup += (USHORT)((realBaseAddress - oh.ImageBase) >> 16);
704 }
705 else {
706 *fixup += (USHORT)((realBaseAddress - oh.ImageBase) & 0xFFFF);
707 }
708}
709//******************************************************************************
710//******************************************************************************
711void Win32PeLdrImage::StoreImportByOrd(Win32DllBase *WinDll, ULONG ordinal, ULONG impaddr)
712{
713 ULONG *import;
714 ULONG apiaddr;
715
716 import = (ULONG *)(impaddr - oh.ImageBase + realBaseAddress);
717 apiaddr = WinDll->getApi(ordinal);
718 if(apiaddr == 0)
719 {
720 dprintf(("KERNEL32:Win32PeLdrImage - %s.%u not found\n",
721 WinDll->getName(),
722 ordinal));
723
724 fout << "--->>> NOT FOUND!";
725 *import = (ULONG)MissingApi;
726 }
727 else *import = apiaddr;
728}
729//******************************************************************************
730//******************************************************************************
731void Win32PeLdrImage::StoreImportByName(Win32DllBase *WinDll, char *impname, ULONG impaddr)
732{
733 ULONG *import;
734 ULONG apiaddr;
735
736 import = (ULONG *)(impaddr - oh.ImageBase + realBaseAddress);
737 apiaddr = WinDll->getApi(impname);
738 if(apiaddr == 0)
739 {
740 dprintf(("KERNEL32:Win32PeLdrImage - %s.%s not found\n",
741 WinDll->getName(),
742 impname));
743
744 fout << "--->>> NOT FOUND!";
745 *import = (ULONG)MissingApi;
746 }
747 else *import = apiaddr;
748}
749//******************************************************************************
750//******************************************************************************
751BOOL Win32PeLdrImage::processExports(char *win32file)
752{
753 IMAGE_SECTION_HEADER sh;
754 PIMAGE_EXPORT_DIRECTORY ped;
755 ULONG *ptrNames, *ptrAddress;
756 USHORT *ptrOrd;
757 int i;
758
759 /* get section header and pointer to data directory for .edata section */
760 if((ped = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryOffset
761 (win32file, IMAGE_DIRECTORY_ENTRY_EXPORT)) != NULL &&
762 GetSectionHdrByImageDir(win32file, IMAGE_DIRECTORY_ENTRY_EXPORT, &sh) ) {
763
764 fout << "Exported Functions: " << endl;
765 ptrOrd = (USHORT *)((ULONG)ped->AddressOfNameOrdinals -
766 (ULONG)sh.VirtualAddress +
767 (ULONG)sh.PointerToRawData + (ULONG)win32file);
768 ptrNames = (ULONG *)((ULONG)ped->AddressOfNames -
769 (ULONG)sh.VirtualAddress +
770 (ULONG)sh.PointerToRawData + (ULONG)win32file);
771 ptrAddress = (ULONG *)((ULONG)ped->AddressOfFunctions -
772 (ULONG)sh.VirtualAddress +
773 (ULONG)sh.PointerToRawData + (ULONG)win32file);
774 nrOrdExports = ped->NumberOfFunctions;
775 nrNameExports = ped->NumberOfNames;
776
777 int ord, RVAExport;
778 char *name;
779 for(i=0;i<ped->NumberOfNames;i++) {
780 ord = ptrOrd[i] + ped->Base;
781 name = (char *)((ULONG)ptrNames[i] - (ULONG)sh.VirtualAddress +
782 (ULONG)sh.PointerToRawData + (ULONG)win32file);
783 RVAExport = ptrAddress[ptrOrd[i]];
784#ifdef FORWARDERS
785 if(RVAExport < sh.VirtualAddress || RVAExport > sh.VirtualAddress + sh.SizeOfRawData) {
786#endif
787 //points to code (virtual address relative to oh.ImageBase
788 fout << "address 0x";
789 fout.setf(ios::hex, ios::basefield);
790 fout << RVAExport;
791 fout.setf(ios::dec, ios::basefield);
792 fout << " " << name << "@" << ord << endl;
793 AddNameExport(oh.ImageBase + RVAExport, name, ord);
794#ifdef FORWARDERS
795
796 }
797 else {//forwarder
798 char *forward = (char *)((ULONG)RVAExport -
799 (ULONG)sh.VirtualAddress +
800 (ULONG)sh.PointerToRawData +
801 (ULONG)win32file);
802 fout << RVAExport << " " << name << " @" << ord << " is forwarder to " << (int)forward << endl;
803 }
804#endif
805 }
806 for(i=0;i<max(ped->NumberOfNames,ped->NumberOfFunctions);i++) {
807 ord = ped->Base + i; //Correct??
808 RVAExport = ptrAddress[i];
809#ifdef FORWARDERS
810 if(RVAExport < sh.VirtualAddress || RVAExport > sh.VirtualAddress + sh.SizeOfRawData) {
811#endif
812 if(RVAExport) {
813 //points to code (virtual address relative to oh.ImageBase
814 fout << "ord " << ord << " at 0x";
815 fout.setf(ios::hex, ios::basefield);
816 fout << RVAExport << endl;
817 fout.setf(ios::dec, ios::basefield);
818 AddOrdExport(oh.ImageBase + RVAExport, ord);
819 }
820#ifdef FORWARDERS
821 }
822 else {//forwarder or empty
823 char *forward = (char *)((ULONG)RVAExport -
824 (ULONG)sh.VirtualAddress +
825 (ULONG)sh.PointerToRawData +
826 (ULONG)win32file);
827 fout << "ord " << ord << " at 0x";
828 fout.setf(ios::hex, ios::basefield);
829 fout << RVAExport << " is forwarder to 0x" << (int)forward << endl;
830 fout.setf(ios::dec, ios::basefield);
831 }
832#endif
833 }
834 }
835 return(TRUE);
836}
837//******************************************************************************
838//******************************************************************************
839void Win32PeLdrImage::AddNameExport(ULONG virtaddr, char *apiname, ULONG ordinal)
840{
841 ULONG nsize;
842
843 if(nameexports == NULL) {
844 nameExportSize= 4096;
845 nameexports = (NameExport *)malloc(nameExportSize);
846 curnameexport = nameexports;
847 }
848 nsize = (ULONG)curnameexport - (ULONG)nameexports;
849 if(nsize + sizeof(NameExport) + strlen(apiname) > nameExportSize) {
850 nameExportSize += 4096;
851 char *tmp = (char *)nameexports;
852 nameexports = (NameExport *)malloc(nameExportSize);
853 memcpy(nameexports, tmp, nsize);
854 curnameexport = (NameExport *)((ULONG)nameexports + nsize);
855 free(tmp);
856 }
857 curnameexport->virtaddr = realBaseAddress + (virtaddr - oh.ImageBase);
858 curnameexport->ordinal = ordinal;
859 *(ULONG *)curnameexport->name = 0;
860 strcpy(curnameexport->name, apiname);
861
862 curnameexport->nlength = strlen(apiname) + 1;
863 if(curnameexport->nlength < sizeof(curnameexport->name))
864 curnameexport->nlength = sizeof(curnameexport->name);
865
866 curnameexport = (NameExport *)((ULONG)curnameexport->name + curnameexport->nlength);
867}
868//******************************************************************************
869//******************************************************************************
870void Win32PeLdrImage::AddOrdExport(ULONG virtaddr, ULONG ordinal)
871{
872 if(ordexports == NULL) {
873 ordexports = (OrdExport *)malloc(nrOrdExports * sizeof(OrdExport));
874 curordexport = ordexports;
875 }
876 curordexport->virtaddr = realBaseAddress + (virtaddr - oh.ImageBase);
877 curordexport->ordinal = ordinal;
878 curordexport++;
879}
880//******************************************************************************
881/** All initial processing of imports is done here
882 * Should now detect most Borland styled files including the GifCon32.exe and
883 * loader32 from SoftIce. (Stupid Borland!!!)
884 *
885 * knut [Jul 22 1998 2:44am]
886 **/
887//******************************************************************************
888BOOL Win32PeLdrImage::processImports(char *win32file)
889{
890 PIMAGE_IMPORT_DESCRIPTOR pID;
891 IMAGE_SECTION_HEADER shID;
892 IMAGE_SECTION_HEADER shExtra = {0};
893 PIMAGE_OPTIONAL_HEADER pOH;
894 int i,j;
895 BOOL fBorland = 0;
896 int cModules;
897 char *pszModules;
898 char *pszCurModule;
899 char *pszTmp;
900 ULONG *pulImport;
901 ULONG ulCurFixup;
902 int Size;
903 Win32PeLdrDll *WinDll;
904
905/* "algorithm:"
906 * 1) get module names and store them
907 * a) check dwRVAModuleName is within .idata seg - if not find section
908 * 2) iterate thru functions of each module
909 * a) check OriginalFirstThunk is not 0 and that it points to a RVA.
910 * b) if not a) borland-styled PE-file - ARG!!!
911 * check FirstThunk
912 * c) check OriginalFirstThunk/FirstThunk ok RVAs and find right section
913 * d) store ordinal/name import
914 * 3) finished
915 */
916
917 /* 1) get module names */
918 pID = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryOffset(win32file, IMAGE_DIRECTORY_ENTRY_IMPORT);
919 if (pID == NULL)
920 return TRUE;
921 if (!GetSectionHdrByImageDir(win32file, IMAGE_DIRECTORY_ENTRY_IMPORT, &shID))
922 return TRUE;
923
924 //calc size of module list
925 i = Size = cModules = 0;
926 while (pID[i].Name != 0)
927 {
928 //test RVA inside ID-Section
929 if (pID[i].Name >= shID.VirtualAddress && pID[i].Name < shID.VirtualAddress + max(shID.Misc.VirtualSize, shID.SizeOfRawData)) {
930 pszTmp = (char*)(pID[i].Name- shID.VirtualAddress + shID.PointerToRawData + (ULONG)win32file);
931 }
932 else {
933 //is the "Extra"-section already found or do we have to find it?
934 if (pID[i].Name < shExtra.VirtualAddress || pID[i].Name >= shExtra.VirtualAddress + max(shExtra.Misc.VirtualSize, shExtra.SizeOfRawData)) {
935 if (!GetSectionHdrByRVA(win32file, &shExtra, pID[i].Name))
936 return FALSE;
937 }
938 pszTmp = (char*)(pID[i].Name- shExtra.VirtualAddress + shExtra.PointerToRawData + (ULONG)win32file);
939 }
940 Size += strlen(pszTmp) + 1;
941 i++;
942 cModules++;
943 }
944
945 pszModules = (char*)malloc(Size);
946 assert(pszModules != NULL);
947 j = 0;
948 for (i = 0; i < cModules; i++)
949 {
950 //test RVA inside ID-Section
951 if (pID[i].Name >= shID.VirtualAddress && pID[i].Name < shID.VirtualAddress + max(shID.Misc.VirtualSize, shID.SizeOfRawData)) {
952 pszTmp = (char*)(pID[i].Name- shID.VirtualAddress + shID.PointerToRawData + (ULONG)win32file);
953 }
954 else {
955 fBorland = TRUE;
956 //is the "Extra"-section already found or do we have to find it?
957 if (pID[i].Name < shExtra.VirtualAddress || pID[i].Name >= shExtra.VirtualAddress + max(shExtra.Misc.VirtualSize, shExtra.SizeOfRawData))
958 {
959 if (GetSectionHdrByRVA(win32file, &shExtra, pID[i].Name)) {
960 free(pszModules);
961 return FALSE;
962 }
963 }
964 pszTmp = (char*)(pID[i].Name- shExtra.VirtualAddress + shExtra.PointerToRawData + (ULONG)win32file);
965 }
966
967 strcpy(pszModules+j, pszTmp);
968 j += strlen(pszTmp) + 1;
969 }
970 fout << endl;
971 if (fBorland)
972 fout << "Borland-styled PE-File." << endl;
973 //Store modules
974 fout << cModules << " imported Modules: " << endl;
975
976 /* 2) functions */
977 pszCurModule = pszModules;
978 pOH = (PIMAGE_OPTIONAL_HEADER)OPTHEADEROFF(win32file);
979 for (i = 0; i < cModules; i++)
980 {
981 fout << "Module " << pszCurModule << endl;
982 // a) check that OriginalFirstThunk not is 0 and look for Borland-styled PE
983 if (i == 0)
984 {
985 //heavy borland-style test - assume array of thunks is within that style does not change
986 if((ULONG)pID[i].u.OriginalFirstThunk == 0 ||
987 (ULONG)pID[i].u.OriginalFirstThunk < shID.VirtualAddress ||
988 (ULONG)pID[i].u.OriginalFirstThunk >= shID.VirtualAddress + max(shID.Misc.VirtualSize, shID.SizeOfRawData) ||
989 (ULONG)pID[i].u.OriginalFirstThunk >= pOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress &&
990 (ULONG)pID[i].u.OriginalFirstThunk < sizeof(*pID)*cModules + pOH->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress)
991 {
992 fBorland = TRUE;
993 }
994 }
995 //light borland-style test
996 if (pID[i].u.OriginalFirstThunk == 0 || fBorland)
997 pulImport = (ULONG*)pID[i].FirstThunk;
998 else pulImport = (ULONG*)pID[i].u.OriginalFirstThunk;
999
1000 // b) check if RVA ok
1001 if (!(pulImport > 0 && (ULONG)pulImport < pOH->SizeOfImage)) {
1002 fout << "Invalid RVA " << hex((ULONG)pulImport) << endl;
1003 break;
1004 }
1005 // check section
1006 if ((ULONG)pulImport < shExtra.VirtualAddress || (ULONG)pulImport >= shExtra.VirtualAddress + max(shExtra.Misc.VirtualSize, shExtra.SizeOfRawData))
1007 {
1008 if (!GetSectionHdrByRVA(win32file, &shExtra, (ULONG)pulImport))
1009 {
1010 fout << "warning: could not find section for Thunk RVA " << hex((ULONG)pulImport) << endl;
1011 break;
1012 }
1013 }
1014
1015 //SvL: Load dll if needed
1016 fout << "**********************************************************************" << endl;
1017 fout << "************** Import Module " << pszCurModule << endl;
1018 fout << "**********************************************************************" << endl;
1019 WinDll = (Win32PeLdrDll *)Win32DllBase::findModule(pszCurModule);
1020 if(WinDll == NULL)
1021 { //not found, so load it
1022 if(isPEImage(pszCurModule) == FALSE)
1023 {//LX image, so let OS/2 do all the work for us
1024 APIRET rc;
1025 char szModuleFailure[CCHMAXPATH] = "";
1026 ULONG hInstanceNewDll;
1027
1028 rc = DosLoadModule(szModuleFailure, sizeof(szModuleFailure), pszCurModule, (HMODULE *)&hInstanceNewDll);
1029 if(rc) {
1030 dprintf(("DosLoadModule returned %X for %s\n", rc, szModuleFailure));
1031 errorState = rc;
1032 return(FALSE);
1033 }
1034 WinDll = (Win32PeLdrDll *)Win32DllBase::findModule(hInstanceNewDll);
1035 if(WinDll == NULL) {//shouldn't happen!
1036 dprintf(("Just loaded the dll, but can't find it anywhere?!!?"));
1037 errorState = ERROR_INTERNAL;
1038 return(FALSE);
1039 }
1040 }
1041 else {
1042 WinDll = new Win32PeLdrDll(pszCurModule, this);
1043
1044 if(WinDll == NULL) {
1045 fout << "WinDll: Error allocating memory" << endl;
1046 WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, szMemErrorMsg, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
1047 errorState = ERROR_INTERNAL;
1048 return(FALSE);
1049 }
1050 fout << "**********************************************************************" << endl;
1051 fout << "********************** Loading Module *********************" << endl;
1052 fout << "**********************************************************************" << endl;
1053 if(WinDll->init(0) == FALSE) {
1054 fout << "Internal WinDll error " << WinDll->getError() << endl;
1055 return(FALSE);
1056 }
1057 if(WinDll->attachProcess() == FALSE) {
1058 fout << "attachProcess failed!" << endl;
1059 errorState = ERROR_INTERNAL;
1060 return(FALSE);
1061 }
1062 }
1063 fout << "**********************************************************************" << endl;
1064 fout << "********************** Finished Loading Module *********************" << endl;
1065 fout << "**********************************************************************" << endl;
1066 }
1067 else fout << "Already found " << pszCurModule << endl;
1068
1069 WinDll->AddRef();
1070
1071 pulImport = (PULONG)((ULONG)pulImport - shExtra.VirtualAddress + (ULONG)win32file + shExtra.PointerToRawData);
1072 j = 0;
1073 ulCurFixup = (ULONG)pID[i].FirstThunk + pOH->ImageBase;
1074 while (pulImport[j] != 0) {
1075 if (pulImport[j] & IMAGE_ORDINAL_FLAG) { //ordinal
1076 fout.setf(ios::hex, ios::basefield);
1077 fout << "0x" << ulCurFixup << " Imported function " << pszCurModule << "@" << (pulImport[j] & ~IMAGE_ORDINAL_FLAG) << endl;
1078 fout.setf(ios::dec, ios::basefield);
1079 StoreImportByOrd(WinDll, pulImport[j] & ~IMAGE_ORDINAL_FLAG, ulCurFixup);
1080 }
1081 else { //name
1082 //check
1083 if (pulImport[j] < shExtra.VirtualAddress || pulImport[j] >= shExtra.VirtualAddress + max(shExtra.Misc.VirtualSize, shExtra.SizeOfRawData)) {
1084 if (!GetSectionHdrByRVA(win32file, &shExtra, pulImport[j]))
1085 {
1086 fout << "warning: could not find section for Import Name RVA " << hex(pulImport[j]) << endl;
1087 break;
1088 }
1089 }
1090 //KSO - Aug 6 1998 1:15am:this eases comparing...
1091 char *pszFunctionName = (char*)(pulImport[j] + (ULONG)win32file + shExtra.PointerToRawData - shExtra.VirtualAddress + 2);
1092 fout.setf(ios::hex, ios::basefield);
1093 fout << "0x" << ulCurFixup << " Imported function " << pszFunctionName << endl;
1094 fout.setf(ios::dec, ios::basefield);
1095 StoreImportByName(WinDll, pszFunctionName, ulCurFixup);
1096 }
1097 ulCurFixup += sizeof(IMAGE_THUNK_DATA);
1098 j++;
1099 }
1100 fout << "**********************************************************************" << endl;
1101 fout << "************** End Import Module " << pszCurModule << endl;
1102 fout << "**********************************************************************" << endl;
1103
1104 pszCurModule += strlen(pszCurModule) + 1;
1105 fout << endl;
1106 }//for (i = 0; i < cModules; i++)
1107
1108 free(pszModules);
1109 return TRUE;
1110}
1111//******************************************************************************
1112//******************************************************************************
1113ULONG MissingApi()
1114{
1115 static BOOL fIgnore = FALSE;
1116 int r;
1117
1118 dprintf(("Missing api called!\n"));
1119 if(fIgnore)
1120 return(0);
1121
1122 do {
1123 r = WinMessageBox(HWND_DESKTOP, NULLHANDLE, "The application has called a non-existing api\n",
1124 "Internal Error", 0, MB_ABORTRETRYIGNORE | MB_ICONEXCLAMATION | MB_MOVEABLE);
1125 }
1126 while(r == MBID_RETRY); //giggle
1127
1128 if( r != MBID_IGNORE )
1129 exit(987);
1130
1131 fIgnore = TRUE;
1132 return(0);
1133}
1134/******************************************************************************/
1135/******************************************************************************/
1136/*heximal(decimal) KSO Sun 24.05.1998*/
1137char szHexBuffer[30];
1138
1139char *hex(ULONG num)
1140{
1141 sprintf(szHexBuffer, "0x%+08x (%lu)",num,num);
1142 return szHexBuffer;
1143}
1144//******************************************************************************
1145//******************************************************************************
Note: See TracBrowser for help on using the repository browser.