wine. windows nt architecture wine architecture socket pipe
TRANSCRIPT
Wine Directory Structure
• server/– wineserver
–Windows abstract object (mailslot, mutex, … etc)
• dlls/–Windows DLL
• loader/–Wine call a preloader to reserve memory space for
Windows application
Wine Overview
Windows App
Windows EXEWindows EXE
Kernel32.DLLKernel32.DLL
NTDLL.DLLNTDLL.DLL
wineserver
socket
pipe
• Client send request to wineserver through the pipe• winserver poll request then call corresponding handler
Load Windows Binary - Part 1
• Example– wine → wine_preloader → wine → notepad.exe
– They are the same process but with different image
• wine check a environment variable too see if preloader already ran before, and when wine_preloader finish its job, it reload wine image and start to load Windows application (i.e., notepad.exe)
Load Windows Binary - Part 1
• wine_preloader– Use customized entry function _start
– _start call wld_start to reserve memory space for Windows PE binary, then jump to dynamic linker return by wld_start
Load Windows Binary - Part 2
• Since preloader already ran, we are ready to start the real and complicate job– wine → wine_preloader → wine → notepad.exe
Load Windows Binary - Part 2
• wine → wine_init– wine_init → __wine_process_init (NTDLL.DLL)
– __wine_process_init → __wine_kernel_init (Kernel32.DLL)
– __wine_kernel_init → start_process
– start_process → notepad.exe
Load Windows Binary - Part 2
• wine_init (libs/wine/loader.c)– Set up DLL path so that wine can load correct
DLL it want
– Load built-in NTDLL.DLL. Built-in DLL contains standard WinAPI and wine internal functions
– Get address of function __wine_process_init from built-in BTDLL.DLL
– Run __wine_process_init
Load Windows Binary - Part 2
• wine_process_init (dlls/ntdll/loader.c)– Call function thread_init to initialize TEB, PEB
and other environment for Windows application. Launch winserver if needed and set up connection to the winserver
– Load built-in Kernel32.DLL
– Get address of function __wine_kernel_init from built-in Kernel32.DLL
Load Windows Binary - Part 2
• wine_kernel_init– Initialize things like register this Windows
application to wineserver, set up current directory and environment parameters
– Load image of Windows application
Load Windows Binary - Part 2
• start_process– LdrInitializeThunk loads remaining DLL needed
by the target Windows application
– Jump to Windows application entry point and kick off
– All WinAPI called by Windows application will be directed to Wine’s version
Implement Win32/NT API
• Three examplesCreateProcessOpenFileWriteFile
• Most of them are implement through POSIX API with emulation
• Some of them call POSIX API at client side, others are at wineserver side
CreateProcess
CreateProcessW (dlls/kernel32/process.c
)
CreateProcessW (dlls/kernel32/process.c
)
create_process_impl (dlls/kernel32/process.c
)
create_process_impl (dlls/kernel32/process.c
)
create_process (dlls/kernel32/process.c
)
create_process (dlls/kernel32/process.c
)
exec_loader (dlls/kernel32/process.c
)
exec_loader (dlls/kernel32/process.c
)
fork →wine_exec_wine_binaryfork →wine_exec_wine_binary
Windows App wineserver
create_process (server/process.c)
create_process (server/process.c)
req_new_process(server/process.c)req_new_process(server/process.c)
OpenFile
OpenFile (dlls/kernel32/file.c)
OpenFile (dlls/kernel32/file.c)
NtCreateFile (dlls/ntdll/file.c)
NtCreateFile (dlls/ntdll/file.c)
FILE_CreateFile (dlls/ntdll/file.c)
FILE_CreateFile (dlls/ntdll/file.c)
Windows App wineserver
req_create_file (server/file.c)req_create_file (server/file.c)
struct fd *open_fd (server/fd.c)
struct fd *open_fd (server/fd.c)
create_file(server/file.c)
create_file(server/file.c)
fd->unix_fd = open( … );
fd->unix_fd = open( … );
reply->handle = alloc_handle ( … );
reply->handle = alloc_handle ( … );
File
• Windows app does not own the file it creates by using WinAPI like OpenFile/CreateFile– OpenFile/CreateFile send request to wineserver
– wineserver uses open to create a UNIX file descriptor, associated it with <windows process, handle> pair
–Windows app only see a fake Windows file handle returned by wineserver
WriteFile
WriteFile (dlls/kernel32/file.c)
WriteFile (dlls/kernel32/file.c)
NtWriteFile (dlls/ntdll/file.c)
NtWriteFile (dlls/ntdll/file.c)
server_get_unix_fd (dlls/ntdll/server.c) server_get_unix_fd (dlls/ntdll/server.c)
write(fd …); write(fd …);
Windows App wineserver
req_get_handle_fd (server/fd.c)
req_get_handle_fd (server/fd.c)
get_handle_fd_obj(server/fd.c)
get_handle_fd_obj(server/fd.c)
receive_fd(dlls/ntdll/server.c)
receive_fd(dlls/ntdll/server.c)
send_client_fd (server/request.c)
send_client_fd (server/request.c)
WriteFile
Windows App wineserver
User space
Kernel space
file
wineserver gives the file descriptor accessright temporarily
Cygwin Overview
cygwin1.dllcygwin1.dll
UNIX AppUNIX App
Kernel32.DLLKernel32.DLL
NTDLL.DLLNTDLL.DLL
newlibc(C
runtime)
newlibc(C
runtime)
What Cygwin Is?
• Cygwin includes two parts– Provide tools like gcc, make, … etc, let you
compile UNIX source code into Windows executable
– Provide cygwin1.dll which acts as a Linux API layer on Windows
fork
fork(cygwin/fork.cc)
fork(cygwin/fork.cc)
frok:: parent(cygwin/fork.cc)
frok:: parent(cygwin/fork.cc)
CreateProcessW(Win32 API)
CreateProcessW(Win32 API)
• Win32 API receive more parameters then POSIX API, make up those parameters
open
• UNIX provides uniform interfaces like open/close/read/write to access devices
• Windows provides various interfaces for different devices
• cygwin glue them by using Class fhandler_base
open(cygwin/syscalls.cc)
open(cygwin/syscalls.cc)
build_fh_name(cygwin/dtable.cc)
build_fh_name(cygwin/dtable.cc)
open
• cygwin glue them by providing a abstract layer: class fhandler_base
virtual int ioctl (unsigned int cmd, void *);virtual int fcntl (int cmd, void *);virtual char const *ttyname () { return get_name (); }virtual void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));virtual ssize_t __stdcall write (const void *ptr, size_t len);
open
• cygwin glue them by providing a abstract layer: class fhandler_base
virtual int ioctl (unsigned int cmd, void *);virtual int fcntl (int cmd, void *);virtual char const *ttyname () { return get_name (); }virtual void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));virtual ssize_t __stdcall write (const void *ptr, size_t len);
open
open(cygwin/syscalls.cc)
open(cygwin/syscalls.cc)
build_fh_name(cygwin/dtable.cc)
build_fh_name(cygwin/dtable.cc)
fhandler_disk_file::open(cygwin/
fhandler_disk_file.cc)
fhandler_disk_file::open(cygwin/
fhandler_disk_file.cc)
fhandler_base::open_fs(cygwin/
fhandler_disk_file.cc)
fhandler_base::open_fs(cygwin/
fhandler_disk_file.cc)
Need to deal with different path conventionbetween UNIX and Windows
fhandler_base::open(cygwin/fhandler.cc)fhandler_base::open(cygwin/fhandler.cc)
NtCreateFileNtCreateFile
Design & Implementation Strategy
• Both WINE and Cygwin are API compatibility layers, WinAPI-to-POSIX or vise versa (with a little different)
• WINE provides binary level compatibilityYou don’t have to compile Windows source code Since you usually can’t get the source code
• Cygwin provides source level compatibilityYou use GCC (Windows port) provided by
Cygwin to compile UNIX source code
Design & Implementation Strategy
• Both implement their own .so or DLL, which do API conversion, or vise versa
• Wine need to implement its own PE loader/dynamic linker, since it achieve binary level compatibility