[PATCH 1/3] winebuild: Added support for entry points generated in runtime.

Jacek Caban jacek at codeweavers.com
Thu Jan 21 09:58:31 CST 2016


On 01/21/16 16:04, Sebastian Lackner wrote:
> On 21.01.2016 15:43, Jacek Caban wrote:
>> On 01/19/16 17:06, Alexandre Julliard wrote:
>>> Jacek Caban <jacek at codeweavers.com> writes:
>>>
>>>> All such solutions require changes in both Chrome and Wine, which makes
>>>> it tricky to decide on a solution. What's your opinion?
>>> My concern is not just about hooking the system calls, it's what happens
>>> once they are hooked. Sebastian said that hooks inside the Ldr*
>>> functions don't work right. I'm worried that supporting this properly
>>> would require that our internal code paths follow the Windows ones
>>> closely, which is neither feasible nor desirable.
>>>
>>> This could of course also be changed in Chrome so that it could deal
>>> with the way Wine's ntdll is implemented, but that would probably be
>>> more intrusive.
>> It's hard to discuss what Sebastian reports without understanding the
>> problem. For what I know, his variant of patches exposes way more
>> hookable calls than it should. It's not a secret that on Windows Nt*
>> functions will not call any other exported functions. This is an
>> implementation detail that I don't consider too internal to follow. The
>> fact that those hooks may be called recursively with Sebastian's patches
>> makes me think that it's the most likely reason of the problems.
> Could you please point out where you think my patchset doesn't match
> Windows behavior / leads to recursive calls which should not occur?

I looked deeper in your patchset and the one occur that I thought was
there was my mistake.


> Or, have you already tried improving your patchset, to implement forwarding
> of Ldr* and Rtl* functions through the thunks, like it is supposed to work
> on Windows? I would guess you encounter exactly the same problem.

Yes, I tried that. See the attached patch (note that SYSCALL macro has
an opposite meaning comparing to your patches) on top of my patchset. I
couldn't reproduce the problem with Steam. It still works for me 100% of
time.

I tried to compare it with your version, but, as I wrote you, it didn't
work for me at all. I assume I'm missing something.

>> For other internal behaviour, we already have cases where they do
>> matter. My recent example is Office 2013 online installer (which has
>> sandbox-like code that among others merges some special dirs, sometimes
>> containing DLLs, into file system). It's obvious that we need
>> NtOpenFile-alike in loader to open a file in loader and all changes that
>> it required was to pass SYNCHRONIZE flag. For all I know native may use
>> different APIs there, but all is fine using this call as long as we pass
>> an argument that is sane and makes sense anyway.
>>
>> That said, I fully agree that we don't want to follow Windows too
>> closely, but I don't think we're at this point yet. Also, my variant of
>> the patch (others could be reworked to follow that as well) exposes even
>> less internal behaviour than existing code, because we need to
>> explicitly mark parts that would go through exported thunks.
>>
>> Here is my proposal for fixing the situation:
>>
>> Short term we use one of variants of patches for syscall thunks. This
>> will give an immediate fix for at lest some (most common?) Wine configs.
> If the issues with Ldr* functions can be solved I'm fine with that. However,
> I wouldn't necessarily recommend the JIT approach if we have only one supported
> config. Lets assume we would use winebuild statically generated thunks (like my
> patch based on Erichs work), the additional logic for JIT could be implemented
> at any time later.

Sure, in that case we won't need the flexibility of JIT, so static
thunks should be fine. I still think we could avoid text relocations,
but that's a different topic.

Thanks,
Jacek
-------------- next part --------------
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index 6529105..10360e2 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -620,7 +620,7 @@ static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *d
     while (import_list[protect_size].u1.Ordinal) protect_size++;
     protect_base = thunk_list;
     protect_size *= sizeof(*thunk_list);
-    NtProtectVirtualMemory( NtCurrentProcess(), &protect_base,
+    SYSCALL(NtProtectVirtualMemory)( NtCurrentProcess(), &protect_base,
                             &protect_size, PAGE_READWRITE, &protect_old );
 
     imp_mod = wmImp->ldr.BaseAddress;
@@ -692,7 +692,7 @@ static WINE_MODREF *import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *d
 
 done:
     /* restore old protection of the import address table */
-    NtProtectVirtualMemory( NtCurrentProcess(), &protect_base, &protect_size, protect_old, &protect_old );
+    SYSCALL(NtProtectVirtualMemory)( NtCurrentProcess(), &protect_base, &protect_size, protect_old, &protect_old );
     return wmImp;
 }
 
