From 34addf6dfee1d7db76eece1610ec43050168411d Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 29 Jul 2021 10:49:02 +0200 Subject: [PATCH] wow64: Add thunks for the process/thread creation syscalls. Signed-off-by: Alexandre Julliard --- dlls/wow64/Makefile.in | 1 + dlls/wow64/process.c | 396 +++++++++++++++++++++++++++++++++++++ dlls/wow64/struct32.h | 53 +++++ dlls/wow64/syscall.h | 7 + dlls/wow64/wow64_private.h | 7 + 5 files changed, 464 insertions(+) create mode 100644 dlls/wow64/process.c diff --git a/dlls/wow64/Makefile.in b/dlls/wow64/Makefile.in index f56d1f0aad9..4e806de3e82 100644 --- a/dlls/wow64/Makefile.in +++ b/dlls/wow64/Makefile.in @@ -6,6 +6,7 @@ EXTRADLLFLAGS = -nodefaultlibs -mno-cygwin -Wl,--image-base,0x6f000000 C_SRCS = \ file.c \ + process.c \ registry.c \ sync.c \ syscall.c \ diff --git a/dlls/wow64/process.c b/dlls/wow64/process.c new file mode 100644 index 00000000000..8f9ac3e6648 --- /dev/null +++ b/dlls/wow64/process.c @@ -0,0 +1,396 @@ +/* + * WoW64 process (and thread) functions + * + * Copyright 2021 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winbase.h" +#include "winnt.h" +#include "winternl.h" +#include "wow64_private.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wow); + + +static BOOL is_process_wow64( HANDLE handle ) +{ + ULONG_PTR info; + + if (handle == GetCurrentProcess()) return TRUE; + if (NtQueryInformationProcess( handle, ProcessWow64Information, &info, sizeof(info), NULL )) + return FALSE; + return !!info; +} + + +static RTL_USER_PROCESS_PARAMETERS *process_params_32to64( RTL_USER_PROCESS_PARAMETERS **params, + RTL_USER_PROCESS_PARAMETERS32 *params32 ) +{ + UNICODE_STRING image, dllpath, curdir, cmdline, title, desktop, shell, runtime; + RTL_USER_PROCESS_PARAMETERS *ret; + + *params = NULL; + if (RtlCreateProcessParametersEx( &ret, unicode_str_32to64( &image, ¶ms32->ImagePathName ), + unicode_str_32to64( &dllpath, ¶ms32->DllPath ), + unicode_str_32to64( &curdir, ¶ms32->CurrentDirectory.DosPath ), + unicode_str_32to64( &cmdline, ¶ms32->CommandLine ), + ULongToPtr( params32->Environment ), + unicode_str_32to64( &title, ¶ms32->WindowTitle ), + unicode_str_32to64( &desktop, ¶ms32->Desktop ), + unicode_str_32to64( &shell, ¶ms32->ShellInfo ), + unicode_str_32to64( &runtime, ¶ms32->RuntimeInfo ), + PROCESS_PARAMS_FLAG_NORMALIZED )) + return NULL; + + ret->DebugFlags = params32->DebugFlags; + ret->ConsoleHandle = LongToHandle( params32->ConsoleHandle ); + ret->ConsoleFlags = params32->ConsoleFlags; + ret->hStdInput = LongToHandle( params32->hStdInput ); + ret->hStdOutput = LongToHandle( params32->hStdOutput ); + ret->hStdError = LongToHandle( params32->hStdError ); + ret->dwX = params32->dwX; + ret->dwY = params32->dwY; + ret->dwXSize = params32->dwXSize; + ret->dwYSize = params32->dwYSize; + ret->dwXCountChars = params32->dwXCountChars; + ret->dwYCountChars = params32->dwYCountChars; + ret->dwFillAttribute = params32->dwFillAttribute; + ret->dwFlags = params32->dwFlags; + ret->wShowWindow = params32->wShowWindow; + ret->EnvironmentVersion = params32->EnvironmentVersion; + ret->PackageDependencyData = ULongToPtr( params32->PackageDependencyData ); + ret->ProcessGroupId = params32->ProcessGroupId; + ret->LoaderThreads = params32->LoaderThreads; + *params = ret; + return ret; +} + + +static void put_ps_create_info( PS_CREATE_INFO32 *info32, const PS_CREATE_INFO *info ) +{ + info32->State = info->State; + switch (info->State) + { + case PsCreateInitialState: + info32->InitState.InitFlags = info->InitState.InitFlags; + info32->InitState.AdditionalFileAccess = info->InitState.AdditionalFileAccess; + break; + case PsCreateFailOnSectionCreate: + info32->FailSection.FileHandle = HandleToLong( info->FailSection.FileHandle ); + break; + case PsCreateFailExeFormat: + info32->ExeFormat.DllCharacteristics = info->ExeFormat.DllCharacteristics; + break; + case PsCreateFailExeName: + info32->ExeName.IFEOKey = HandleToLong( info->ExeName.IFEOKey ); + break; + case PsCreateSuccess: + info32->SuccessState.OutputFlags = info->SuccessState.OutputFlags; + info32->SuccessState.FileHandle = HandleToLong( info->SuccessState.FileHandle ); + info32->SuccessState.SectionHandle = HandleToLong( info->SuccessState.SectionHandle ); + info32->SuccessState.UserProcessParametersNative = info->SuccessState.UserProcessParametersNative; + info32->SuccessState.UserProcessParametersWow64 = info->SuccessState.UserProcessParametersWow64; + info32->SuccessState.CurrentParameterFlags = info->SuccessState.CurrentParameterFlags; + info32->SuccessState.PebAddressNative = info->SuccessState.PebAddressNative; + info32->SuccessState.PebAddressWow64 = info->SuccessState.PebAddressWow64; + info32->SuccessState.ManifestAddress = info->SuccessState.ManifestAddress; + info32->SuccessState.ManifestSize = info->SuccessState.ManifestSize; + break; + default: + break; + } +} + + +static PS_ATTRIBUTE_LIST *ps_attributes_32to64( PS_ATTRIBUTE_LIST **attr, const PS_ATTRIBUTE_LIST32 *attr32 ) +{ + PS_ATTRIBUTE_LIST *ret; + ULONG i, count; + + if (!attr32) return NULL; + count = (attr32->TotalLength - sizeof(attr32->TotalLength)) / sizeof(PS_ATTRIBUTE32); + ret = Wow64AllocateTemp( offsetof(PS_ATTRIBUTE_LIST, Attributes[count]) ); + ret->TotalLength = offsetof( PS_ATTRIBUTE_LIST, Attributes[count] ); + for (i = 0; i < count; i++) + { + ret->Attributes[i].Attribute = attr32->Attributes[i].Attribute; + ret->Attributes[i].Size = attr32->Attributes[i].Size; + ret->Attributes[i].Value = attr32->Attributes[i].Value; + ret->Attributes[i].ReturnLength = NULL; + switch (ret->Attributes[i].Attribute) + { + case PS_ATTRIBUTE_IMAGE_NAME: + { + OBJECT_ATTRIBUTES attr; + UNICODE_STRING path; + + path.Length = ret->Attributes[i].Size; + path.Buffer = ret->Attributes[i].ValuePtr; + InitializeObjectAttributes( &attr, &path, OBJ_CASE_INSENSITIVE, 0, 0 ); + if (get_file_redirect( &attr )) + { + ret->Attributes[i].Size = attr.ObjectName->Length; + ret->Attributes[i].ValuePtr = attr.ObjectName->Buffer; + } + } + break; + case PS_ATTRIBUTE_HANDLE_LIST: + case PS_ATTRIBUTE_JOB_LIST: + { + ULONG j, handles_count = attr32->Attributes[i].Size / sizeof(ULONG); + + ret->Attributes[i].Size = handles_count * sizeof(HANDLE); + ret->Attributes[i].ValuePtr = Wow64AllocateTemp( ret->Attributes[i].Size ); + for (j = 0; j < handles_count; j++) + ((HANDLE *)ret->Attributes[i].ValuePtr)[j] = + LongToHandle( ((LONG *)ULongToPtr(attr32->Attributes[i].Value))[j] ); + } + break; + case PS_ATTRIBUTE_CLIENT_ID: + ret->Attributes[i].Size = sizeof(CLIENT_ID); + ret->Attributes[i].ValuePtr = Wow64AllocateTemp( ret->Attributes[i].Size ); + break; + case PS_ATTRIBUTE_IMAGE_INFO: + ret->Attributes[i].Size = sizeof(SECTION_IMAGE_INFORMATION); + ret->Attributes[i].ValuePtr = Wow64AllocateTemp( ret->Attributes[i].Size ); + break; + case PS_ATTRIBUTE_TEB_ADDRESS: + ret->Attributes[i].Size = sizeof(TEB *); + ret->Attributes[i].ValuePtr = Wow64AllocateTemp( ret->Attributes[i].Size ); + break; + } + } + *attr = ret; + return ret; +} + + +static void put_ps_attributes( PS_ATTRIBUTE_LIST32 *attr32, const PS_ATTRIBUTE_LIST *attr ) +{ + ULONG i; + + if (!attr32) return; + for (i = 0; i < (attr32->TotalLength - sizeof(attr32->TotalLength)) / sizeof(PS_ATTRIBUTE32); i++) + { + switch (attr->Attributes[i].Attribute) + { + case PS_ATTRIBUTE_CLIENT_ID: + { + CLIENT_ID32 id32; + ULONG size = min( attr32->Attributes[i].Size, sizeof(id32) ); + put_client_id( &id32, attr->Attributes[i].ValuePtr ); + memcpy( ULongToPtr( attr32->Attributes[i].Value ), &id32, size ); + if (attr32->Attributes[i].ReturnLength) + *(ULONG *)ULongToPtr(attr32->Attributes[i].ReturnLength) = size; + break; + } + case PS_ATTRIBUTE_IMAGE_INFO: + { + SECTION_IMAGE_INFORMATION32 info32; + ULONG size = min( attr32->Attributes[i].Size, sizeof(info32) ); + put_section_image_info( &info32, attr->Attributes[i].ValuePtr ); + memcpy( ULongToPtr( attr32->Attributes[i].Value ), &info32, size ); + if (attr32->Attributes[i].ReturnLength) + *(ULONG *)ULongToPtr(attr32->Attributes[i].ReturnLength) = size; + break; + } + case PS_ATTRIBUTE_TEB_ADDRESS: + { + TEB **teb = attr->Attributes[i].ValuePtr; + ULONG teb32 = PtrToUlong( *teb ) + 0x2000; + ULONG size = min( attr->Attributes[i].Size, sizeof(teb32) ); + memcpy( ULongToPtr( attr32->Attributes[i].Value ), &teb32, size ); + if (attr32->Attributes[i].ReturnLength) + *(ULONG *)ULongToPtr(attr32->Attributes[i].ReturnLength) = size; + break; + } + } + } +} + + +/********************************************************************** + * wow64_NtCreateThread + */ +NTSTATUS WINAPI wow64_NtCreateThread( UINT *args ) +{ + ULONG *handle_ptr = get_ptr( &args ); + ACCESS_MASK access = get_ulong( &args ); + OBJECT_ATTRIBUTES32 *attr32 = get_ptr( &args ); + HANDLE process = get_handle( &args ); + CLIENT_ID32 *id32 = get_ptr( &args ); + I386_CONTEXT *context = get_ptr( &args ); + void *initial_teb = get_ptr( &args ); + BOOLEAN suspended = get_ulong( &args ); + + FIXME( "%p %x %p %p %p %p %p %u: stub\n", handle_ptr, access, attr32, process, + id32, context, initial_teb, suspended ); + return STATUS_NOT_IMPLEMENTED; +} + + +/********************************************************************** + * wow64_NtCreateThreadEx + */ +NTSTATUS WINAPI wow64_NtCreateThreadEx( UINT *args ) +{ + ULONG *handle_ptr = get_ptr( &args ); + ACCESS_MASK access = get_ulong( &args ); + OBJECT_ATTRIBUTES32 *attr32 = get_ptr( &args ); + HANDLE process = get_handle( &args ); + PRTL_THREAD_START_ROUTINE start = get_ptr( &args ); + void *param = get_ptr( &args ); + ULONG flags = get_ulong( &args ); + ULONG_PTR zero_bits = get_ulong( &args ); + SIZE_T stack_commit = get_ulong( &args ); + SIZE_T stack_reserve = get_ulong( &args ); + PS_ATTRIBUTE_LIST32 *attr_list32 = get_ptr( &args ); + + struct object_attr64 attr; + PS_ATTRIBUTE_LIST *attr_list; + HANDLE handle = 0; + NTSTATUS status; + + *handle_ptr = 0; + if (is_process_wow64( process )) + { + status = NtCreateThreadEx( &handle, access, objattr_32to64( &attr, attr32 ), process, + start, param, flags, get_zero_bits( zero_bits ), + stack_commit, stack_reserve, + ps_attributes_32to64( &attr_list, attr_list32 )); + put_ps_attributes( attr_list32, attr_list ); + } + else status = STATUS_ACCESS_DENIED; + + put_handle( handle_ptr, handle ); + return status; +} + + +/********************************************************************** + * wow64_NtCreateUserProcess + */ +NTSTATUS WINAPI wow64_NtCreateUserProcess( UINT *args ) +{ + ULONG *process_handle_ptr = get_ptr( &args ); + ULONG *thread_handle_ptr = get_ptr( &args ); + ACCESS_MASK process_access = get_ulong( &args ); + ACCESS_MASK thread_access = get_ulong( &args ); + OBJECT_ATTRIBUTES32 *process_attr32 = get_ptr( &args ); + OBJECT_ATTRIBUTES32 *thread_attr32 = get_ptr( &args ); + ULONG process_flags = get_ulong( &args ); + ULONG thread_flags = get_ulong( &args ); + RTL_USER_PROCESS_PARAMETERS32 *params32 = get_ptr( &args ); + PS_CREATE_INFO32 *info32 = get_ptr( &args ); + PS_ATTRIBUTE_LIST32 *attr32 = get_ptr( &args ); + + struct object_attr64 process_attr, thread_attr; + RTL_USER_PROCESS_PARAMETERS *params; + PS_CREATE_INFO info; + PS_ATTRIBUTE_LIST *attr; + HANDLE process_handle = 0, thread_handle = 0; + + NTSTATUS status; + + *process_handle_ptr = *thread_handle_ptr = 0; + status = NtCreateUserProcess( &process_handle, &thread_handle, process_access, thread_access, + objattr_32to64( &process_attr, process_attr32 ), + objattr_32to64( &thread_attr, thread_attr32 ), + process_flags, thread_flags, + process_params_32to64( ¶ms, params32), + &info, ps_attributes_32to64( &attr, attr32 )); + put_handle( process_handle_ptr, process_handle ); + put_handle( thread_handle_ptr, thread_handle ); + put_ps_create_info( info32, &info ); + put_ps_attributes( attr32, attr ); + RtlDestroyProcessParameters( params ); + return status; +} + + +/********************************************************************** + * wow64_NtOpenProcess + */ +NTSTATUS WINAPI wow64_NtOpenProcess( UINT *args ) +{ + ULONG *handle_ptr = get_ptr( &args ); + ACCESS_MASK access = get_ulong( &args ); + OBJECT_ATTRIBUTES32 *attr32 = get_ptr( &args ); + CLIENT_ID32 *id32 = get_ptr( &args ); + + struct object_attr64 attr; + HANDLE handle = 0; + CLIENT_ID id; + NTSTATUS status; + + *handle_ptr = 0; + status = NtOpenProcess( &handle, access, objattr_32to64( &attr, attr32 ), client_id_32to64( &id, id32 )); + put_handle( handle_ptr, handle ); + return status; +} + + +/********************************************************************** + * wow64_NtOpenThread + */ +NTSTATUS WINAPI wow64_NtOpenThread( UINT *args ) +{ + ULONG *handle_ptr = get_ptr( &args ); + ACCESS_MASK access = get_ulong( &args ); + OBJECT_ATTRIBUTES32 *attr32 = get_ptr( &args ); + CLIENT_ID32 *id32 = get_ptr( &args ); + + struct object_attr64 attr; + HANDLE handle = 0; + CLIENT_ID id; + NTSTATUS status; + + *handle_ptr = 0; + status = NtOpenThread( &handle, access, objattr_32to64( &attr, attr32 ), client_id_32to64( &id, id32 )); + put_handle( handle_ptr, handle ); + return status; +} + + +/********************************************************************** + * wow64_NtTerminateProcess + */ +NTSTATUS WINAPI wow64_NtTerminateProcess( UINT *args ) +{ + HANDLE handle = get_handle( &args ); + LONG exit_code = get_ulong( &args ); + + return NtTerminateProcess( handle, exit_code ); +} + + +/********************************************************************** + * wow64_NtTerminateThread + */ +NTSTATUS WINAPI wow64_NtTerminateThread( UINT *args ) +{ + HANDLE handle = get_handle( &args ); + LONG exit_code = get_ulong( &args ); + + return NtTerminateThread( handle, exit_code ); +} diff --git a/dlls/wow64/struct32.h b/dlls/wow64/struct32.h index 258fa9f74c1..3a7ee75eab5 100644 --- a/dlls/wow64/struct32.h +++ b/dlls/wow64/struct32.h @@ -136,6 +136,59 @@ typedef struct MEMORY_WORKING_SET_EX_BLOCK32 VirtualAttributes; } MEMORY_WORKING_SET_EX_INFORMATION32; +typedef struct +{ + ULONG Size; + PS_CREATE_STATE State; + union + { + struct + { + ULONG InitFlags; + ACCESS_MASK AdditionalFileAccess; + } InitState; + struct + { + ULONG FileHandle; + } FailSection; + struct + { + USHORT DllCharacteristics; + } ExeFormat; + struct + { + ULONG IFEOKey; + } ExeName; + struct + { + ULONG OutputFlags; + ULONG FileHandle; + ULONG SectionHandle; + ULONGLONG UserProcessParametersNative; + ULONG UserProcessParametersWow64; + ULONG CurrentParameterFlags; + ULONGLONG PebAddressNative; + ULONG PebAddressWow64; + ULONGLONG ManifestAddress; + ULONG ManifestSize; + } SuccessState; + }; +} PS_CREATE_INFO32; + +typedef struct +{ + ULONG Attribute; + ULONG Size; + ULONG Value; + ULONG ReturnLength; +} PS_ATTRIBUTE32; + +typedef struct +{ + ULONG TotalLength; + PS_ATTRIBUTE32 Attributes[1]; +} PS_ATTRIBUTE_LIST32; + typedef struct { ULONG BaseAddress; diff --git a/dlls/wow64/syscall.h b/dlls/wow64/syscall.h index 93896ae4ca3..e2238e34186 100644 --- a/dlls/wow64/syscall.h +++ b/dlls/wow64/syscall.h @@ -55,7 +55,10 @@ SYSCALL_ENTRY( NtCreateSection ) \ SYSCALL_ENTRY( NtCreateSemaphore ) \ SYSCALL_ENTRY( NtCreateSymbolicLinkObject ) \ + SYSCALL_ENTRY( NtCreateThread ) \ + SYSCALL_ENTRY( NtCreateThreadEx ) \ SYSCALL_ENTRY( NtCreateTimer ) \ + SYSCALL_ENTRY( NtCreateUserProcess ) \ SYSCALL_ENTRY( NtDebugContinue ) \ SYSCALL_ENTRY( NtDelayExecution ) \ SYSCALL_ENTRY( NtDeleteAtom ) \ @@ -92,9 +95,11 @@ SYSCALL_ENTRY( NtOpenKeyTransactedEx ) \ SYSCALL_ENTRY( NtOpenKeyedEvent ) \ SYSCALL_ENTRY( NtOpenMutant ) \ + SYSCALL_ENTRY( NtOpenProcess ) \ SYSCALL_ENTRY( NtOpenSection ) \ SYSCALL_ENTRY( NtOpenSemaphore ) \ SYSCALL_ENTRY( NtOpenSymbolicLinkObject ) \ + SYSCALL_ENTRY( NtOpenThread ) \ SYSCALL_ENTRY( NtOpenTimer ) \ SYSCALL_ENTRY( NtProtectVirtualMemory ) \ SYSCALL_ENTRY( NtPulseEvent ) \ @@ -156,6 +161,8 @@ SYSCALL_ENTRY( NtSetVolumeInformationFile ) \ SYSCALL_ENTRY( NtSignalAndWaitForSingleObject ) \ SYSCALL_ENTRY( NtTerminateJobObject ) \ + SYSCALL_ENTRY( NtTerminateProcess ) \ + SYSCALL_ENTRY( NtTerminateThread ) \ SYSCALL_ENTRY( NtUnloadKey ) \ SYSCALL_ENTRY( NtUnlockFile ) \ SYSCALL_ENTRY( NtUnlockVirtualMemory ) \ diff --git a/dlls/wow64/wow64_private.h b/dlls/wow64/wow64_private.h index 9f2f8b8af5b..09af40a2fb0 100644 --- a/dlls/wow64/wow64_private.h +++ b/dlls/wow64/wow64_private.h @@ -197,6 +197,13 @@ static inline void put_size( ULONG *size32, SIZE_T size ) if (size32) *size32 = min( size, MAXDWORD ); } +static inline void put_client_id( CLIENT_ID32 *id32, const CLIENT_ID *id ) +{ + if (!id32) return; + id32->UniqueProcess = HandleToLong( id->UniqueProcess ); + id32->UniqueThread = HandleToLong( id->UniqueThread ); +} + static inline void put_iosb( IO_STATUS_BLOCK32 *io32, const IO_STATUS_BLOCK *io ) { /* sync I/O modifies the 64-bit iosb right away, so in that case we update the 32-bit one */