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: stable/12/sys/compat/ndis/subr_pe.c 325966 2017-11-18 14:26:50Z pfg $");
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 
68 static 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 
78 int
pe_get_dos_header(imgbase,hdr)79 pe_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 
101 int
pe_is_nt_image(imgbase)102 pe_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 
128 int
pe_get_optional_header(imgbase,hdr)129 pe_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 
156 int
pe_get_file_header(imgbase,hdr)157 pe_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 
192 int
pe_get_section_header(imgbase,hdr)193 pe_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 
220 int
pe_numsections(imgbase)221 pe_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 
237 vm_offset_t
pe_imagebase(imgbase)238 pe_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 
254 vm_offset_t
pe_directory_offset(imgbase,diridx)255 pe_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 
273 vm_offset_t
pe_translate_addr(imgbase,rva)274 pe_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 
327 int
pe_get_section(imgbase,hdr,name)328 pe_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 
370 int
pe_relocate(imgbase)371 pe_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 
446 int
pe_get_import_descriptor(imgbase,desc,module)447 pe_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 
479 int
pe_get_messagetable(imgbase,md)480 pe_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 
525 int
pe_get_message(imgbase,id,str,len,flags)526 pe_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 
570 static vm_offset_t
pe_functbl_match(functbl,name)571 pe_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 
608 int
pe_patch_imports(imgbase,module,functbl)609 pe_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