1/*-
2 * SPDX-License-Identifier: BSD-4-Clause
3 *
4 * Copyright (c) 2003
5 *	Bill Paul <wpaul@windriver.com>.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by Bill Paul.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD$");
37
38/*
39 * This file contains routines for relocating and dynamically linking
40 * executable object code files in the Windows(r) PE (Portable Executable)
41 * format. In Windows, anything with a .EXE, .DLL or .SYS extension is
42 * considered an executable, and all such files have some structures in
43 * common. The PE format was apparently based largely on COFF but has
44 * mutated significantly over time. We are mainly concerned with .SYS files,
45 * so this module implements only enough routines to be able to parse the
46 * headers and sections of a .SYS object file and perform the necessary
47 * relocations and jump table patching to allow us to call into it
48 * (and to have it call back to us). Note that while this module
49 * can handle fixups for imported symbols, it knows nothing about
50 * exporting them.
51 */
52
53#include <sys/param.h>
54#include <sys/types.h>
55#include <sys/errno.h>
56#ifdef _KERNEL
57#include <sys/systm.h>
58#else
59#include <stdio.h>
60#include <stddef.h>
61#include <stdlib.h>
62#include <unistd.h>
63#include <string.h>
64#endif
65
66#include <compat/ndis/pe_var.h>
67
68static vm_offset_t pe_functbl_match(image_patch_table *, char *);
69
70/*
71 * Check for an MS-DOS executable header. All Windows binaries
72 * have a small MS-DOS executable prepended to them to print out
73 * the "This program requires Windows" message. Even .SYS files
74 * have this header, in spite of the fact that you're can't actually
75 * run them directly.
76 */
77
78int
79pe_get_dos_header(imgbase, hdr)
80	vm_offset_t		imgbase;
81	image_dos_header	*hdr;
82{
83	uint16_t		signature;
84
85	if (imgbase == 0 || hdr == NULL)
86		return (EINVAL);
87
88	signature = *(uint16_t *)imgbase;
89	if (signature != IMAGE_DOS_SIGNATURE)
90		return (ENOEXEC);
91
92	bcopy ((char *)imgbase, (char *)hdr, sizeof(image_dos_header));
93
94	return (0);
95}
96
97/*
98 * Verify that this image has a Windows NT PE signature.
99 */
100
101int
102pe_is_nt_image(imgbase)
103	vm_offset_t		imgbase;
104{
105	uint32_t		signature;
106	image_dos_header	*dos_hdr;
107
108	if (imgbase == 0)
109		return (EINVAL);
110
111	signature = *(uint16_t *)imgbase;
112	if (signature == IMAGE_DOS_SIGNATURE) {
113		dos_hdr = (image_dos_header *)imgbase;
114		signature = *(uint32_t *)(imgbase + dos_hdr->idh_lfanew);
115		if (signature == IMAGE_NT_SIGNATURE)
116			return (0);
117	}
118
119	return (ENOEXEC);
120}
121
122/*
123 * Return a copy of the optional header. This contains the
124 * executable entry point and the directory listing which we
125 * need to find the relocations and imports later.
126 */
127
128int
129pe_get_optional_header(imgbase, hdr)
130	vm_offset_t		imgbase;
131	image_optional_header	*hdr;
132{
133	image_dos_header	*dos_hdr;
134	image_nt_header		*nt_hdr;
135
136	if (imgbase == 0 || hdr == NULL)
137		return (EINVAL);
138
139	if (pe_is_nt_image(imgbase))
140		return (EINVAL);
141
142	dos_hdr = (image_dos_header *)(imgbase);
143	nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
144
145	bcopy ((char *)&nt_hdr->inh_optionalhdr, (char *)hdr,
146	    nt_hdr->inh_filehdr.ifh_optionalhdrlen);
147
148	return (0);
149}
150
151/*
152 * Return a copy of the file header. Contains the number of
153 * sections in this image.
154 */
155
156int
157pe_get_file_header(imgbase, hdr)
158	vm_offset_t		imgbase;
159	image_file_header	*hdr;
160{
161	image_dos_header	*dos_hdr;
162	image_nt_header		*nt_hdr;
163
164	if (imgbase == 0 || hdr == NULL)
165		return (EINVAL);
166
167	if (pe_is_nt_image(imgbase))
168		return (EINVAL);
169
170	dos_hdr = (image_dos_header *)imgbase;
171	nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
172
173	/*
174	 * Note: the size of the nt_header is variable since it
175	 * can contain optional fields, as indicated by ifh_optionalhdrlen.
176	 * However it happens we're only interested in fields in the
177	 * non-variant portion of the nt_header structure, so we don't
178	 * bother copying the optional parts here.
179	 */
180
181	bcopy ((char *)&nt_hdr->inh_filehdr, (char *)hdr,
182	    sizeof(image_file_header));
183
184	return (0);
185}
186
187/*
188 * Return the header of the first section in this image (usually
189 * .text).
190 */
191
192int
193pe_get_section_header(imgbase, hdr)
194	vm_offset_t		imgbase;
195	image_section_header	*hdr;
196{
197	image_dos_header	*dos_hdr;
198	image_nt_header		*nt_hdr;
199	image_section_header	*sect_hdr;
200
201	if (imgbase == 0 || hdr == NULL)
202		return (EINVAL);
203
204	if (pe_is_nt_image(imgbase))
205		return (EINVAL);
206
207	dos_hdr = (image_dos_header *)imgbase;
208	nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
209	sect_hdr = IMAGE_FIRST_SECTION(nt_hdr);
210
211	bcopy ((char *)sect_hdr, (char *)hdr, sizeof(image_section_header));
212
213	return (0);
214}
215
216/*
217 * Return the number of sections in this executable, or 0 on error.
218 */
219
220int
221pe_numsections(imgbase)
222	vm_offset_t		imgbase;
223{
224	image_file_header	file_hdr;
225
226	if (pe_get_file_header(imgbase, &file_hdr))
227		return (0);
228
229	return (file_hdr.ifh_numsections);
230}
231
232/*
233 * Return the base address that this image was linked for.
234 * This helps us calculate relocation addresses later.
235 */
236
237vm_offset_t
238pe_imagebase(imgbase)
239	vm_offset_t		imgbase;
240{
241	image_optional_header	optional_hdr;
242
243	if (pe_get_optional_header(imgbase, &optional_hdr))
244		return (0);
245
246	return (optional_hdr.ioh_imagebase);
247}
248
249/*
250 * Return the offset of a given directory structure within the
251 * image. Directories reside within sections.
252 */
253
254vm_offset_t
255pe_directory_offset(imgbase, diridx)
256	vm_offset_t		imgbase;
257	uint32_t		diridx;
258{
259	image_optional_header	opt_hdr;
260	vm_offset_t		dir;
261
262	if (pe_get_optional_header(imgbase, &opt_hdr))
263		return (0);
264
265	if (diridx >= opt_hdr.ioh_rva_size_cnt)
266		return (0);
267
268	dir = opt_hdr.ioh_datadir[diridx].idd_vaddr;
269
270	return (pe_translate_addr(imgbase, dir));
271}
272
273vm_offset_t
274pe_translate_addr(imgbase, rva)
275	vm_offset_t		imgbase;
276	vm_offset_t		rva;
277{
278	image_optional_header	opt_hdr;
279	image_section_header	*sect_hdr;
280	image_dos_header	*dos_hdr;
281	image_nt_header		*nt_hdr;
282	int			i = 0, sections, fixedlen;
283
284	if (pe_get_optional_header(imgbase, &opt_hdr))
285		return (0);
286
287	sections = pe_numsections(imgbase);
288
289	dos_hdr = (image_dos_header *)imgbase;
290	nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
291	sect_hdr = IMAGE_FIRST_SECTION(nt_hdr);
292
293	/*
294	 * The test here is to see if the RVA falls somewhere
295	 * inside the section, based on the section's start RVA
296	 * and its length. However it seems sometimes the
297	 * virtual length isn't enough to cover the entire
298	 * area of the section. We fudge by taking into account
299	 * the section alignment and rounding the section length
300	 * up to a page boundary.
301	 */
302	while (i++ < sections) {
303		fixedlen = sect_hdr->ish_misc.ish_vsize;
304		fixedlen += ((opt_hdr.ioh_sectalign - 1) -
305		    sect_hdr->ish_misc.ish_vsize) &
306		    (opt_hdr.ioh_sectalign - 1);
307		if (sect_hdr->ish_vaddr <= (uint32_t)rva &&
308		    (sect_hdr->ish_vaddr + fixedlen) >
309		    (uint32_t)rva)
310			break;
311		sect_hdr++;
312	}
313
314	if (i > sections)
315		return (0);
316
317	return ((vm_offset_t)(imgbase + rva - sect_hdr->ish_vaddr +
318	    sect_hdr->ish_rawdataaddr));
319}
320
321/*
322 * Get the section header for a particular section. Note that
323 * section names can be anything, but there are some standard
324 * ones (.text, .data, .rdata, .reloc).
325 */
326
327int
328pe_get_section(imgbase, hdr, name)
329	vm_offset_t		imgbase;
330	image_section_header	*hdr;
331	const char		*name;
332{
333	image_dos_header	*dos_hdr;
334	image_nt_header		*nt_hdr;
335	image_section_header	*sect_hdr;
336
337	int			i, sections;
338
339	if (imgbase == 0 || hdr == NULL)
340		return (EINVAL);
341
342	if (pe_is_nt_image(imgbase))
343		return (EINVAL);
344
345	sections = pe_numsections(imgbase);
346
347	dos_hdr = (image_dos_header *)imgbase;
348	nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
349	sect_hdr = IMAGE_FIRST_SECTION(nt_hdr);
350
351	for (i = 0; i < sections; i++) {
352		if (!strcmp ((char *)&sect_hdr->ish_name, name)) {
353			bcopy((char *)sect_hdr, (char *)hdr,
354			    sizeof(image_section_header));
355			return (0);
356		} else
357			sect_hdr++;
358	}
359
360	return (ENOEXEC);
361}
362
363/*
364 * Apply the base relocations to this image. The relocation table
365 * resides within the .reloc section. Relocations are specified in
366 * blocks which refer to a particular page. We apply the relocations
367 * one page block at a time.
368 */
369
370int
371pe_relocate(imgbase)
372	vm_offset_t		imgbase;
373{
374	image_section_header	sect;
375	image_base_reloc	*relhdr;
376	uint16_t		rel, *sloc;
377	vm_offset_t		base;
378	vm_size_t		delta;
379	uint32_t		*lloc;
380	uint64_t		*qloc;
381	int			i, count;
382	vm_offset_t		txt;
383
384	base = pe_imagebase(imgbase);
385	pe_get_section(imgbase, &sect, ".text");
386	txt = pe_translate_addr(imgbase, sect.ish_vaddr);
387	delta = (uint32_t)(txt) - base - sect.ish_vaddr;
388
389	pe_get_section(imgbase, &sect, ".reloc");
390
391	relhdr = (image_base_reloc *)(imgbase + sect.ish_rawdataaddr);
392
393	do {
394		count = (relhdr->ibr_blocksize -
395		    (sizeof(uint32_t) * 2)) / sizeof(uint16_t);
396		for (i = 0; i < count; i++) {
397			rel = relhdr->ibr_rel[i];
398			switch (IMR_RELTYPE(rel)) {
399			case IMAGE_REL_BASED_ABSOLUTE:
400				break;
401			case IMAGE_REL_BASED_HIGHLOW:
402				lloc = (uint32_t *)pe_translate_addr(imgbase,
403				    relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
404				*lloc = pe_translate_addr(imgbase,
405				    (*lloc - base));
406				break;
407			case IMAGE_REL_BASED_HIGH:
408				sloc = (uint16_t *)pe_translate_addr(imgbase,
409				    relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
410				*sloc += (delta & 0xFFFF0000) >> 16;
411				break;
412			case IMAGE_REL_BASED_LOW:
413				sloc = (uint16_t *)pe_translate_addr(imgbase,
414				    relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
415				*sloc += (delta & 0xFFFF);
416				break;
417			case IMAGE_REL_BASED_DIR64:
418				qloc = (uint64_t *)pe_translate_addr(imgbase,
419				    relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
420				*qloc = pe_translate_addr(imgbase,
421				    (*qloc - base));
422				break;
423
424			default:
425				printf("[%d]reloc type: %d\n",i,
426				    IMR_RELTYPE(rel));
427				break;
428			}
429		}
430		relhdr = (image_base_reloc *)((vm_offset_t)relhdr +
431		    relhdr->ibr_blocksize);
432	} while (relhdr->ibr_blocksize);
433
434	return (0);
435}
436
437/*
438 * Return the import descriptor for a particular module. An image
439 * may be linked against several modules, typically HAL.dll, ntoskrnl.exe
440 * and NDIS.SYS. For each module, there is a list of imported function
441 * names and their addresses.
442 *
443 * Note: module names are case insensitive!
444 */
445
446int
447pe_get_import_descriptor(imgbase, desc, module)
448	vm_offset_t		imgbase;
449	image_import_descriptor	*desc;
450	char			*module;
451{
452	vm_offset_t		offset;
453	image_import_descriptor	*imp_desc;
454	char			*modname;
455
456	if (imgbase == 0 || module == NULL || desc == NULL)
457		return (EINVAL);
458
459	offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_IMPORT);
460	if (offset == 0)
461		return (ENOENT);
462
463	imp_desc = (void *)offset;
464
465	while (imp_desc->iid_nameaddr) {
466		modname = (char *)pe_translate_addr(imgbase,
467		    imp_desc->iid_nameaddr);
468		if (!strncasecmp(module, modname, strlen(module))) {
469			bcopy((char *)imp_desc, (char *)desc,
470			    sizeof(image_import_descriptor));
471			return (0);
472		}
473		imp_desc++;
474	}
475
476	return (ENOENT);
477}
478
479int
480pe_get_messagetable(imgbase, md)
481	vm_offset_t		imgbase;
482	message_resource_data	**md;
483{
484	image_resource_directory	*rdir, *rtype;
485	image_resource_directory_entry	*dent, *dent2;
486	image_resource_data_entry	*rent;
487	vm_offset_t		offset;
488	int			i;
489
490	if (imgbase == 0)
491		return (EINVAL);
492
493	offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_RESOURCE);
494	if (offset == 0)
495		return (ENOENT);
496
497	rdir = (image_resource_directory *)offset;
498
499	dent = (image_resource_directory_entry *)(offset +
500	    sizeof(image_resource_directory));
501
502	for (i = 0; i < rdir->ird_id_entries; i++){
503		if (dent->irde_name != RT_MESSAGETABLE)	{
504			dent++;
505			continue;
506		}
507		dent2 = dent;
508		while (dent2->irde_dataoff & RESOURCE_DIR_FLAG) {
509			rtype = (image_resource_directory *)(offset +
510			    (dent2->irde_dataoff & ~RESOURCE_DIR_FLAG));
511			dent2 = (image_resource_directory_entry *)
512			    ((uintptr_t)rtype +
513			     sizeof(image_resource_directory));
514		}
515		rent = (image_resource_data_entry *)(offset +
516		    dent2->irde_dataoff);
517		*md = (message_resource_data *)pe_translate_addr(imgbase,
518		    rent->irde_offset);
519		return (0);
520	}
521
522	return (ENOENT);
523}
524
525int
526pe_get_message(imgbase, id, str, len, flags)
527	vm_offset_t		imgbase;
528	uint32_t		id;
529	char			**str;
530	int			*len;
531	uint16_t		*flags;
532{
533	message_resource_data	*md = NULL;
534	message_resource_block	*mb;
535	message_resource_entry	*me;
536	uint32_t		i;
537
538	pe_get_messagetable(imgbase, &md);
539
540	if (md == NULL)
541		return (ENOENT);
542
543	mb = (message_resource_block *)((uintptr_t)md +
544	    sizeof(message_resource_data));
545
546	for (i = 0; i < md->mrd_numblocks; i++) {
547		if (id >= mb->mrb_lowid && id <= mb->mrb_highid) {
548			me = (message_resource_entry *)((uintptr_t)md +
549			    mb->mrb_entryoff);
550			for (i = id - mb->mrb_lowid; i > 0; i--)
551				me = (message_resource_entry *)((uintptr_t)me +
552				    me->mre_len);
553			*str = me->mre_text;
554			*len = me->mre_len;
555			*flags = me->mre_flags;
556			return (0);
557		}
558		mb++;
559	}
560
561	return (ENOENT);
562}
563
564/*
565 * Find the function that matches a particular name. This doesn't
566 * need to be particularly speedy since it's only run when loading
567 * a module for the first time.
568 */
569
570static vm_offset_t
571pe_functbl_match(functbl, name)
572	image_patch_table	*functbl;
573	char			*name;
574{
575	image_patch_table	*p;
576
577	if (functbl == NULL || name == NULL)
578		return (0);
579
580	p = functbl;
581
582	while (p->ipt_name != NULL) {
583		if (!strcmp(p->ipt_name, name))
584			return ((vm_offset_t)p->ipt_wrap);
585		p++;
586	}
587	printf("no match for %s\n", name);
588
589	/*
590	 * Return the wrapper pointer for this routine.
591	 * For x86, this is the same as the funcptr.
592	 * For amd64, this points to a wrapper routine
593	 * that does calling convention translation and
594	 * then invokes the underlying routine.
595	 */
596	return ((vm_offset_t)p->ipt_wrap);
597}
598
599/*
600 * Patch the imported function addresses for a given module.
601 * The caller must specify the module name and provide a table
602 * of function pointers that will be patched into the jump table.
603 * Note that there are actually two copies of the jump table: one
604 * copy is left alone. In a .SYS file, the jump tables are usually
605 * merged into the INIT segment.
606 */
607
608int
609pe_patch_imports(imgbase, module, functbl)
610	vm_offset_t		imgbase;
611	char			*module;
612	image_patch_table	*functbl;
613{
614	image_import_descriptor	imp_desc;
615	char			*fname;
616	vm_offset_t		*nptr, *fptr;
617	vm_offset_t		func;
618
619	if (imgbase == 0 || module == NULL || functbl == NULL)
620		return (EINVAL);
621
622	if (pe_get_import_descriptor(imgbase, &imp_desc, module))
623		return (ENOEXEC);
624
625	nptr = (vm_offset_t *)pe_translate_addr(imgbase,
626	    imp_desc.iid_import_name_table_addr);
627	fptr = (vm_offset_t *)pe_translate_addr(imgbase,
628	    imp_desc.iid_import_address_table_addr);
629
630	while (nptr != NULL && pe_translate_addr(imgbase, *nptr)) {
631		fname = (char *)pe_translate_addr(imgbase, (*nptr) + 2);
632		func = pe_functbl_match(functbl, fname);
633		if (func)
634			*fptr = func;
635#ifdef notdef
636		if (*fptr == 0)
637			return (ENOENT);
638#endif
639		nptr++;
640		fptr++;
641	}
642
643	return (0);
644}
645