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: releng/12.0/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
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
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
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
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
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
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
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
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
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
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 *)§_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
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, §, ".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, §, ".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
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
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
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
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
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 }
Cache object: 9abe302ee9ed4315a4630ebe958db722
|