2 * Creation of Wine fake dlls for apps that access the dll file directly.
4 * Copyright 2006 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define NONAMELESSSTRUCT
24 #define NONAMELESSUNION
26 #define WIN32_NO_STATUS
33 #include "wine/unicode.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(setupapi
);
38 static const char fakedll_signature
[] = "Wine placeholder DLL";
40 static const unsigned int file_alignment
= 512;
41 static const unsigned int section_alignment
= 4096;
51 #define ALIGN(size,align) (((size) + (align) - 1) & ~((align) - 1))
53 /* contents of the dll sections */
55 static const BYTE dll_code_section
[] = { 0x31, 0xc0, /* xor %eax,%eax */
56 0xc2, 0x0c, 0x00 }; /* ret $12 */
58 static const BYTE exe_code_section
[] = { 0xb8, 0x01, 0x00, 0x00, 0x00, /* movl $1,%eax */
59 0xc2, 0x04, 0x00 }; /* ret $4 */
61 static const IMAGE_BASE_RELOCATION reloc_section
; /* empty relocs */
64 /* wrapper for WriteFile */
65 static inline BOOL
xwrite( struct dll_info
*info
, const void *data
, DWORD size
, DWORD offset
)
69 return (SetFilePointer( info
->handle
, offset
, NULL
, FILE_BEGIN
) != INVALID_SET_FILE_POINTER
&&
70 WriteFile( info
->handle
, data
, size
, &res
, NULL
) &&
74 /* add a new section to the dll NT header */
75 static void add_section( struct dll_info
*info
, const char *name
, DWORD size
, DWORD flags
)
77 IMAGE_SECTION_HEADER
*sec
= (IMAGE_SECTION_HEADER
*)(info
->nt
+ 1);
79 sec
+= info
->nt
->FileHeader
.NumberOfSections
;
80 memcpy( (char *)sec
->Name
, name
, min( strlen(name
), sizeof(sec
->Name
)) );
81 sec
->Misc
.VirtualSize
= ALIGN( size
, section_alignment
);
82 sec
->VirtualAddress
= info
->mem_pos
;
83 sec
->SizeOfRawData
= size
;
84 sec
->PointerToRawData
= info
->file_pos
;
85 sec
->Characteristics
= flags
;
86 info
->file_pos
+= ALIGN( size
, file_alignment
);
87 info
->mem_pos
+= ALIGN( size
, section_alignment
);
88 info
->nt
->FileHeader
.NumberOfSections
++;
91 /* add a data directory to the dll NT header */
92 static inline void add_directory( struct dll_info
*info
, unsigned int idx
, DWORD rva
, DWORD size
)
94 info
->nt
->OptionalHeader
.DataDirectory
[idx
].VirtualAddress
= rva
;
95 info
->nt
->OptionalHeader
.DataDirectory
[idx
].Size
= size
;
98 /* find the limits of the resource data */
99 static void get_resource_data( const IMAGE_RESOURCE_DIRECTORY
*dir
, const BYTE
*root
,
100 DWORD
*rva_start
, DWORD
*rva_end
)
102 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
105 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
106 for (i
= 0; i
< dir
->NumberOfNamedEntries
+ dir
->NumberOfIdEntries
; i
++, entry
++)
108 const void *ptr
= root
+ entry
->u2
.s3
.OffsetToDirectory
;
109 if (entry
->u2
.s3
.DataIsDirectory
) get_resource_data( ptr
, root
, rva_start
, rva_end
);
112 const IMAGE_RESOURCE_DATA_ENTRY
*data
= ptr
;
113 *rva_start
= min( *rva_start
, data
->OffsetToData
);
114 *rva_end
= max( *rva_end
, data
->OffsetToData
+ data
->Size
);
119 /* fixup RVAs of resource data */
120 static void fixup_resources( IMAGE_RESOURCE_DIRECTORY
*dir
, BYTE
*root
, int delta
)
122 IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
125 entry
= (IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
126 for (i
= 0; i
< dir
->NumberOfNamedEntries
+ dir
->NumberOfIdEntries
; i
++, entry
++)
128 void *ptr
= root
+ entry
->u2
.s3
.OffsetToDirectory
;
129 if (entry
->u2
.s3
.DataIsDirectory
) fixup_resources( ptr
, root
, delta
);
132 IMAGE_RESOURCE_DATA_ENTRY
*data
= ptr
;
133 if (data
->OffsetToData
) data
->OffsetToData
+= delta
;
138 /* add version resources to the dll by copying them from the source module */
139 static BOOL
add_version_resource( HMODULE module
, struct dll_info
*dll_info
)
142 DWORD rva_start
= ~0U, rva_end
= 0, dir_size
, total_size
;
143 const IMAGE_RESOURCE_DIRECTORY
*basedir
;
144 const BYTE
*data_start
, *root
;
147 if (!module
) return TRUE
;
148 if (LdrFindResourceDirectory_U( module
, NULL
, 0, &basedir
) != STATUS_SUCCESS
) return TRUE
;
149 root
= (const BYTE
*)basedir
;
150 get_resource_data( basedir
, root
, &rva_start
, &rva_end
);
151 data_start
= (const BYTE
*)module
+ rva_start
;
152 if (data_start
<= root
) return FALSE
;
153 dir_size
= data_start
- root
;
154 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, dir_size
))) return FALSE
;
155 memcpy( buffer
, root
, dir_size
);
156 fixup_resources( (IMAGE_RESOURCE_DIRECTORY
*)buffer
, buffer
, dll_info
->mem_pos
+ dir_size
- rva_start
);
157 if (!xwrite( dll_info
, buffer
, dir_size
, dll_info
->file_pos
)) goto done
;
158 if (!xwrite( dll_info
, data_start
, rva_end
- rva_start
, dll_info
->file_pos
+ dir_size
)) goto done
;
159 total_size
= dir_size
+ rva_end
- rva_start
;
160 add_directory( dll_info
, IMAGE_DIRECTORY_ENTRY_RESOURCE
, dll_info
->mem_pos
, total_size
);
161 add_section( dll_info
, ".rsrc", total_size
, IMAGE_SCN_CNT_INITIALIZED_DATA
| IMAGE_SCN_MEM_READ
);
164 HeapFree( GetProcessHeap(), 0, buffer
);
168 /* build a complete fake dll, optionally using module as a source */
169 static BOOL
build_fake_dll( HANDLE file
, HMODULE module
)
171 IMAGE_DOS_HEADER
*dos
;
172 IMAGE_NT_HEADERS
*nt
;
173 const IMAGE_NT_HEADERS
*src_nt
= NULL
;
174 struct dll_info info
;
177 DWORD lfanew
= (sizeof(*dos
) + sizeof(fakedll_signature
) + 15) & ~15;
178 DWORD size
, header_size
= lfanew
+ sizeof(*nt
);
181 buffer
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, header_size
+ 8 * sizeof(IMAGE_SECTION_HEADER
) );
183 dos
= (IMAGE_DOS_HEADER
*)buffer
;
184 dos
->e_magic
= IMAGE_DOS_SIGNATURE
;
185 dos
->e_cblp
= sizeof(*dos
);
187 dos
->e_cparhdr
= lfanew
/ 16;
189 dos
->e_maxalloc
= 0xffff;
192 dos
->e_lfarlc
= lfanew
;
193 dos
->e_lfanew
= lfanew
;
194 memcpy( dos
+ 1, fakedll_signature
, sizeof(fakedll_signature
) );
196 nt
= info
.nt
= (IMAGE_NT_HEADERS
*)(buffer
+ lfanew
);
197 src_nt
= RtlImageNtHeader( module
);
198 /* some fields are copied from the source dll */
199 #define SET(field,def) nt->field = src_nt ? src_nt->field : def
200 SET( FileHeader
.Machine
, IMAGE_FILE_MACHINE_I386
);
201 SET( FileHeader
.TimeDateStamp
, 0 );
202 SET( FileHeader
.Characteristics
, IMAGE_FILE_DLL
);
203 SET( OptionalHeader
.MajorLinkerVersion
, 1 );
204 SET( OptionalHeader
.MinorLinkerVersion
, 0 );
205 SET( OptionalHeader
.MajorOperatingSystemVersion
, 1 );
206 SET( OptionalHeader
.MinorOperatingSystemVersion
, 0 );
207 SET( OptionalHeader
.MajorImageVersion
, 1 );
208 SET( OptionalHeader
.MinorImageVersion
, 0 );
209 SET( OptionalHeader
.MajorSubsystemVersion
, 4 );
210 SET( OptionalHeader
.MinorSubsystemVersion
, 0 );
211 SET( OptionalHeader
.Win32VersionValue
, 0 );
212 SET( OptionalHeader
.Subsystem
, IMAGE_SUBSYSTEM_WINDOWS_GUI
);
213 SET( OptionalHeader
.DllCharacteristics
, 0 );
214 SET( OptionalHeader
.SizeOfStackReserve
, 0 );
215 SET( OptionalHeader
.SizeOfStackCommit
, 0 );
216 SET( OptionalHeader
.SizeOfHeapReserve
, 0 );
217 SET( OptionalHeader
.SizeOfHeapCommit
, 0 );
219 /* other fields have fixed values */
220 nt
->Signature
= IMAGE_NT_SIGNATURE
;
221 nt
->FileHeader
.NumberOfSections
= 0;
222 nt
->FileHeader
.SizeOfOptionalHeader
= IMAGE_SIZEOF_NT_OPTIONAL_HEADER
;
223 nt
->OptionalHeader
.Magic
= IMAGE_NT_OPTIONAL_HDR_MAGIC
;
224 nt
->OptionalHeader
.ImageBase
= 0x10000000;
225 nt
->OptionalHeader
.SectionAlignment
= section_alignment
;
226 nt
->OptionalHeader
.FileAlignment
= file_alignment
;
227 nt
->OptionalHeader
.NumberOfRvaAndSizes
= IMAGE_NUMBEROF_DIRECTORY_ENTRIES
;
229 header_size
= (BYTE
*)(nt
+ 1) - buffer
;
230 info
.mem_pos
= ALIGN( header_size
, section_alignment
);
231 info
.file_pos
= ALIGN( header_size
, file_alignment
);
233 nt
->OptionalHeader
.AddressOfEntryPoint
= info
.mem_pos
;
234 nt
->OptionalHeader
.BaseOfCode
= info
.mem_pos
;
236 if (nt
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
238 size
= sizeof(dll_code_section
);
239 if (!xwrite( &info
, dll_code_section
, size
, info
.file_pos
)) goto done
;
243 size
= sizeof(exe_code_section
);
244 if (!xwrite( &info
, exe_code_section
, size
, info
.file_pos
)) goto done
;
246 nt
->OptionalHeader
.SizeOfCode
= size
;
247 add_section( &info
, ".text", size
, IMAGE_SCN_CNT_CODE
| IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
);
249 if (!xwrite( &info
, &reloc_section
, sizeof(reloc_section
), info
.file_pos
)) goto done
;
250 add_directory( &info
, IMAGE_DIRECTORY_ENTRY_BASERELOC
, info
.mem_pos
, sizeof(reloc_section
) );
251 add_section( &info
, ".reloc", sizeof(reloc_section
),
252 IMAGE_SCN_CNT_INITIALIZED_DATA
| IMAGE_SCN_MEM_DISCARDABLE
| IMAGE_SCN_MEM_READ
);
254 if (!add_version_resource( module
, &info
)) goto done
;
256 header_size
+= nt
->FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
);
257 nt
->OptionalHeader
.SizeOfHeaders
= ALIGN( header_size
, file_alignment
);
258 nt
->OptionalHeader
.SizeOfImage
= ALIGN( info
.mem_pos
, section_alignment
);
259 ret
= xwrite( &info
, buffer
, header_size
, 0 );
261 HeapFree( GetProcessHeap(), 0, buffer
);
265 /* check if an existing file is a fake dll so that we can overwrite it */
266 static BOOL
is_fake_dll( HANDLE h
)
268 IMAGE_DOS_HEADER
*dos
;
270 BYTE buffer
[sizeof(*dos
) + sizeof(fakedll_signature
)];
272 if (!ReadFile( h
, buffer
, sizeof(buffer
), &size
, NULL
) || size
!= sizeof(buffer
))
274 dos
= (IMAGE_DOS_HEADER
*)buffer
;
275 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
) return FALSE
;
276 if (dos
->e_lfanew
< size
) return FALSE
;
277 return !memcmp( dos
+ 1, fakedll_signature
, sizeof(fakedll_signature
) );
280 /***********************************************************************
283 BOOL
create_fake_dll( const WCHAR
*name
, const WCHAR
*source
)
289 /* first check for an existing file */
290 h
= CreateFileW( name
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
291 if (h
!= INVALID_HANDLE_VALUE
)
293 if (!is_fake_dll( h
))
295 TRACE( "%s is not a fake dll, not overwriting it\n", debugstr_w(name
) );
299 /* truncate the file */
300 SetFilePointer( h
, 0, NULL
, FILE_BEGIN
);
305 h
= CreateFileW( name
, GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, 0, NULL
);
306 if (h
== INVALID_HANDLE_VALUE
)
308 WARN( "failed to create %s\n", debugstr_w(name
) );
313 module
= LoadLibraryW( source
);
315 ret
= build_fake_dll( h
, module
);
318 if (module
) FreeLibrary( module
);
319 if (!ret
) DeleteFileW( name
);