@@ -1475,7 +1475,7 @@ static BOOL is_fake_dll( HANDLE handle )
     LARGE_INTEGER offset;
 
     offset.QuadPart = 0;
-    if (NtReadFile( handle, 0, NULL, 0, &io, buffer, sizeof(buffer), &offset, NULL )) return FALSE;
+    if (SYSCALL(NtReadFile)( handle, 0, NULL, 0, &io, buffer, sizeof(buffer), &offset, NULL )) return FALSE;
     if (io.Information < sizeof(buffer)) return FALSE;
     if (dos->e_magic != IMAGE_DOS_SIGNATURE) return FALSE;
     if (dos->e_lfanew >= sizeof(*dos) + sizeof(fakedll_signature) &&
@@ -1774,12 +1774,12 @@ static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file,
     TRACE("Trying native dll %s\n", debugstr_w(name));
 
     size.QuadPart = 0;
-    status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
+    status = SYSCALL(NtCreateSection)( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
                               NULL, &size, PAGE_EXECUTE_READ, SEC_IMAGE, file );
     if (status != STATUS_SUCCESS) return status;
 
     module = NULL;
-    status = NtMapViewOfSection( mapping, NtCurrentProcess(),
+    status = SYSCALL(NtMapViewOfSection)( mapping, NtCurrentProcess(),
                                  &module, 0, 0, &size, &len, ViewShare, 0, PAGE_EXECUTE_READ );
 
     /* perform base relocation, if necessary */
@@ -1789,7 +1789,7 @@ static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file,
 
     if (status != STATUS_SUCCESS)
     {
-        if (module) NtUnmapViewOfSection( NtCurrentProcess(), module );
+        if (module) SYSCALL(NtUnmapViewOfSection)( NtCurrentProcess(), module );
         goto done;
     }
 
@@ -1851,7 +1851,7 @@ static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file,
     *pwm = wm;
     status = STATUS_SUCCESS;
 done:
-    NtClose( mapping );
+    SYSCALL(NtClose)( mapping );
     return status;
 }
 
@@ -2247,7 +2247,7 @@ static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_
     if (handle && is_fake_dll( handle ))
     {
         TRACE( "%s is a fake Wine dll\n", debugstr_w(filename) );
-        NtClose( handle );
+        SYSCALL(NtClose)( handle );
         handle = 0;
     }
 
@@ -2299,13 +2299,13 @@ static NTSTATUS load_dll( LPCWSTR load_path, LPCWSTR libname, DWORD flags, WINE_
         TRACE("Loaded module %s (%s) at %p\n", debugstr_w(filename),
               ((*pwm)->ldr.Flags & LDR_WINE_INTERNAL) ? "builtin" : "native",
               (*pwm)->ldr.BaseAddress);
-        if (handle) NtClose( handle );
+        if (handle) SYSCALL(NtClose)( handle );
         if (filename != buffer) RtlFreeHeap( GetProcessHeap(), 0, filename );
         return nts;
     }
 
     WARN("Failed to load module %s; status=%x\n", debugstr_w(libname), nts);
-    if (handle) NtClose( handle );
+    if (handle) SYSCALL(NtClose)( handle );
     if (filename != buffer) RtlFreeHeap( GetProcessHeap(), 0, filename );
     return nts;
 }
@@ -2579,7 +2579,7 @@ static NTSTATUS query_string_option( HANDLE hkey, LPCWSTR name, ULONG type,
     size = info_size + in_size;
     if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, size ))) return STATUS_NO_MEMORY;
     info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
