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