2 * SPDX-License-Identifier: BSD-4-Clause
5 * Bill Paul <wpaul@windriver.com>. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
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
53 #include <sys/param.h>
54 #include <sys/types.h>
55 #include <sys/errno.h>
57 #include <sys/systm.h>
66 #include <compat/ndis/pe_var.h>
68 static vm_offset_t pe_functbl_match(image_patch_table *, char *);
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
79 pe_get_dos_header(imgbase, hdr)
81 image_dos_header *hdr;
85 if (imgbase == 0 || hdr == NULL)
88 signature = *(uint16_t *)imgbase;
89 if (signature != IMAGE_DOS_SIGNATURE)
92 bcopy ((char *)imgbase, (char *)hdr, sizeof(image_dos_header));
98 * Verify that this image has a Windows NT PE signature.
102 pe_is_nt_image(imgbase)
106 image_dos_header *dos_hdr;
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)
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.
129 pe_get_optional_header(imgbase, hdr)
131 image_optional_header *hdr;
133 image_dos_header *dos_hdr;
134 image_nt_header *nt_hdr;
136 if (imgbase == 0 || hdr == NULL)
139 if (pe_is_nt_image(imgbase))
142 dos_hdr = (image_dos_header *)(imgbase);
143 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
145 bcopy ((char *)&nt_hdr->inh_optionalhdr, (char *)hdr,
146 nt_hdr->inh_filehdr.ifh_optionalhdrlen);
152 * Return a copy of the file header. Contains the number of
153 * sections in this image.
157 pe_get_file_header(imgbase, hdr)
159 image_file_header *hdr;
161 image_dos_header *dos_hdr;
162 image_nt_header *nt_hdr;
164 if (imgbase == 0 || hdr == NULL)
167 if (pe_is_nt_image(imgbase))
170 dos_hdr = (image_dos_header *)imgbase;
171 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
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.
181 bcopy ((char *)&nt_hdr->inh_filehdr, (char *)hdr,
182 sizeof(image_file_header));
188 * Return the header of the first section in this image (usually
193 pe_get_section_header(imgbase, hdr)
195 image_section_header *hdr;
197 image_dos_header *dos_hdr;
198 image_nt_header *nt_hdr;
199 image_section_header *sect_hdr;
201 if (imgbase == 0 || hdr == NULL)
204 if (pe_is_nt_image(imgbase))
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);
211 bcopy ((char *)sect_hdr, (char *)hdr, sizeof(image_section_header));
217 * Return the number of sections in this executable, or 0 on error.
221 pe_numsections(imgbase)
224 image_file_header file_hdr;
226 if (pe_get_file_header(imgbase, &file_hdr))
229 return (file_hdr.ifh_numsections);
233 * Return the base address that this image was linked for.
234 * This helps us calculate relocation addresses later.
238 pe_imagebase(imgbase)
241 image_optional_header optional_hdr;
243 if (pe_get_optional_header(imgbase, &optional_hdr))
246 return (optional_hdr.ioh_imagebase);
250 * Return the offset of a given directory structure within the
251 * image. Directories reside within sections.
255 pe_directory_offset(imgbase, diridx)
259 image_optional_header opt_hdr;
262 if (pe_get_optional_header(imgbase, &opt_hdr))
265 if (diridx >= opt_hdr.ioh_rva_size_cnt)
268 dir = opt_hdr.ioh_datadir[diridx].idd_vaddr;
270 return (pe_translate_addr(imgbase, dir));
274 pe_translate_addr(imgbase, rva)
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;
284 if (pe_get_optional_header(imgbase, &opt_hdr))
287 sections = pe_numsections(imgbase);
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);
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.
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) >
317 return ((vm_offset_t)(imgbase + rva - sect_hdr->ish_vaddr +
318 sect_hdr->ish_rawdataaddr));
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).
328 pe_get_section(imgbase, hdr, name)
330 image_section_header *hdr;
333 image_dos_header *dos_hdr;
334 image_nt_header *nt_hdr;
335 image_section_header *sect_hdr;
339 if (imgbase == 0 || hdr == NULL)
342 if (pe_is_nt_image(imgbase))
345 sections = pe_numsections(imgbase);
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);
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));
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.
374 image_section_header sect;
375 image_base_reloc *relhdr;
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;
389 pe_get_section(imgbase, §, ".reloc");
391 relhdr = (image_base_reloc *)(imgbase + sect.ish_rawdataaddr);
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:
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,
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;
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);
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,
425 printf("[%d]reloc type: %d\n",i,
430 relhdr = (image_base_reloc *)((vm_offset_t)relhdr +
431 relhdr->ibr_blocksize);
432 } while (relhdr->ibr_blocksize);
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.
443 * Note: module names are case insensitive!
447 pe_get_import_descriptor(imgbase, desc, module)
449 image_import_descriptor *desc;
453 image_import_descriptor *imp_desc;
456 if (imgbase == 0 || module == NULL || desc == NULL)
459 offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_IMPORT);
463 imp_desc = (void *)offset;
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));
480 pe_get_messagetable(imgbase, md)
482 message_resource_data **md;
484 image_resource_directory *rdir, *rtype;
485 image_resource_directory_entry *dent, *dent2;
486 image_resource_data_entry *rent;
493 offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_RESOURCE);
497 rdir = (image_resource_directory *)offset;
499 dent = (image_resource_directory_entry *)(offset +
500 sizeof(image_resource_directory));
502 for (i = 0; i < rdir->ird_id_entries; i++){
503 if (dent->irde_name != RT_MESSAGETABLE) {
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 *)
513 sizeof(image_resource_directory));
515 rent = (image_resource_data_entry *)(offset +
516 dent2->irde_dataoff);
517 *md = (message_resource_data *)pe_translate_addr(imgbase,
526 pe_get_message(imgbase, id, str, len, flags)
533 message_resource_data *md = NULL;
534 message_resource_block *mb;
535 message_resource_entry *me;
538 pe_get_messagetable(imgbase, &md);
543 mb = (message_resource_block *)((uintptr_t)md +
544 sizeof(message_resource_data));
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 +
550 for (i = id - mb->mrb_lowid; i > 0; i--)
551 me = (message_resource_entry *)((uintptr_t)me +
555 *flags = me->mre_flags;
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.
571 pe_functbl_match(functbl, name)
572 image_patch_table *functbl;
575 image_patch_table *p;
577 if (functbl == NULL || name == NULL)
582 while (p->ipt_name != NULL) {
583 if (!strcmp(p->ipt_name, name))
584 return ((vm_offset_t)p->ipt_wrap);
587 printf("no match for %s\n", name);
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.
596 return ((vm_offset_t)p->ipt_wrap);
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.
609 pe_patch_imports(imgbase, module, functbl)
612 image_patch_table *functbl;
614 image_import_descriptor imp_desc;
616 vm_offset_t *nptr, *fptr;
619 if (imgbase == 0 || module == NULL || functbl == NULL)
622 if (pe_get_import_descriptor(imgbase, &imp_desc, module))
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);
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);