source: trunk/src/kernel32/winimagebase.cpp@ 21388

Last change on this file since 21388 was 21339, checked in by vladest, 16 years ago
  1. Attempt to add support for DosAllocMem at specific address
  2. Fixed crashes in Handle manager when its tries to access non initialized pointer
File size: 20.1 KB
Line 
1/* $Id: winimagebase.cpp,v 1.37 2004-01-15 10:39:11 sandervl Exp $ */
2
3/*
4 * Win32 PE Image base class
5 *
6 * Copyright 1998-1999 Sander van Leeuwen (sandervl@xs4all.nl)
7 * Copyright 1998-2000 knut st. osmundsen (knut.stange.osmundsen@mynd.no)
8 * Copyright 2003 Innotek Systemberatung GmbH (sandervl@innotek.de)
9 *
10 * Project Odin Software License can be found in LICENSE.TXT
11 *
12 */
13
14#define INCL_DOSFILEMGR /* File Manager values */
15#define INCL_DOSMODULEMGR
16#define INCL_DOSERRORS /* DOS Error values */
17#define INCL_DOSPROCESS /* DOS Process values */
18#define INCL_DOSMISC /* DOS Miscellanous values */
19#define INCL_WIN
20#define INCL_BASE
21#include <os2wrap.h> //Odin32 OS/2 api wrappers
22
23#include <stdio.h>
24#include <string.h>
25#include <stdlib.h>
26
27#include <assert.h>
28#include <misc.h>
29#include <win32type.h>
30#include <winimagebase.h>
31#include <windllbase.h>
32#include <winexebase.h>
33#include <windlllx.h>
34#include <pefile.h>
35#include <unicode.h>
36#include "oslibmisc.h"
37#include "oslibdos.h"
38#include "initterm.h"
39#include "directory.h"
40#include <win\virtual.h>
41#include <winconst.h>
42
43#define DBG_LOCALLOG DBG_winimagebase
44#include "dbglocal.h"
45
46//******************************************************************************
47//******************************************************************************
48Win32ImageBase::Win32ImageBase(HINSTANCE hInstance) :
49 errorState(NO_ERROR), entryPoint(0), fullpath(NULL),
50 tlsAddress(0), tlsIndexAddr(0), tlsInitSize(0), tlsTotalSize(0),
51 tlsCallBackAddr(0), tlsIndex(-1), pResRootDir(NULL), poh(NULL),
52 ulRVAResourceSection(0), fIsPEImage(FALSE), pExportDir(NULL)
53{
54 char *name;
55
56 magic = MAGIC_WINIMAGE;
57
58 if(hInstance != -1) {
59 this->hinstance = hInstance;
60
61 if(lpszCustomDllName) {
62 name = lpszCustomDllName;
63 }
64 else name = OSLibGetDllName(hinstance);
65
66 strcpy(szFileName, name);
67 strupr(szFileName);
68
69 if(lpszCustomDllName) {
70 strcpy(szModule, name);
71 }
72 else {
73 //rename dll (os/2 -> win32) if necessary (i.e. OLE32OS2 -> OLE32)
74 Win32DllBase::renameDll(szFileName, FALSE);
75 name = strrchr(szFileName, '\\')+1;
76 strcpy(szModule, name);
77 }
78 }
79 else {
80 szModule[0] = 0;
81 this->hinstance = -1;
82 }
83}
84//******************************************************************************
85//******************************************************************************
86Win32ImageBase::~Win32ImageBase()
87{
88 if(fullpath)
89 free(fullpath);
90}
91//******************************************************************************
92//******************************************************************************
93void Win32ImageBase::setFullPath(char *name)
94{
95 if(fullpath)
96 free(fullpath);
97 fullpath = (char *)malloc(strlen(name)+1);
98 strcpy(fullpath, name);
99}
100//******************************************************************************
101//Add image to dependency list of this image
102//******************************************************************************
103void Win32ImageBase::addDependency(Win32DllBase *image)
104{
105 loadedDlls.Push((ULONG)image);
106}
107//******************************************************************************
108//******************************************************************************
109BOOL Win32ImageBase::dependsOn(Win32DllBase *image)
110{
111 QueueItem *item;
112 BOOL ret = FALSE;
113
114 dlllistmutex.enter();
115 item = loadedDlls.Head();
116 while(item) {
117 if(loadedDlls.getItem(item) == (ULONG)image) {
118 ret = TRUE;
119 break;
120 }
121 item = loadedDlls.getNext(item);
122 }
123 dlllistmutex.leave();
124 return ret;
125}
126//******************************************************************************
127//Returns required OS version for this image
128//******************************************************************************
129ULONG Win32ImageBase::getVersion()
130{
131 dprintf(("Win32ImageBase::getVersion: NOT IMPLEMENTED!"));
132 return 0x40000; //NT 4
133}
134//******************************************************************************
135//******************************************************************************
136BOOL Win32ImageBase::insideModule(ULONG address)
137{
138 //dummy
139 return FALSE;
140}
141//******************************************************************************
142//******************************************************************************
143BOOL Win32ImageBase::insideModuleCode(ULONG address)
144{
145 //dummy
146 return FALSE;
147}
148//******************************************************************************
149//******************************************************************************
150ULONG Win32ImageBase::getImageSize()
151{
152 //dummy
153 return 0;
154}
155//******************************************************************************
156//
157// Win32ImageBase::findApi: find function in export table and change if necessary
158//
159// Parameters:
160// char *name - function name (NULL for ordinal search)
161// int ordinal - function ordinal (only used if name == NULL)
162// ULONG pfnNewProc - new function address (ignored if 0)
163//
164// Returns:
165// 0 - not found
166// <>0 - function address
167//
168//******************************************************************************
169ULONG Win32ImageBase::findApi(char *pszName, ULONG ulOrdinal, ULONG pfnNewProc)
170{
171 PIMAGE_EXPORT_DIRECTORY ped = pExportDir;
172
173 /*
174 * Get ped if it's NULL.
175 */
176 if (!ped)
177 {
178 if (!poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)
179 return 0;
180 ped = (PIMAGE_EXPORT_DIRECTORY)getPointerFromRVA(poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
181 pExportDir = ped;
182 }
183
184 int iExpOrdinal = 0; /* index into address table. */
185 if (pszName)
186 {
187 /*
188 * Find Named Export: Do binary search on the name table.
189 */
190 const char**paRVANames = (const char **)getPointerFromRVA(ped->AddressOfNames);
191 PUSHORT paOrdinals = (PUSHORT)getPointerFromRVA(ped->AddressOfNameOrdinals);
192 int iStart = 1;
193 int iEnd = ped->NumberOfNames;
194
195 for (;;)
196 {
197 /* end of search? */
198 if (iStart > iEnd)
199 {
200 #ifdef DEBUG
201 /* do a linear search just to verify the correctness of the above algorithm */
202 for (int i = 0; i < ped->NumberOfNames; i++)
203 if (!strcmp(paRVANames[i - 1] + (unsigned)hinstance, pszName))
204 {
205 dprintf(("bug in binary export search!!!\n"));
206 DebugInt3();
207 }
208 #endif
209 return 0;
210 }
211
212 int i = (iEnd - iStart) / 2 + iStart;
213 const char *pszExpName = (const char *)getPointerFromRVA(paRVANames[i - 1]);
214 int diff = strcmp(pszExpName, pszName);
215 if (diff > 0) /* pszExpName > pszName: search chunck before i */
216 iEnd = i - 1;
217 else if (diff) /* pszExpName < pszName: search chunk after i */
218 iStart = i + 1;
219 else /* pszExpName == pszName */
220 {
221 iExpOrdinal = paOrdinals[i - 1];
222 break;
223 }
224 } /* binary search thru name table */
225 }
226 else
227 {
228 /*
229 * Find ordinal export: Simple table lookup.
230 */
231 if ( ulOrdinal >= ped->Base + max(ped->NumberOfNames, ped->NumberOfFunctions)
232 || ulOrdinal < ped->Base)
233 return NULL;
234 iExpOrdinal = ulOrdinal - ped->Base;
235 }
236
237 /*
238 * Found export (iExpOrdinal).
239 */
240 PULONG paAddress = (PULONG)getPointerFromRVA(ped->AddressOfFunctions);
241 unsigned uRVAExport = paAddress[iExpOrdinal];
242 unsigned uRet;
243
244 /* Install override for the export (if requested) */
245 if (pfnNewProc && uRet)
246 paAddress[iExpOrdinal] = getRVAFromPointer((void*)pfnNewProc, TRUE);
247
248 if ( uRVAExport > poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
249 && uRVAExport < poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress
250 + poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)
251 /* Resolve forwarder. */
252 uRet = findForwarder(poh->ImageBase + uRVAExport, pszName, iExpOrdinal);
253 else
254 /* Get plain export address */
255 uRet = (ULONG)getPointerFromRVA(uRVAExport, TRUE);
256
257 return uRet;
258}
259//******************************************************************************
260//******************************************************************************
261ULONG Win32ImageBase::findForwarder(ULONG virtaddr, char *apiname, ULONG ordinal)
262{
263 char *forward;
264 char *forwarddll, *forwardapi;
265 Win32DllBase *WinDll;
266 DWORD exportaddr;
267 int forwardord;
268 int iForwardDllLength;
269 int iForwardApiLength;
270
271 forward = (char *)(hinstance + (virtaddr - poh->ImageBase));
272 iForwardDllLength = strlen(forward);
273
274 if(iForwardDllLength == 0)
275 return 0;
276
277 forwarddll = (char*)alloca(iForwardDllLength);
278 if(forwarddll == NULL) {
279 DebugInt3();
280 return 0;
281 }
282 memcpy(forwarddll, forward, iForwardDllLength + 1);
283
284 forwardapi = strchr(forwarddll, '.');
285 if(forwardapi == NULL) {
286 return 0;
287 }
288 *forwardapi++ = 0;
289 iForwardApiLength = strlen(forwardapi);
290 if(iForwardApiLength == 0) {
291 return FALSE;
292 }
293 WinDll = Win32DllBase::findModule(forwarddll);
294 if(WinDll == NULL) {
295 return 0;
296 }
297 //check if name or ordinal forwarder
298 forwardord = 0;
299 if(*forwardapi >= '0' && *forwardapi <= '9') {
300 forwardord = atoi(forwardapi);
301 }
302 if(forwardord != 0 || (iForwardApiLength == 1 && *forwardapi == '0')) {
303 exportaddr = WinDll->getApi(forwardord);
304 }
305 else exportaddr = WinDll->getApi(forwardapi);
306
307 return exportaddr;
308}
309//******************************************************************************
310//******************************************************************************
311ULONG Win32ImageBase::setApi(char *name, ULONG pfnNewProc)
312{
313 return findApi(name, 0, pfnNewProc);
314}
315//******************************************************************************
316//******************************************************************************
317ULONG Win32ImageBase::setApi(int ordinal, ULONG pfnNewProc)
318{
319 return findApi(NULL, ordinal, pfnNewProc);
320}
321//******************************************************************************
322//******************************************************************************
323ULONG Win32ImageBase::getApi(char *name)
324{
325 return findApi(name, 0);
326}
327//******************************************************************************
328//******************************************************************************
329ULONG Win32ImageBase::getApi(int ordinal)
330{
331 return findApi(NULL, ordinal);
332}
333//******************************************************************************
334//******************************************************************************
335BOOL Win32ImageBase::findDll(const char *szFileName, char *szFullName,
336 int cchFullFileName, const char *pszAltPath)
337{
338 char modname[CCHMAXPATH];
339 HFILE dllfile = NULL;
340 char *imagepath;
341
342 strcpy(szFullName, szFileName);
343 strupr(szFullName);
344 if(!strchr(szFullName, (int)'.')) {
345 strcat(szFullName, DLL_EXTENSION);
346 }
347
348 //search order:
349 //1) exe dir
350 //2) current dir
351 //3) windows system dir (kernel32 path)
352 //4) windows dir
353 //5) path
354 if(WinExe) {
355 strcpy(modname, WinExe->getFullPath());
356 //remove file name from full path
357 imagepath = modname + strlen(modname) - 1;
358 while(*imagepath != '\\')
359 imagepath--;
360 imagepath[1] = 0;
361 strcat(modname, szFullName);
362 dllfile = OSLibDosOpen(modname, OSLIB_ACCESS_READONLY|OSLIB_ACCESS_SHAREDENYNONE);
363 }
364 if(dllfile == NULL)
365 {
366 strcpy(modname, szFullName);
367 dllfile = OSLibDosOpen(szFullName, OSLIB_ACCESS_READONLY|OSLIB_ACCESS_SHAREDENYNONE);
368 if(dllfile == NULL)
369 {
370 strcpy(modname, InternalGetSystemDirectoryA());
371 strcat(modname, "\\");
372 strcat(modname, szFullName);
373 dllfile = OSLibDosOpen(modname, OSLIB_ACCESS_READONLY|OSLIB_ACCESS_SHAREDENYNONE);
374 if(dllfile == NULL)
375 {
376 strcpy(modname, InternalGetWindowsDirectoryA());
377 strcat(modname, "\\");
378 strcat(modname, szFullName);
379 dllfile = OSLibDosOpen(modname, OSLIB_ACCESS_READONLY|OSLIB_ACCESS_SHAREDENYNONE);
380 if(dllfile == NULL) {
381 if(OSLibDosSearchPath(OSLIB_SEARCHENV, "PATH", szFullName, modname, sizeof(modname)) == 0)
382 return FALSE;
383 }
384 }
385 }
386 }
387 strcpy(szFullName, modname);
388 if(dllfile) OSLibDosClose(dllfile);
389 return TRUE;
390}
391
392//******************************************************************************
393//returns ERROR_SUCCESS or error code (Characteristics will contain
394//the Characteristics member of the file header structure)
395//******************************************************************************
396ULONG Win32ImageBase::isPEImage(char *szFileName, DWORD *Characteristics,
397 DWORD *subsystem, DWORD *fNEExe)
398{
399 char filename[CCHMAXPATH];
400 char *syspath;
401 HFILE dllfile;
402 IMAGE_FILE_HEADER fh;
403 IMAGE_OPTIONAL_HEADER oh;
404 HFILE win32handle;
405 ULONG ulAction = 0; /* Action taken by DosOpen */
406 ULONG ulLocal = 0; /* File pointer position after DosSetFilePtr */
407 APIRET rc = NO_ERROR; /* Return code */
408 LPVOID win32file = NULL;
409 ULONG ulRead;
410 int nSections, i;
411
412 if(fNEExe)
413 *fNEExe = FALSE;
414
415 if (!findDll(ODINHelperStripUNC(szFileName), filename, sizeof(filename)))
416 {
417 dprintf(("KERNEL32:Win32ImageBase::isPEImage(%s) findDll failed to find the file.\n",
418 szFileName, rc));
419 return ERROR_FILE_NOT_FOUND_W;
420 }
421 rc = DosOpen(filename, /* File path name */
422 &win32handle, /* File handle */
423 &ulAction, /* Action taken */
424 0L, /* File primary allocation */
425 0L, /* File attribute */
426 OPEN_ACTION_FAIL_IF_NEW |
427 OPEN_ACTION_OPEN_IF_EXISTS, /* Open function type */
428 OPEN_FLAGS_NOINHERIT |
429 OPEN_SHARE_DENYNONE |
430 OPEN_ACCESS_READONLY, /* Open mode of the file */
431 0L); /* No extended attribute */
432
433 if (rc != NO_ERROR)
434 {
435 dprintf(("KERNEL32:Win32ImageBase::isPEImage(%s) failed with %u\n",
436 szFileName, rc));
437 return ERROR_FILE_NOT_FOUND_W;
438 }
439
440 /* Move the file pointer back to the beginning of the file */
441 DosSetFilePtr(win32handle, 0L, FILE_BEGIN, &ulLocal);
442
443 IMAGE_DOS_HEADER *pdoshdr = (IMAGE_DOS_HEADER *)malloc(sizeof(IMAGE_DOS_HEADER));
444 if(pdoshdr == NULL) {
445 DosClose(win32handle); /* Close the file */
446 return ERROR_INVALID_EXE_SIGNATURE_W;
447 }
448 rc = DosRead(win32handle, pdoshdr, sizeof(IMAGE_DOS_HEADER), &ulRead);
449 if(rc != NO_ERROR || ulRead != sizeof(IMAGE_DOS_HEADER)) {
450 free(pdoshdr);
451 DosClose(win32handle); /* Close the file */
452 return ERROR_INVALID_EXE_SIGNATURE_W;
453 }
454 if(pdoshdr->e_magic != IMAGE_DOS_SIGNATURE) {
455 free(pdoshdr);
456 DosClose(win32handle); /* Close the file */
457 return ERROR_INVALID_EXE_SIGNATURE_W;
458 }
459 ULONG hdrsize = pdoshdr->e_lfanew + SIZE_OF_NT_SIGNATURE + sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER);
460 free(pdoshdr);
461
462 /* Move the file pointer back to the beginning of the file */
463 DosSetFilePtr(win32handle, 0L, FILE_BEGIN, &ulLocal);
464
465 win32file = malloc(hdrsize);
466 if(win32file == NULL) {
467 DosClose(win32handle); /* Close the file */
468 return ERROR_NOT_ENOUGH_MEMORY_W;
469 }
470 rc = DosRead(win32handle, win32file, hdrsize, &ulRead);
471 if(rc != NO_ERROR || ulRead != hdrsize) {
472 goto failure;
473 }
474
475 if(GetPEFileHeader (win32file, &fh) == FALSE)
476 {
477 if(*(WORD *)PE_HEADER(win32file) == IMAGE_OS2_SIGNATURE) {
478 if(fNEExe)
479 *fNEExe = TRUE;
480 }
481 goto failure;
482 }
483 if(GetPEOptionalHeader (win32file, &oh) == FALSE) {
484 goto failure;
485 }
486
487 if(!(fh.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)) {//not valid
488 goto failure;
489 }
490 if(fh.Machine != IMAGE_FILE_MACHINE_I386) {
491 goto failure;
492 }
493 //IMAGE_FILE_SYSTEM == only drivers (device/file system/video etc)?
494 if(fh.Characteristics & IMAGE_FILE_SYSTEM) {
495 goto failure;
496 }
497 if(Characteristics) {
498 *Characteristics = fh.Characteristics;
499 }
500 if(subsystem) {
501 *subsystem = oh.Subsystem;
502 }
503
504 free(win32file);
505 DosClose(win32handle);
506 return ERROR_SUCCESS_W;
507
508failure:
509 free(win32file);
510 DosClose(win32handle);
511 return ERROR_INVALID_EXE_SIGNATURE_W;
512}
513//******************************************************************************
514//******************************************************************************
515/**
516 * Static helper which finds the Win32ImageBase object corresponding to hModule.
517 * @returns Pointer to Win32ImageBase object corresponding to hModule.
518 * @param hModule Odin32 modulehandler. 0 and -1 is aliases for the executable module
519 * @status completely implemented and tested.
520 * @author knut st. osmundsen
521 */
522Win32ImageBase * Win32ImageBase::findModule(HMODULE hModule)
523{
524 Win32ImageBase *pRet;
525
526 if (hModule == -1 || hModule == 0 || /* note: WinNt 4, SP4 don't accept -1 as the EXE handle.*/
527 (WinExe != NULL && hModule == WinExe->getInstanceHandle())
528 )
529 pRet = WinExe;
530 else
531 pRet = Win32DllBase::findModule(hModule);
532
533 if (pRet == NULL)
534 {
535 if (WinExe == NULL)
536 dprintf(("Win32ImageBase::findModule: Module not found. WinExe is NULL, hModule=%#x\n", hModule));
537 else
538 dprintf(("Win32ImageBase::findModule: Module not found, hModule=%#x\n", hModule));
539 }
540
541 return pRet;
542}
543
544
545/**
546 * Matches a given filename or module name with the module name of
547 * this object.
548 * @returns TRUE: The modulenames matches.
549 * FALSE: Don't match.
550 * @param pszFilename Pointer to filename or module name.
551 * @status completely implemented.
552 * @author knut st. osmundsen (knut.stange.osmundsen@mynd.no)
553 * @remark Just a clarification:
554 * A module name is the filename of a executable image without
555 * path, but *with* extention.
556 */
557BOOL Win32ImageBase::matchModName(const char *pszFilename) const
558{
559 const char *pszModName; /* Pointer to the modulename. */
560 const char *pszModNameEnd = NULL; /* Pointer to the dot starting the extention. (if any) */
561 register char ch;
562
563 /** @sketch
564 * Search the filename string finding the modulename start and end.
565 * The loop ends when we have passed one char left of the module name.
566 */
567 pszModName = pszFilename + strlen(pszFilename) - 1;
568 while (pszModName >= pszFilename
569 && (ch = *pszModName) != '\\'
570 && ch != '/'
571 && ch != ':'
572 )
573 {
574 pszModName--;
575 }
576 pszModName++;
577
578 /** @sketch
579 * Compare the names caseinsensitivly.
580 */
581 return stricmp(pszModName, szModule) == 0;
582}
583
584/** Converts a RVA to an pointer into the loaded image.
585 * @returns Pointer corresponding to the RVA.
586 * @param ulRVA RVA to make a pointer.
587 * @param fOverride Flags if the RVA might be to an overridden address (export).
588 */
589void *Win32ImageBase::getPointerFromRVA(ULONG ulRVA, BOOL fOverride/* = FALSE*/)
590{
591 return (PVOID)((char*)hinstance + ulRVA);
592}
593
594/** Converts a pointer to an RVA for the loaded image.
595 * @returns Pointer corresponding to the RVA.
596 * @param ulRVA RVA to make a pointer.
597 * @param fOverride Flags if the pointer might be to an overridden address (export).
598 */
599ULONG Win32ImageBase::getRVAFromPointer(void *pv, BOOL fOverride/* = FALSE*/)
600{
601 return (ULONG)pv - (ULONG)hinstance;
602}
603
Note: See TracBrowser for help on using the repository browser.