-    status = NtQueryValueKey( hkey, &str, KeyValuePartialInformation, buffer, size, &size );
+    status = SYSCALL(NtQueryValueKey)( hkey, &str, KeyValuePartialInformation, buffer, size, &size );
     if (!status || status == STATUS_BUFFER_OVERFLOW)
     {
         if (out_size) *out_size = info->DataLength;
@@ -2626,7 +2626,7 @@ NTSTATUS WINAPI LdrQueryImageFileExecutionOptions( const UNICODE_STRING *key, LP
     name_str.MaximumLength = name_str.Length;
     memcpy( path, optionsW, sizeof(optionsW) );
     memcpy( path + sizeof(optionsW)/sizeof(WCHAR), p, len );
-    if ((status = NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr ))) return status;
+    if ((status = SYSCALL(NtOpenKey)( &hkey, KEY_QUERY_VALUE, &attr ))) return status;
 
     if (type == REG_DWORD)
     {
@@ -2636,7 +2636,7 @@ NTSTATUS WINAPI LdrQueryImageFileExecutionOptions( const UNICODE_STRING *key, LP
     }
     else status = query_string_option( hkey, value, type, data, in_size, out_size );
 
-    NtClose( hkey );
+    SYSCALL(NtClose)( hkey );
     return status;
 }
 
@@ -2733,9 +2733,9 @@ void WINAPI RtlExitUserProcess( DWORD status )
 {
     RtlEnterCriticalSection( &loader_section );
     RtlAcquirePebLock();
-    NtTerminateProcess( 0, status );
+    SYSCALL(NtTerminateProcess)( 0, status );
     LdrShutdownProcess();
-    NtTerminateProcess( GetCurrentProcess(), status );
+    SYSCALL(NtTerminateProcess)( GetCurrentProcess(), status );
     exit( status );
 }
 
@@ -2813,7 +2813,7 @@ static void free_modref( WINE_MODREF *wm )
     free_tls_slot( &wm->ldr );
     RtlReleaseActivationContext( wm->ldr.ActivationContext );
     if (wm->ldr.Flags & LDR_WINE_INTERNAL) wine_dll_unload( wm->ldr.SectionHandle );
-    NtUnmapViewOfSection( NtCurrentProcess(), wm->ldr.BaseAddress );
+    SYSCALL(NtUnmapViewOfSection)( NtCurrentProcess(), wm->ldr.BaseAddress );
     if (cached_modref == wm) cached_modref = NULL;
     RtlFreeUnicodeString( &wm->ldr.FullDllName );
     RtlFreeHeap( GetProcessHeap(), 0, wm->deps );
@@ -3053,7 +3053,7 @@ void WINAPI LdrInitializeThunk( void *kernel_start, ULONG_PTR unknown2,
     LPCWSTR load_path;
     PEB *peb = NtCurrentTeb()->Peb;
 
-    if (main_exe_file) NtClose( main_exe_file );  /* at this point the main module is created */
+    if (main_exe_file) SYSCALL(NtClose)( main_exe_file );  /* at this point the main module is created */
 
     /* allocate the modref for the main exe (if not already done) */
     wm = get_modref( peb->ImageBaseAddress );
@@ -3096,7 +3096,7 @@ void WINAPI LdrInitializeThunk( void *kernel_start, ULONG_PTR unknown2,
 error:
     ERR( "Main exe initialization for %s failed, status %x\n",
          debugstr_w(peb->ProcessParameters->ImagePathName.Buffer), status );
-    NtTerminateProcess( GetCurrentProcess(), status );
+    SYSCALL(NtTerminateProcess)( GetCurrentProcess(), status );
 }
 
 
diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
index f185eb9..254e527 100644
--- a/dlls/ntdll/ntdll_misc.h
+++ b/dlls/ntdll/ntdll_misc.h
@@ -273,6 +273,16 @@ NTSTATUS WINAPI RtlHashUnicodeString(PCUNICODE_STRING,BOOLEAN,ULONG,ULONG*);
     extern typeof( name ) __jit_ ## name
 
 DECLARE_SYSCALL_ENTRYPOINT( NtOpenFile );
+DECLARE_SYSCALL_ENTRYPOINT( NtAllocateVirtualMemory );
+DECLARE_SYSCALL_ENTRYPOINT( NtProtectVirtualMemory );
+DECLARE_SYSCALL_ENTRYPOINT( NtReadFile );
+DECLARE_SYSCALL_ENTRYPOINT( NtCreateSection );
+DECLARE_SYSCALL_ENTRYPOINT( NtMapViewOfSection );
+DECLARE_SYSCALL_ENTRYPOINT( NtUnmapViewOfSection );
+DECLARE_SYSCALL_ENTRYPOINT( NtClose );
+DECLARE_SYSCALL_ENTRYPOINT( NtQueryValueKey );
+DECLARE_SYSCALL_ENTRYPOINT( NtOpenKey );
+DECLARE_SYSCALL_ENTRYPOINT( NtTerminateProcess );
 
 #else /* defined(__i386__) */
 


More information about the wine-devel mailing list