From 510e746718bb11f45fff58517582e72c09f1055a Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Mon, 22 Apr 2019 11:40:41 +0200 Subject: [PATCH] setupapi: Add support for installing PE builtins as fake dlls. Signed-off-by: Alexandre Julliard --- dlls/setupapi/fakedll.c | 53 +++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/dlls/setupapi/fakedll.c b/dlls/setupapi/fakedll.c index e0d012a0343..260eb1e54ab 100644 --- a/dlls/setupapi/fakedll.c +++ b/dlls/setupapi/fakedll.c @@ -51,6 +51,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(setupapi); +static const char builtin_signature[] = "Wine builtin DLL"; static const char fakedll_signature[] = "Wine placeholder DLL"; static const unsigned int file_alignment = 512; @@ -191,14 +192,15 @@ failed: /* read in the contents of a file into the global file buffer */ /* return 1 on success, 0 on nonexistent file, -1 on other error */ -static int read_file( const char *name, void **data, SIZE_T *size ) +static int read_file( const char *name, void **data, SIZE_T *size, BOOL expect_builtin ) { struct stat st; int fd, ret = -1; size_t header_size; IMAGE_DOS_HEADER *dos; IMAGE_NT_HEADERS *nt; - const size_t min_size = sizeof(*dos) + sizeof(fakedll_signature) + + const char *signature = expect_builtin ? builtin_signature : fakedll_signature; + const size_t min_size = sizeof(*dos) + 32 + FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader.MajorLinkerVersion ); if ((fd = open( name, O_RDONLY | O_BINARY )) == -1) return 0; @@ -220,8 +222,8 @@ static int read_file( const char *name, void **data, SIZE_T *size ) if (pread( fd, file_buffer, header_size, 0 ) != header_size) goto done; dos = file_buffer; if (dos->e_magic != IMAGE_DOS_SIGNATURE) goto done; - if (dos->e_lfanew < sizeof(fakedll_signature)) goto done; - if (memcmp( dos + 1, fakedll_signature, sizeof(fakedll_signature) )) goto done; + if (dos->e_lfanew < strlen(signature) + 1) goto done; + if (memcmp( dos + 1, signature, strlen(signature) + 1 )) goto done; if (dos->e_lfanew + FIELD_OFFSET(IMAGE_NT_HEADERS,OptionalHeader.MajorLinkerVersion) > header_size) goto done; nt = (IMAGE_NT_HEADERS *)((char *)file_buffer + dos->e_lfanew); @@ -354,14 +356,15 @@ static BOOL is_fake_dll( HANDLE h ) { IMAGE_DOS_HEADER *dos; DWORD size; - BYTE buffer[sizeof(*dos) + sizeof(fakedll_signature)]; + BYTE buffer[sizeof(*dos) + 32]; if (!ReadFile( h, buffer, sizeof(buffer), &size, NULL ) || size != sizeof(buffer)) return FALSE; dos = (IMAGE_DOS_HEADER *)buffer; if (dos->e_magic != IMAGE_DOS_SIGNATURE) return FALSE; if (dos->e_lfanew < size) return FALSE; - return !memcmp( dos + 1, fakedll_signature, sizeof(fakedll_signature) ); + return (!memcmp( dos + 1, builtin_signature, sizeof(builtin_signature) ) || + !memcmp( dos + 1, fakedll_signature, sizeof(fakedll_signature) )); } /* create directories leading to a given file */ @@ -417,33 +420,39 @@ static void *load_fake_dll( const WCHAR *name, SIZE_T *size ) if (build_dir) { - strcpy( file + pos + len + 1, ".fake" ); - /* try as a dll */ ptr = file + pos; namelen = len + 1; + file[pos + len + 1] = 0; if (namelen > 4 && !memcmp( ptr + namelen - 4, ".dll", 4 )) namelen -= 4; ptr = prepend( ptr, ptr, namelen ); ptr = prepend( ptr, "/dlls", sizeof("/dlls") - 1 ); ptr = prepend( ptr, build_dir, strlen(build_dir) ); - if ((res = read_file( ptr, &data, size ))) goto done; + if ((res = read_file( ptr, &data, size, TRUE ))) goto done; + strcpy( file + pos + len + 1, ".fake" ); + if ((res = read_file( ptr, &data, size, FALSE ))) goto done; /* now as a program */ ptr = file + pos; namelen = len + 1; + file[pos + len + 1] = 0; if (namelen > 4 && !memcmp( ptr + namelen - 4, ".exe", 4 )) namelen -= 4; ptr = prepend( ptr, ptr, namelen ); ptr = prepend( ptr, "/programs", sizeof("/programs") - 1 ); ptr = prepend( ptr, build_dir, strlen(build_dir) ); - if ((res = read_file( ptr, &data, size ))) goto done; + if ((res = read_file( ptr, &data, size, TRUE ))) goto done; + strcpy( file + pos + len + 1, ".fake" ); + if ((res = read_file( ptr, &data, size, FALSE ))) goto done; } file[pos + len + 1] = 0; for (i = 0; (path = wine_dll_enum_load_path( i )); i++) { + ptr = prepend( file + pos, path, strlen(path) ); + if ((res = read_file( ptr, &data, size, TRUE ))) break; ptr = prepend( file + pos, "/fakedlls", sizeof("/fakedlls") - 1 ); ptr = prepend( ptr, path, strlen(path) ); - if ((res = read_file( ptr, &data, size ))) break; + if ((res = read_file( ptr, &data, size, FALSE ))) break; } done: @@ -842,7 +851,7 @@ static void register_fake_dll( const WCHAR *name, const void *data, size_t size } /* copy a fake dll file to the dest directory */ -static void install_fake_dll( WCHAR *dest, char *file, const char *ext ) +static int install_fake_dll( WCHAR *dest, char *file, const char *ext, BOOL expect_builtin ) { int ret; SIZE_T size; @@ -852,8 +861,8 @@ static void install_fake_dll( WCHAR *dest, char *file, const char *ext ) char *name = strrchr( file, '/' ) + 1; char *end = name + strlen(name); - if (ext) strcpy( end, ext ); - if (!(ret = read_file( file, &data, &size ))) return; + strcpy( end, ext ); + if (!(ret = read_file( file, &data, &size, expect_builtin ))) return 0; if (end > name + 2 && !strncmp( end - 2, "16", 2 )) end -= 2; /* remove "16" suffix */ dll_name_AtoW( destname, name, end - name ); @@ -875,10 +884,11 @@ static void install_fake_dll( WCHAR *dest, char *file, const char *ext ) } } *destname = 0; /* restore it for next file */ + return ret; } /* find and install all fake dlls in a given lib directory */ -static void install_lib_dir( WCHAR *dest, char *file, const char *default_ext ) +static void install_lib_dir( WCHAR *dest, char *file, const char *default_ext, BOOL expect_builtin ) { DIR *dir; struct dirent *de; @@ -898,9 +908,10 @@ static void install_lib_dir( WCHAR *dest, char *file, const char *default_ext ) strcat( name, "/" ); strcat( name, de->d_name ); if (!strchr( de->d_name, '.' )) strcat( name, default_ext ); - install_fake_dll( dest, file, ".fake" ); + if (!install_fake_dll( dest, file, "", expect_builtin )) + install_fake_dll( dest, file, ".fake", FALSE ); } - else install_fake_dll( dest, file, NULL ); + else install_fake_dll( dest, file, "", expect_builtin ); } closedir( dir ); } @@ -931,16 +942,18 @@ static BOOL create_wildcard_dlls( const WCHAR *dirname ) { strcpy( file, build_dir ); strcat( file, "/dlls" ); - install_lib_dir( dest, file, ".dll" ); + install_lib_dir( dest, file, ".dll", TRUE ); strcpy( file, build_dir ); strcat( file, "/programs" ); - install_lib_dir( dest, file, ".exe" ); + install_lib_dir( dest, file, ".exe", TRUE ); } for (i = 0; (path = wine_dll_enum_load_path( i )); i++) { + strcpy( file, path ); + install_lib_dir( dest, file, NULL, TRUE ); strcpy( file, path ); strcat( file, "/fakedlls" ); - install_lib_dir( dest, file, NULL ); + install_lib_dir( dest, file, NULL, FALSE ); } HeapFree( GetProcessHeap(), 0, file ); HeapFree( GetProcessHeap(), 0, dest );