Commit 97ad311e authored by Alexandre Julliard's avatar Alexandre Julliard

Moved the 32-bit builtin loader and the remaining bits of the PE

loader into dlls/ntdll/loader.c.
parent ce85a905
......@@ -124,6 +124,8 @@ int main_create_flags = 0;
extern BOOL init_user_process_pmts( size_t, char*, size_t );
extern BOOL build_command_line( char **argv );
extern WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename ); /* FIXME */
extern void RELAY_InitDebugLists(void);
extern void SHELL_LoadRegistry(void);
extern void VERSION_Init( const char *appname );
......@@ -276,6 +278,51 @@ static BOOL find_exe_file( const char *name, char *buffer, int buflen, HANDLE *h
}
/**********************************************************************
* load_pe_exe
*
* Load a PE format EXE file.
*/
static HMODULE load_pe_exe( HANDLE file )
{
IMAGE_NT_HEADERS *nt;
HANDLE mapping;
void *module;
OBJECT_ATTRIBUTES attr;
LARGE_INTEGER size;
DWORD len = 0;
attr.Length = sizeof(attr);
attr.RootDirectory = 0;
attr.ObjectName = NULL;
attr.Attributes = 0;
attr.SecurityDescriptor = NULL;
attr.SecurityQualityOfService = NULL;
size.QuadPart = 0;
if (NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
&attr, &size, 0, SEC_IMAGE, file ) != STATUS_SUCCESS)
return NULL;
module = NULL;
if (NtMapViewOfSection( mapping, GetCurrentProcess(), &module, 0, 0, &size, &len,
ViewShare, 0, PAGE_READONLY ) != STATUS_SUCCESS)
return NULL;
NtClose( mapping );
/* virus check */
nt = RtlImageNtHeader( module );
if (nt->OptionalHeader.AddressOfEntryPoint)
{
if (!RtlImageRvaToSection( nt, module, nt->OptionalHeader.AddressOfEntryPoint ))
MESSAGE("VIRUS WARNING: PE module has an invalid entrypoint (0x%08lx) "
"outside all sections (possibly infected by Tchernobyl/SpaceFiller virus)!\n",
nt->OptionalHeader.AddressOfEntryPoint );
}
return module;
}
/***********************************************************************
* process_init
*
......@@ -411,6 +458,7 @@ static void start_process( void *arg )
LPTHREAD_START_ROUTINE entry;
HANDLE main_file = main_exe_file;
IMAGE_NT_HEADERS *nt;
WINE_MODREF *wm;
PEB *peb = NtCurrentTeb()->Peb;
if (main_file)
......@@ -450,11 +498,13 @@ static void start_process( void *arg )
SERVER_END_REQ;
/* create the main modref and load dependencies */
if (!PE_CreateModule( peb->ImageBaseAddress, main_exe_name, 0, 0, FALSE )) goto error;
if (!(wm = MODULE_AllocModRef( peb->ImageBaseAddress, main_exe_name ))) goto error;
if (main_exe_file) CloseHandle( main_exe_file ); /* we no longer need it */
MODULE_DllProcessAttach( NULL, (LPVOID)1 );
if (MODULE_DllProcessAttach( NULL, (LPVOID)1 ) != STATUS_SUCCESS)
{
ERR( "Main exe initialization failed\n" );
goto error;
}
if (TRACE_ON(relay))
DPRINTF( "%04lx:Starting process %s (entryproc=%p)\n",
......@@ -523,7 +573,7 @@ void __wine_process_init( int argc, char *argv[] )
{
case BINARY_PE_EXE:
TRACE( "starting Win32 binary %s\n", debugstr_a(main_exe_name) );
if ((current_process.module = PE_LoadImage( main_exe_file, main_exe_name, 0 ))) goto found;
if ((current_process.module = load_pe_exe( main_exe_file ))) goto found;
MESSAGE( "%s: could not load '%s' as Win32 binary\n", argv0, main_exe_name );
ExitProcess(1);
case BINARY_PE_DLL:
......
......@@ -14,7 +14,6 @@ C_SRCS = \
$(TOPOBJDIR)/files/smb.c \
$(TOPOBJDIR)/loader/loadorder.c \
$(TOPOBJDIR)/loader/module.c \
$(TOPOBJDIR)/loader/pe_image.c \
$(TOPOBJDIR)/loader/task.c \
$(TOPOBJDIR)/loader/ne/module.c \
$(TOPOBJDIR)/memory/codepage.c \
......@@ -28,7 +27,6 @@ C_SRCS = \
$(TOPOBJDIR)/misc/registry.c \
$(TOPOBJDIR)/misc/version.c \
$(TOPOBJDIR)/msdos/dpmi.c \
$(TOPOBJDIR)/relay32/builtin32.c \
$(TOPOBJDIR)/relay32/relay386.c \
$(TOPOBJDIR)/relay32/snoop.c \
$(TOPOBJDIR)/scheduler/handle.c \
......
......@@ -32,7 +32,6 @@
#include "file.h"
#include "wine/exception.h"
#include "excpt.h"
#include "snoop.h"
#include "wine/debug.h"
#include "wine/server.h"
#include "ntdll_misc.h"
......@@ -78,6 +77,7 @@ static CRITICAL_SECTION loader_section = { &critsect_debug, -1, 0, 0, 0, 0 };
static WINE_MODREF *cached_modref;
static WINE_MODREF *current_modref;
static NTSTATUS last_builtin_status; /* use to gather all errors in callback */
static NTSTATUS load_dll( LPCSTR libname, DWORD flags, WINE_MODREF** pwm );
static FARPROC find_named_export( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
......@@ -114,6 +114,55 @@ static WINE_MODREF *get_modref( HMODULE hmod )
}
/**********************************************************************
* find_module
*
* Find a (loaded) win32 module depending on path
* LPCSTR path: [in] pathname of module/library to be found
*
* The loader_section must be locked while calling this function
* RETURNS
* the module handle if found
* 0 if not
*/
static WINE_MODREF *find_module( LPCSTR path )
{
WINE_MODREF *wm;
PLIST_ENTRY mark, entry;
PLDR_MODULE mod;
char dllname[260], *p;
/* Append .DLL to name if no extension present */
strcpy( dllname, path );
if (!(p = strrchr( dllname, '.')) || strchr( p, '/' ) || strchr( p, '\\'))
strcat( dllname, ".DLL" );
if ((wm = cached_modref) != NULL)
{
if ( !FILE_strcasecmp( dllname, wm->modname ) ) return wm;
if ( !FILE_strcasecmp( dllname, wm->filename ) ) return wm;
if ( !FILE_strcasecmp( dllname, wm->short_modname ) ) return wm;
if ( !FILE_strcasecmp( dllname, wm->short_filename ) ) return wm;
}
mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
for (entry = mark->Flink; entry != mark; entry = entry->Flink)
{
mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
if ( !FILE_strcasecmp( dllname, wm->modname ) ) break;
if ( !FILE_strcasecmp( dllname, wm->filename ) ) break;
if ( !FILE_strcasecmp( dllname, wm->short_modname ) ) break;
if ( !FILE_strcasecmp( dllname, wm->short_filename ) ) break;
}
if (entry == mark) wm = NULL;
cached_modref = wm;
return wm;
}
/*************************************************************************
* find_forwarded_export
*
......@@ -134,7 +183,7 @@ static FARPROC find_forwarded_export( HMODULE module, const char *forward )
memcpy( mod_name, forward, end - forward );
mod_name[end-forward] = 0;
if (!(wm = MODULE_FindModule( mod_name )))
if (!(wm = find_module( mod_name )))
{
ERR("module not found for forward '%s' used by '%s'\n",
forward, get_modref(module)->filename );
......@@ -305,12 +354,12 @@ static WINE_MODREF *import_dll( HMODULE module, IMAGE_IMPORT_DESCRIPTOR *descr )
/****************************************************************
* PE_fixup_imports
* fixup_imports
*
* Fixup all imports of a given module.
* The loader_section must be locked while calling this function.
*/
DWORD PE_fixup_imports( WINE_MODREF *wm )
static NTSTATUS fixup_imports( WINE_MODREF *wm )
{
int i, nb_imports;
IMAGE_IMPORT_DESCRIPTOR *imports;
......@@ -319,7 +368,7 @@ DWORD PE_fixup_imports( WINE_MODREF *wm )
if (!(imports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
return 0;
return STATUS_SUCCESS;
nb_imports = size / sizeof(*imports);
for (i = 0; i < nb_imports; i++)
......@@ -330,7 +379,7 @@ DWORD PE_fixup_imports( WINE_MODREF *wm )
break;
}
}
if (!nb_imports) return 0; /* no imports */
if (!nb_imports) return STATUS_SUCCESS; /* no imports */
/* Allocate module dependency list */
wm->nDeps = nb_imports;
......@@ -346,7 +395,8 @@ DWORD PE_fixup_imports( WINE_MODREF *wm )
if (!(wm->deps[i] = import_dll( wm->ldr.BaseAddress, &imports[i] ))) break;
}
current_modref = prev;
return (i < nb_imports);
if (i < nb_imports) return STATUS_DLL_NOT_FOUND;
return STATUS_SUCCESS;
}
......@@ -634,6 +684,7 @@ NTSTATUS MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved )
LDR_MODULE, InLoadOrderModuleList),
WINE_MODREF, ldr);
wm->ldr.LoadCount = -1; /* can't unload main exe */
if ((status = fixup_imports( wm )) != STATUS_SUCCESS) goto done;
if ((status = alloc_process_tls()) != STATUS_SUCCESS) goto done;
if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto done;
}
......@@ -809,55 +860,6 @@ NTSTATUS WINAPI LdrFindEntryForAddress(const void* addr, PLDR_MODULE* pmod)
return STATUS_NO_MORE_ENTRIES;
}
/**********************************************************************
* MODULE_FindModule
*
* Find a (loaded) win32 module depending on path
* LPCSTR path: [in] pathname of module/library to be found
*
* The loader_section must be locked while calling this function
* RETURNS
* the module handle if found
* 0 if not
*/
WINE_MODREF *MODULE_FindModule(LPCSTR path)
{
WINE_MODREF *wm;
PLIST_ENTRY mark, entry;
PLDR_MODULE mod;
char dllname[260], *p;
/* Append .DLL to name if no extension present */
strcpy( dllname, path );
if (!(p = strrchr( dllname, '.')) || strchr( p, '/' ) || strchr( p, '\\'))
strcat( dllname, ".DLL" );
if ((wm = cached_modref) != NULL)
{
if ( !FILE_strcasecmp( dllname, wm->modname ) ) return wm;
if ( !FILE_strcasecmp( dllname, wm->filename ) ) return wm;
if ( !FILE_strcasecmp( dllname, wm->short_modname ) ) return wm;
if ( !FILE_strcasecmp( dllname, wm->short_filename ) ) return wm;
}
mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
for (entry = mark->Flink; entry != mark; entry = entry->Flink)
{
mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
if ( !FILE_strcasecmp( dllname, wm->modname ) ) break;
if ( !FILE_strcasecmp( dllname, wm->filename ) ) break;
if ( !FILE_strcasecmp( dllname, wm->short_modname ) ) break;
if ( !FILE_strcasecmp( dllname, wm->short_filename ) ) break;
}
if (entry == mark) wm = NULL;
cached_modref = wm;
return wm;
}
/******************************************************************
* LdrLockLoaderLock (NTDLL.@)
*
......@@ -906,7 +908,7 @@ NTSTATUS WINAPI LdrGetDllHandle(ULONG x, ULONG y, PUNICODE_STRING name, HMODULE
/* FIXME: we should store module name information as unicode */
RtlUnicodeStringToAnsiString( &str, name, TRUE );
wm = MODULE_FindModule( str.Buffer );
wm = find_module( str.Buffer );
RtlFreeAnsiString( &str );
if (!wm)
......@@ -957,6 +959,97 @@ NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, PANSI_STRING name, ULONG
/***********************************************************************
* load_builtin_callback
*
* Load a library in memory; callback function for wine_dll_register
*/
static void load_builtin_callback( void *module, const char *filename )
{
IMAGE_NT_HEADERS *nt;
WINE_MODREF *wm;
char *fullname;
DWORD len;
if (!module)
{
ERR("could not map image for %s\n", filename ? filename : "main exe" );
return;
}
if (!(nt = RtlImageNtHeader( module )))
{
ERR( "bad module for %s\n", filename ? filename : "main exe" );
last_builtin_status = STATUS_INVALID_IMAGE_FORMAT;
return;
}
if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL))
{
/* if we already have an executable, ignore this one */
if (!NtCurrentTeb()->Peb->ImageBaseAddress)
NtCurrentTeb()->Peb->ImageBaseAddress = module;
return; /* don't create the modref here, will be done later on */
}
if (find_module( filename ))
MESSAGE( "Warning: loading builtin %s, but native version already present. "
"Expect trouble.\n", filename );
/* create the MODREF */
len = GetSystemDirectoryA( NULL, 0 );
if (!(fullname = RtlAllocateHeap( ntdll_get_process_heap(), 0, len + strlen(filename) + 1 )))
{
ERR( "can't load %s\n", filename );
last_builtin_status = STATUS_NO_MEMORY;
return;
}
GetSystemDirectoryA( fullname, len );
strcat( fullname, "\\" );
strcat( fullname, filename );
wm = MODULE_AllocModRef( module, fullname );
RtlFreeHeap( ntdll_get_process_heap(), 0, fullname );
if (!wm)
{
ERR( "can't load %s\n", filename );
last_builtin_status = STATUS_NO_MEMORY;
return;
}
wm->ldr.Flags |= LDR_WINE_INTERNAL;
/* fixup imports */
if (fixup_imports( wm ) != STATUS_SUCCESS)
{
/* the module has only be inserted in the load & memory order lists */
RemoveEntryList(&wm->ldr.InLoadOrderModuleList);
RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);
/* FIXME: free the modref */
last_builtin_status = STATUS_DLL_NOT_FOUND;
return;
}
TRACE( "loaded %s %p %p\n", filename, wm, module );
/* send the DLL load event */
SERVER_START_REQ( load_dll )
{
req->handle = 0;
req->base = module;
req->size = nt->OptionalHeader.SizeOfImage;
req->dbg_offset = nt->FileHeader.PointerToSymbolTable;
req->dbg_size = nt->FileHeader.NumberOfSymbols;
req->name = &wm->filename;
wine_server_add_data( req, wm->filename, strlen(wm->filename) );
wine_server_call( req );
}
SERVER_END_REQ;
/* setup relay debugging entry points */
if (TRACE_ON(relay)) RELAY_SetupDLL( module );
}
/***********************************************************************
* allocate_lib_dir
*
* helper for MODULE_LoadLibraryExA. Allocate space to hold the directory
......@@ -987,6 +1080,166 @@ static LPCSTR allocate_lib_dir(LPCSTR libname)
return result;
}
/******************************************************************************
* load_native_dll (internal)
*/
static NTSTATUS load_native_dll( LPCSTR name, DWORD flags, WINE_MODREF** pwm )
{
void *module;
HANDLE file, mapping;
OBJECT_ATTRIBUTES attr;
LARGE_INTEGER size;
IMAGE_NT_HEADERS *nt;
DWORD len = 0;
WINE_MODREF *wm;
NTSTATUS status;
UINT drive_type;
file = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
if (file == INVALID_HANDLE_VALUE)
{
/* keep it that way until we transform CreateFile into NtCreateFile */
return (GetLastError() == ERROR_FILE_NOT_FOUND) ?
STATUS_NO_SUCH_FILE : STATUS_INTERNAL_ERROR;
}
TRACE( "loading %s\n", debugstr_a(name) );
attr.Length = sizeof(attr);
attr.RootDirectory = 0;
attr.ObjectName = NULL;
attr.Attributes = 0;
attr.SecurityDescriptor = NULL;
attr.SecurityQualityOfService = NULL;
size.QuadPart = 0;
status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
&attr, &size, 0, SEC_IMAGE, file );
if (status != STATUS_SUCCESS) goto done;
module = NULL;
status = NtMapViewOfSection( mapping, GetCurrentProcess(),
&module, 0, 0, &size, &len, ViewShare, 0, PAGE_READONLY );
NtClose( mapping );
if (status != STATUS_SUCCESS) goto done;
/* create the MODREF */
if (!(wm = MODULE_AllocModRef( module, name )))
{
status = STATUS_NO_MEMORY;
goto done;
}
/* fixup imports */
if (!(flags & DONT_RESOLVE_DLL_REFERENCES))
{
if ((status = fixup_imports(wm)) != STATUS_SUCCESS)
{
/* the module has only be inserted in the load & memory order lists */
RemoveEntryList(&wm->ldr.InLoadOrderModuleList);
RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);
/* FIXME: there are several more dangling references
* left. Including dlls loaded by this dll before the
* failed one. Unrolling is rather difficult with the
* current structure and we can leave them lying
* around with no problems, so we don't care.
* As these might reference our wm, we don't free it.
*/
goto done;
}
}
else wm->ldr.Flags |= LDR_DONT_RESOLVE_REFS;
/* send DLL load event */
nt = RtlImageNtHeader( module );
drive_type = GetDriveTypeA( wm->filename );
SERVER_START_REQ( load_dll )
{
req->handle = file;
req->base = module;
req->size = nt->OptionalHeader.SizeOfImage;
req->dbg_offset = nt->FileHeader.PointerToSymbolTable;
req->dbg_size = nt->FileHeader.NumberOfSymbols;
req->name = &wm->filename;
/* don't keep the file handle open on removable media */
if (drive_type == DRIVE_REMOVABLE || drive_type == DRIVE_CDROM) req->handle = 0;
wine_server_add_data( req, wm->filename, strlen(wm->filename) );
wine_server_call( req );
}
SERVER_END_REQ;
if (TRACE_ON(snoop)) SNOOP_SetupDLL( module );
*pwm = wm;
status = STATUS_SUCCESS;
done:
NtClose( file );
return status;
}
/***********************************************************************
* load_builtin_dll
*/
static NTSTATUS load_builtin_dll( LPCSTR path, DWORD flags, WINE_MODREF** pwm )
{
char error[256], dllname[MAX_PATH], *p;
int file_exists;
LPCSTR name;
void *handle;
WINE_MODREF *wm;
/* Fix the name in case we have a full path and extension */
name = path;
if ((p = strrchr( name, '\\' ))) name = p + 1;
if ((p = strrchr( name, '/' ))) name = p + 1;
if (strlen(name) >= sizeof(dllname)-4) return STATUS_NO_SUCH_FILE;
strcpy( dllname, name );
p = strrchr( dllname, '.' );
if (!p) strcat( dllname, ".dll" );
for (p = dllname; *p; p++) *p = FILE_tolower(*p);
last_builtin_status = STATUS_SUCCESS;
/* load_library will modify last_builtin_status. Note also that load_library can be
* called several times, if the .so file we're loading has dependencies.
* last_builtin_status will gather all the errors we may get while loading all these
* libraries
*/
if (!(handle = wine_dll_load( dllname, error, sizeof(error), &file_exists )))
{
if (!file_exists)
{
/* The file does not exist -> WARN() */
WARN("cannot open .so lib for builtin %s: %s\n", name, error);
return STATUS_NO_SUCH_FILE;
}
/* ERR() for all other errors (missing functions, ...) */
ERR("failed to load .so lib for builtin %s: %s\n", name, error );
return STATUS_PROCEDURE_NOT_FOUND;
}
if (last_builtin_status != STATUS_SUCCESS) return last_builtin_status;
if (!(wm = find_module( path ))) wm = find_module( dllname );
if (!wm)
{
ERR( "loaded .so but dll %s still not found - 16-bit dll or version conflict.\n", dllname );
/* wine_dll_unload( handle );*/
return STATUS_INVALID_IMAGE_FORMAT;
}
wm->dlhandle = handle;
*pwm = wm;
return STATUS_SUCCESS;
}
/***********************************************************************
* load_dll (internal)
*
......@@ -1049,7 +1302,7 @@ static NTSTATUS load_dll( LPCSTR libname, DWORD flags, WINE_MODREF** pwm )
}
/* Check for already loaded module */
if (!(*pwm = MODULE_FindModule(filename)) && !FILE_contains_path(libname))
if (!(*pwm = find_module(filename)) && !FILE_contains_path(libname))
{
LPSTR fn = RtlAllocateHeap ( ntdll_get_process_heap(), 0, MAX_PATH + 1 );
if (fn)
......@@ -1064,7 +1317,7 @@ static NTSTATUS load_dll( LPCSTR libname, DWORD flags, WINE_MODREF** pwm )
strcpy ( fn, libname );
/* if the filename doesn't have an extension append .DLL */
if (!strrchr( fn, '.')) strcat( fn, ".dll" );
if ((*pwm = MODULE_FindModule( fn )) != NULL)
if ((*pwm = find_module( fn )) != NULL)
strcpy( filename, fn );
RtlFreeHeap( ntdll_get_process_heap(), 0, fn );
}
......@@ -1077,7 +1330,7 @@ static NTSTATUS load_dll( LPCSTR libname, DWORD flags, WINE_MODREF** pwm )
!(flags & DONT_RESOLVE_DLL_REFERENCES))
{
(*pwm)->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
PE_fixup_imports( *pwm );
fixup_imports( *pwm );
}
TRACE("Already loaded module '%s' at %p, count=%d\n", filename, (*pwm)->ldr.BaseAddress, (*pwm)->ldr.LoadCount);
if (allocated_libdir)
......@@ -1100,16 +1353,14 @@ static NTSTATUS load_dll( LPCSTR libname, DWORD flags, WINE_MODREF** pwm )
{
case LOADORDER_DLL:
TRACE("Trying native dll '%s'\n", filename);
nts = PE_LoadLibraryExA(filename, flags, pwm);
nts = load_native_dll(filename, flags, pwm);
filetype = "native";
break;
case LOADORDER_BI:
TRACE("Trying built-in '%s'\n", filename);
nts = BUILTIN32_LoadLibraryExA(filename, flags, pwm);
nts = load_builtin_dll(filename, flags, pwm);
filetype = "builtin";
break;
default:
nts = STATUS_INTERNAL_ERROR;
break;
......@@ -1505,3 +1756,24 @@ PVOID WINAPI RtlImageRvaToVa( const IMAGE_NT_HEADERS *nt, HMODULE module,
if (section) *section = sec;
return (char *)module + sec->PointerToRawData + (rva - sec->VirtualAddress);
}
/***********************************************************************
* BUILTIN32_Init
*
* Initialize loading callbacks and return HMODULE of main exe.
* 'main' is the main exe in case it was already loaded from a PE file.
*
* FIXME: this should be done differently once kernel is properly separated.
*/
HMODULE BUILTIN32_LoadExeModule( HMODULE main )
{
NtCurrentTeb()->Peb->ImageBaseAddress = main;
last_builtin_status = STATUS_SUCCESS;
wine_dll_set_callback( load_builtin_callback );
if (!NtCurrentTeb()->Peb->ImageBaseAddress)
MESSAGE( "No built-in EXE module loaded! Did you create a .spec file?\n" );
if (last_builtin_status != STATUS_SUCCESS)
MESSAGE( "Error while processing initial modules\n");
return NtCurrentTeb()->Peb->ImageBaseAddress;
}
......@@ -40,13 +40,12 @@ extern NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handl
const LARGE_INTEGER *timeout );
/* module handling */
extern WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename );
extern FARPROC RELAY_GetProcAddress( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
DWORD exp_size, FARPROC proc, const char *user );
extern FARPROC SNOOP_GetProcAddress( HMODULE hmod, IMAGE_EXPORT_DIRECTORY *exports, DWORD exp_size,
FARPROC origfun, DWORD ordinal );
extern void RELAY_SetupDLL( const char *module );
extern void SNOOP_SetupDLL( HMODULE hmod );
static inline HANDLE ntdll_get_process_heap(void)
{
......
......@@ -181,7 +181,6 @@ enum binary_type
/* module.c */
extern NTSTATUS MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved );
extern NTSTATUS MODULE_DllThreadAttach( LPVOID lpReserved );
extern WINE_MODREF *MODULE_FindModule( LPCSTR path );
extern enum binary_type MODULE_GetBinaryType( HANDLE hfile );
extern FARPROC16 WINAPI WIN32_GetProcAddress16( HMODULE hmodule, LPCSTR name );
extern void MODULE_WalkModref( DWORD id );
......@@ -216,20 +215,12 @@ extern void NE_CallUserSignalProc( HMODULE16 hModule, UINT16 code );
extern HRSRC PE_FindResourceW(HMODULE,LPCWSTR,LPCWSTR);
extern HRSRC PE_FindResourceExW(HMODULE,LPCWSTR,LPCWSTR,WORD);
/* loader/pe_image.c */
extern NTSTATUS PE_LoadLibraryExA(LPCSTR, DWORD, WINE_MODREF**);
extern HMODULE PE_LoadImage( HANDLE hFile, LPCSTR filename, DWORD flags );
extern WINE_MODREF *PE_CreateModule( HMODULE hModule, LPCSTR filename,
DWORD flags, HANDLE hFile, BOOL builtin );
extern DWORD PE_fixup_imports(WINE_MODREF *wm);
/* loader/loadorder.c */
extern BOOL MODULE_GetBuiltinPath( const char *libname, const char *ext, char *filename, UINT size );
extern void MODULE_GetLoadOrder( enum loadorder_type plo[], const char *path, BOOL win32 );
extern void MODULE_AddLoadOrderOption( const char *option );
/* relay32/builtin.c */
extern NTSTATUS BUILTIN32_LoadLibraryExA(LPCSTR name, DWORD flags, WINE_MODREF**);
extern HMODULE BUILTIN32_LoadExeModule( HMODULE main );
#endif /* __WINE_MODULE_H */
......@@ -23,7 +23,6 @@
#include <module.h>
extern void SNOOP_RegisterDLL(HMODULE,LPCSTR,DWORD,DWORD);
extern void SNOOP16_RegisterDLL(NE_MODULE*,LPCSTR);
extern FARPROC16 SNOOP16_GetProcAddress16(HMODULE16,DWORD,FARPROC16);
extern int SNOOP_ShowDebugmsgSnoop(const char *dll,int ord,const char *fname);
......
/*
* Copyright 1994 Eric Youndale & Erik Bos
* Copyright 1995 Martin von Lwis
* Copyright 1996-98 Marcus Meissner
*
* based on Eric Youndale's pe-test and:
* ftp.microsoft.com:/developr/MSDN/OctCD/PEFILE.ZIP
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Notes:
* Before you start changing something in this file be aware of the following:
*
* - There are several functions called recursively. In a very subtle and
* obscure way. DLLs can reference each other recursively etc.
* - If you want to enhance, speed up or clean up something in here, think
* twice WHY it is implemented in that strange way. There is usually a reason.
* Though sometimes it might just be lazyness ;)
* - In PE_MapImage, right before PE_fixup_imports() all external and internal
* state MUST be correct since this function can be called with the SAME image
* AGAIN. (Thats recursion for you.) That means MODREF.module and
* NE_MODULE.module32.
*/
#include "config.h"
#include <sys/types.h>
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
#include <stdarg.h>
#include <string.h>
#include "ntstatus.h"
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "snoop.h"
#include "wine/server.h"
#include "wine/debug.h"
#include "ntdll_misc.h"
WINE_DEFAULT_DEBUG_CHANNEL(win32);
WINE_DECLARE_DEBUG_CHANNEL(module);
WINE_DECLARE_DEBUG_CHANNEL(relay);
/* convert PE image VirtualAddress to Real Address */
inline static void *get_rva( HMODULE module, DWORD va )
{
return (void *)((char *)module + va);
}
#define AdjustPtr(ptr,delta) ((char *)(ptr) + (delta))
void dump_exports( HMODULE hModule )
{
char *Module;
int i, j;
WORD *ordinal;
DWORD *function,*functions;
DWORD *name;
IMAGE_EXPORT_DIRECTORY *pe_exports;
DWORD rva_start, size;
pe_exports = RtlImageDirectoryEntryToData( hModule, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size );
rva_start = (char *)pe_exports - (char *)hModule;
Module = get_rva(hModule, pe_exports->Name);
DPRINTF("*******EXPORT DATA*******\n");
DPRINTF("Module name is %s, %ld functions, %ld names\n",
Module, pe_exports->NumberOfFunctions, pe_exports->NumberOfNames);
ordinal = get_rva(hModule, pe_exports->AddressOfNameOrdinals);
functions = function = get_rva(hModule, pe_exports->AddressOfFunctions);
name = get_rva(hModule, pe_exports->AddressOfNames);
DPRINTF(" Ord RVA Addr Name\n" );
for (i=0;i<pe_exports->NumberOfFunctions;i++, function++)
{
if (!*function) continue; /* No such function */
DPRINTF( "%4ld %08lx %p", i + pe_exports->Base, *function, get_rva(hModule, *function) );
/* Check if we have a name for it */
for (j = 0; j < pe_exports->NumberOfNames; j++)
if (ordinal[j] == i)
{
DPRINTF( " %s", (char*)get_rva(hModule, name[j]) );
break;
}
if ((*function >= rva_start) && (*function <= rva_start + size))
DPRINTF(" (forwarded -> %s)", (char *)get_rva(hModule, *function));
DPRINTF("\n");
}
}
/**********************************************************************
* PE_LoadImage
* Load one PE format DLL/EXE into memory
*
* Unluckily we can't just mmap the sections where we want them, for
* (at least) Linux does only support offsets which are page-aligned.
*
* BUT we have to map the whole image anyway, for Win32 programs sometimes
* want to access them. (HMODULE points to the start of it)
*/
HMODULE PE_LoadImage( HANDLE hFile, LPCSTR filename, DWORD flags )
{
IMAGE_NT_HEADERS *nt;
HMODULE hModule;
HANDLE mapping;
void *base = NULL;
OBJECT_ATTRIBUTES attr;
LARGE_INTEGER lg_int;
DWORD len = 0;
NTSTATUS nts;
TRACE_(module)( "loading %s\n", filename );
attr.Length = sizeof(attr);
attr.RootDirectory = 0;
attr.ObjectName = NULL;
attr.Attributes = 0;
attr.SecurityDescriptor = NULL;
attr.SecurityQualityOfService = NULL;
lg_int.QuadPart = 0;
if (NtCreateSection( &mapping,
STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
&attr, &lg_int, 0, SEC_IMAGE, hFile ) != STATUS_SUCCESS)
return 0;
nts = NtMapViewOfSection( mapping, GetCurrentProcess(),
&base, 0, 0, &lg_int, &len, ViewShare, 0,
PAGE_READONLY );
NtClose( mapping );
if (nts != STATUS_SUCCESS) return 0;
/* virus check */
hModule = (HMODULE)base;
nt = RtlImageNtHeader( hModule );
if (nt->OptionalHeader.AddressOfEntryPoint)
{
if (!RtlImageRvaToSection( nt, hModule, nt->OptionalHeader.AddressOfEntryPoint ))
MESSAGE("VIRUS WARNING: PE module has an invalid entrypoint (0x%08lx) "
"outside all sections (possibly infected by Tchernobyl/SpaceFiller virus)!\n",
nt->OptionalHeader.AddressOfEntryPoint );
}
return hModule;
}
/**********************************************************************
* PE_CreateModule
*
* Create WINE_MODREF structure for loaded HMODULE, link it into
* process modref_list, and fixup all imports.
*
* Note: hModule must point to a correctly allocated PE image,
* with base relocations applied; the 16-bit dummy module
* associated to hModule must already exist.
*
* Note: This routine must always be called in the context of the
* process that is to own the module to be created.
*
* Note: Assumes that the process critical section is held
*/
WINE_MODREF *PE_CreateModule( HMODULE hModule, LPCSTR filename, DWORD flags,
HANDLE hFile, BOOL builtin )
{
IMAGE_NT_HEADERS *nt;
IMAGE_DATA_DIRECTORY *dir;
IMAGE_EXPORT_DIRECTORY *pe_export = NULL;
WINE_MODREF *wm;
/* Retrieve DataDirectory entries */
nt = RtlImageNtHeader(hModule);
dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_EXPORT;
if (dir->Size) pe_export = get_rva(hModule, dir->VirtualAddress);
dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_EXCEPTION;
if (dir->Size) FIXME("Exception directory ignored\n" );
dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_SECURITY;
if (dir->Size) FIXME("Security directory ignored\n" );
/* IMAGE_DIRECTORY_ENTRY_BASERELOC handled in PE_LoadImage */
/* IMAGE_DIRECTORY_ENTRY_DEBUG handled by debugger */
dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_GLOBALPTR;
if (dir->Size) FIXME("Global Pointer (MIPS) ignored\n" );
/* IMAGE_DIRECTORY_ENTRY_TLS handled in PE_TlsInit */
dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG;
if (dir->Size) FIXME("Load Configuration directory ignored\n" );
dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT;
if (dir->Size) TRACE("Bound Import directory ignored\n" );
dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_IAT;
if (dir->Size) TRACE("Import Address Table directory ignored\n" );
dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT;
if (dir->Size)
{
TRACE("Delayed import, stub calls LoadLibrary\n" );
/*
* Nothing to do here.
*/
#ifdef ImgDelayDescr
/*
* This code is useful to observe what the heck is going on.
*/
{
ImgDelayDescr *pe_delay = NULL;
pe_delay = get_rva(hModule, dir->VirtualAddress);
TRACE("pe_delay->grAttrs = %08x\n", pe_delay->grAttrs);
TRACE("pe_delay->szName = %s\n", pe_delay->szName);
TRACE("pe_delay->phmod = %08x\n", pe_delay->phmod);
TRACE("pe_delay->pIAT = %08x\n", pe_delay->pIAT);
TRACE("pe_delay->pINT = %08x\n", pe_delay->pINT);
TRACE("pe_delay->pBoundIAT = %08x\n", pe_delay->pBoundIAT);
TRACE("pe_delay->pUnloadIAT = %08x\n", pe_delay->pUnloadIAT);
TRACE("pe_delay->dwTimeStamp = %08x\n", pe_delay->dwTimeStamp);
}
#endif /* ImgDelayDescr */
}
dir = nt->OptionalHeader.DataDirectory+IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR;
if (dir->Size) FIXME("Unknown directory 14 ignored\n" );
dir = nt->OptionalHeader.DataDirectory+15;
if (dir->Size) FIXME("Unknown directory 15 ignored\n" );
/* Allocate and fill WINE_MODREF */
if (!(wm = MODULE_AllocModRef( hModule, filename ))) return NULL;
if ( builtin )
wm->ldr.Flags |= LDR_WINE_INTERNAL;
else if ( flags & DONT_RESOLVE_DLL_REFERENCES )
wm->ldr.Flags |= LDR_DONT_RESOLVE_REFS;
/* Dump Exports */
if (pe_export && TRACE_ON(win32))
dump_exports( hModule );
/* Fixup Imports */
if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS) &&
PE_fixup_imports( wm ))
{
/* the module has only be inserted in the load & memory order lists */
RemoveEntryList(&wm->ldr.InLoadOrderModuleList);
RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);
/* FIXME: there are several more dangling references
* left. Including dlls loaded by this dll before the
* failed one. Unrolling is rather difficult with the
* current structure and we can leave them lying
* around with no problems, so we don't care.
* As these might reference our wm, we don't free it.
*/
return NULL;
}
if (!builtin && pe_export)
SNOOP_RegisterDLL( hModule, wm->modname, pe_export->Base, pe_export->NumberOfFunctions );
/* Send DLL load event */
/* we don't need to send a dll event for the main exe */
if (nt->FileHeader.Characteristics & IMAGE_FILE_DLL)
{
if (hFile)
{
UINT drive_type = GetDriveTypeA( wm->short_filename );
/* don't keep the file handle open on removable media */
if (drive_type == DRIVE_REMOVABLE || drive_type == DRIVE_CDROM) hFile = 0;
}
SERVER_START_REQ( load_dll )
{
req->handle = hFile;
req->base = (void *)hModule;
req->size = nt->OptionalHeader.SizeOfImage;
req->dbg_offset = nt->FileHeader.PointerToSymbolTable;
req->dbg_size = nt->FileHeader.NumberOfSymbols;
req->name = &wm->filename;
wine_server_add_data( req, wm->filename, strlen(wm->filename) );
wine_server_call( req );
}
SERVER_END_REQ;
}
return wm;
}
/******************************************************************************
* The PE Library Loader frontend.
* FIXME: handle the flags.
*/
NTSTATUS PE_LoadLibraryExA (LPCSTR name, DWORD flags, WINE_MODREF** pwm)
{
HMODULE hModule32;
HANDLE hFile;
hFile = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, 0 );
if ( hFile == INVALID_HANDLE_VALUE )
{
/* keep it that way until we transform CreateFile into NtCreateFile */
return (GetLastError() == ERROR_FILE_NOT_FOUND) ?
STATUS_NO_SUCH_FILE : STATUS_INTERNAL_ERROR;
}
/* Load PE module */
hModule32 = PE_LoadImage( hFile, name, flags );
if (!hModule32)
{
CloseHandle( hFile );
return STATUS_INTERNAL_ERROR;
}
/* Create 32-bit MODREF */
if ( !(*pwm = PE_CreateModule( hModule32, name, flags, hFile, FALSE )) )
{
ERR( "can't load %s\n", name );
CloseHandle( hFile );
return STATUS_NO_MEMORY; /* FIXME */
}
CloseHandle( hFile );
return STATUS_SUCCESS;
}
/*
* Win32 builtin functions
*
* Copyright 1997 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "wine/port.h"
#include <assert.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
#include "ntstatus.h"
#include "windef.h"
#include "winbase.h"
#include "wine/winbase16.h"
#include "wine/library.h"
#include "module.h"
#include "file.h"
#include "ntdll_misc.h"
#include "wine/server.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(module);
WINE_DECLARE_DEBUG_CHANNEL(relay);
static HMODULE main_module;
static NTSTATUS last_status; /* use to gather all errors in callback */
/***********************************************************************
* load_library
*
* Load a library in memory; callback function for wine_dll_register
*/
static void load_library( void *base, const char *filename )
{
UNICODE_STRING wstr;
HMODULE module = (HMODULE)base, ret;
IMAGE_NT_HEADERS *nt;
WINE_MODREF *wm;
char *fullname;
DWORD len;
if (!base)
{
ERR("could not map image for %s\n", filename ? filename : "main exe" );
return;
}
if (!(nt = RtlImageNtHeader( module )))
{
ERR( "bad module for %s\n", filename ? filename : "main exe" );
last_status = STATUS_INVALID_IMAGE_FORMAT;
return;
}
if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL))
{
/* if we already have an executable, ignore this one */
if (!main_module) main_module = module;
return; /* don't create the modref here, will be done later on */
}
RtlCreateUnicodeStringFromAsciiz(&wstr, filename);
if (LdrGetDllHandle(0, 0, &wstr, &ret) == STATUS_SUCCESS)
MESSAGE( "Warning: loading builtin %s, but native version already present. "
"Expect trouble.\n", filename );
RtlFreeUnicodeString( &wstr );
len = GetSystemDirectoryA( NULL, 0 );
if (!(fullname = RtlAllocateHeap( ntdll_get_process_heap(), 0, len + strlen(filename) + 1 )))
{
ERR( "can't load %s\n", filename );
last_status = STATUS_NO_MEMORY;
return;
}
GetSystemDirectoryA( fullname, len );
strcat( fullname, "\\" );
strcat( fullname, filename );
/* Create 32-bit MODREF */
if (!(wm = PE_CreateModule( module, fullname, 0, 0, TRUE )))
{
ERR( "can't load %s\n", filename );
RtlFreeHeap( ntdll_get_process_heap(), 0, fullname );
last_status = STATUS_NO_MEMORY;
return;
}
TRACE( "loaded %s %p %p\n", fullname, wm, module );
RtlFreeHeap( ntdll_get_process_heap(), 0, fullname );
/* setup relay debugging entry points */
if (TRACE_ON(relay)) RELAY_SetupDLL( (void *)module );
}
/***********************************************************************
* BUILTIN32_LoadLibraryExA
*
* Partly copied from the original PE_ version.
*
*/
NTSTATUS BUILTIN32_LoadLibraryExA(LPCSTR path, DWORD flags, WINE_MODREF** pwm)
{
char error[256], dllname[MAX_PATH], *p;
int file_exists;
LPCSTR name;
void *handle;
/* Fix the name in case we have a full path and extension */
name = path;
if ((p = strrchr( name, '\\' ))) name = p + 1;
if ((p = strrchr( name, '/' ))) name = p + 1;
if (strlen(name) >= sizeof(dllname)-4) return STATUS_NO_SUCH_FILE;
strcpy( dllname, name );
p = strrchr( dllname, '.' );
if (!p) strcat( dllname, ".dll" );
for (p = dllname; *p; p++) *p = FILE_tolower(*p);
last_status = STATUS_SUCCESS;
/* load_library will modify last_status. Note also that load_library can be
* called several times, if the .so file we're loading has dependencies.
* last_status will gather all the errors we may get while loading all these
* libraries
*/
if (!(handle = wine_dll_load( dllname, error, sizeof(error), &file_exists )))
{
if (!file_exists)
{
/* The file does not exist -> WARN() */
WARN("cannot open .so lib for builtin %s: %s\n", name, error);
return STATUS_NO_SUCH_FILE;
}
/* ERR() for all other errors (missing functions, ...) */
ERR("failed to load .so lib for builtin %s: %s\n", name, error );
return STATUS_PROCEDURE_NOT_FOUND;
}
if (last_status != STATUS_SUCCESS) return last_status;
if (!((*pwm) = MODULE_FindModule( path ))) *pwm = MODULE_FindModule( dllname );
if (!*pwm)
{
ERR( "loaded .so but dll %s still not found - 16-bit dll or version conflict.\n", dllname );
/* wine_dll_unload( handle );*/
return STATUS_INVALID_IMAGE_FORMAT;
}
(*pwm)->dlhandle = handle;
return STATUS_SUCCESS;
}
/***********************************************************************
* BUILTIN32_Init
*
* Initialize loading callbacks and return HMODULE of main exe.
* 'main' is the main exe in case it was already loaded from a PE file.
*/
HMODULE BUILTIN32_LoadExeModule( HMODULE main )
{
main_module = main;
last_status = STATUS_SUCCESS;
wine_dll_set_callback( load_library );
if (!main_module)
MESSAGE( "No built-in EXE module loaded! Did you create a .spec file?\n" );
if (last_status != STATUS_SUCCESS)
MESSAGE( "Error while processing initial modules\n");
return main_module;
}
......@@ -142,47 +142,51 @@ int SNOOP_ShowDebugmsgSnoop(const char *dll, int ord, const char *fname) {
return 1;
}
void
SNOOP_RegisterDLL(HMODULE hmod,LPCSTR name,DWORD ordbase,DWORD nrofordinals) {
SNOOP_DLL **dll = &(firstdll);
char *s;
void *addr;
SIZE_T size;
TRACE("hmod=%p, name=%s, ordbase=%ld, nrofordinals=%ld\n",
hmod, name, ordbase, nrofordinals);
if (!TRACE_ON(snoop)) return;
while (*dll) {
if ((*dll)->hmod == hmod)
{
/* another dll, loaded at the same address */
addr = (*dll)->funs;
size = (*dll)->nrofordinals * sizeof(SNOOP_FUN);
NtFreeVirtualMemory(GetCurrentProcess(), &addr, &size, MEM_RELEASE);
break;
}
dll = &((*dll)->next);
}
*dll = RtlReAllocateHeap(ntdll_get_process_heap(),
HEAP_ZERO_MEMORY, *dll,
sizeof(SNOOP_DLL) + strlen(name));
(*dll)->hmod = hmod;
(*dll)->ordbase = ordbase;
(*dll)->nrofordinals = nrofordinals;
strcpy( (*dll)->name, name );
if ((s=strrchr((*dll)->name,'.')))
*s='\0';
size = nrofordinals * sizeof(SNOOP_FUN);
NtAllocateVirtualMemory(GetCurrentProcess(), &addr, NULL, &size,
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!addr) {
RtlFreeHeap(ntdll_get_process_heap(),0,*dll);
FIXME("out of memory\n");
return;
}
(*dll)->funs = addr;
memset((*dll)->funs,0,size);
void SNOOP_SetupDLL(HMODULE hmod)
{
SNOOP_DLL **dll = &firstdll;
char *p, *name;
void *addr;
SIZE_T size;
IMAGE_EXPORT_DIRECTORY *exports;
exports = RtlImageDirectoryEntryToData( hmod, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size );
if (!exports) return;
name = (char *)hmod + exports->Name;
TRACE("hmod=%p, name=%s\n", hmod, name);
while (*dll) {
if ((*dll)->hmod == hmod)
{
/* another dll, loaded at the same address */
addr = (*dll)->funs;
size = (*dll)->nrofordinals * sizeof(SNOOP_FUN);
NtFreeVirtualMemory(GetCurrentProcess(), &addr, &size, MEM_RELEASE);
break;
}
dll = &((*dll)->next);
}
*dll = RtlReAllocateHeap(ntdll_get_process_heap(),
HEAP_ZERO_MEMORY, *dll,
sizeof(SNOOP_DLL) + strlen(name));
(*dll)->hmod = hmod;
(*dll)->ordbase = exports->Base;
(*dll)->nrofordinals = exports->NumberOfFunctions;
strcpy( (*dll)->name, name );
p = (*dll)->name + strlen((*dll)->name) - 4;
if (p > (*dll)->name && !strcasecmp( p, ".dll" )) *p = 0;
size = exports->NumberOfFunctions * sizeof(SNOOP_FUN);
NtAllocateVirtualMemory(GetCurrentProcess(), &addr, NULL, &size,
MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!addr) {
RtlFreeHeap(ntdll_get_process_heap(),0,*dll);
FIXME("out of memory\n");
return;
}
(*dll)->funs = addr;
memset((*dll)->funs,0,size);
}
FARPROC SNOOP_GetProcAddress( HMODULE hmod, IMAGE_EXPORT_DIRECTORY *exports, DWORD exp_size,
......@@ -432,9 +436,10 @@ __ASM_GLOBAL_FUNC( SNOOP_Return,
".long " __ASM_NAME("SNOOP_DoReturn") ",0" );
#else /* !__i386__ */
void SNOOP_RegisterDLL(HMODULE hmod,LPCSTR name,DWORD nrofordinals, DWORD dw) {
if (!TRACE_ON(snoop)) return;
FIXME("snooping works only on i386 for now.\n");
void SNOOP_SetupDLL(HMODULE hmod)
{
FIXME("snooping works only on i386 for now.\n");
}
FARPROC SNOOP_GetProcAddress( HMODULE hmod, IMAGE_EXPORT_DIRECTORY *exports, DWORD exp_size,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment