3 * Bill Paul <wpaul@windriver.com>. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
32 * $DragonFly: src/sys/emulation/ndis/subr_pe.c,v 1.2 2005/12/10 16:06:20 swildner Exp $
33 * $FreeBSD: src/sys/compat/ndis/subr_pe.c,v 1.7 2004/01/13 22:49:45 obrien Exp $
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 extention 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
51 #include <sys/param.h>
52 #include <sys/types.h>
53 #include <sys/errno.h>
55 #include <sys/systm.h>
66 static vm_offset_t pe_functbl_match(image_patch_table *, char *);
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
77 pe_get_dos_header(vm_offset_t imgbase, image_dos_header *hdr)
81 if (imgbase == 0 || hdr == NULL)
84 signature = *(uint16_t *)imgbase;
85 if (signature != IMAGE_DOS_SIGNATURE)
88 bcopy ((char *)imgbase, (char *)hdr, sizeof(image_dos_header));
94 * Verify that this image has a Windows NT PE signature.
98 pe_is_nt_image(vm_offset_t imgbase)
101 image_dos_header *dos_hdr;
106 signature = *(uint16_t *)imgbase;
107 if (signature == IMAGE_DOS_SIGNATURE) {
108 dos_hdr = (image_dos_header *)imgbase;
109 signature = *(uint32_t *)(imgbase + dos_hdr->idh_lfanew);
110 if (signature == IMAGE_NT_SIGNATURE)
118 * Return a copy of the optional header. This contains the
119 * executable entry point and the directory listing which we
120 * need to find the relocations and imports later.
124 pe_get_optional_header(vm_offset_t imgbase, image_optional_header *hdr)
126 image_dos_header *dos_hdr;
127 image_nt_header *nt_hdr;
129 if (imgbase == 0 || hdr == NULL)
132 if (pe_is_nt_image(imgbase))
135 dos_hdr = (image_dos_header *)(imgbase);
136 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
138 bcopy ((char *)&nt_hdr->inh_optionalhdr, (char *)hdr,
139 sizeof(image_optional_header));
145 * Return a copy of the file header. Contains the number of
146 * sections in this image.
150 pe_get_file_header(vm_offset_t imgbase, image_file_header *hdr)
152 image_dos_header *dos_hdr;
153 image_nt_header *nt_hdr;
155 if (imgbase == 0 || hdr == NULL)
158 if (pe_is_nt_image(imgbase))
161 dos_hdr = (image_dos_header *)imgbase;
162 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
164 bcopy ((char *)&nt_hdr->inh_filehdr, (char *)hdr,
165 sizeof(image_file_header));
171 * Return the header of the first section in this image (usually
176 pe_get_section_header(vm_offset_t imgbase, image_section_header *hdr)
178 image_dos_header *dos_hdr;
179 image_nt_header *nt_hdr;
180 image_section_header *sect_hdr;
182 if (imgbase == 0 || hdr == NULL)
185 if (pe_is_nt_image(imgbase))
188 dos_hdr = (image_dos_header *)imgbase;
189 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
190 sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr +
191 sizeof(image_nt_header));
193 bcopy ((char *)sect_hdr, (char *)hdr, sizeof(image_section_header));
199 * Return the number of sections in this executable, or 0 on error.
203 pe_numsections(vm_offset_t imgbase)
205 image_file_header file_hdr;
207 if (pe_get_file_header(imgbase, &file_hdr))
210 return (file_hdr.ifh_numsections);
214 * Return the base address that this image was linked for.
215 * This helps us calculate relocation addresses later.
219 pe_imagebase(vm_offset_t imgbase)
221 image_optional_header optional_hdr;
223 if (pe_get_optional_header(imgbase, &optional_hdr))
226 return (optional_hdr.ioh_imagebase);
230 * Return the offset of a given directory structure within the
231 * image. Directories reside within sections.
235 pe_directory_offset(vm_offset_t imgbase, uint32_t diridx)
237 image_optional_header opt_hdr;
240 if (pe_get_optional_header(imgbase, &opt_hdr))
243 if (diridx >= opt_hdr.ioh_rva_size_cnt)
246 dir = opt_hdr.ioh_datadir[diridx].idd_vaddr;
248 return(pe_translate_addr(imgbase, dir));
252 pe_translate_addr(vm_offset_t imgbase, uint32_t rva)
254 image_optional_header opt_hdr;
255 image_section_header *sect_hdr;
256 image_dos_header *dos_hdr;
257 image_nt_header *nt_hdr;
258 int i = 0, sections, fixedlen;
260 if (pe_get_optional_header(imgbase, &opt_hdr))
263 sections = pe_numsections(imgbase);
265 dos_hdr = (image_dos_header *)imgbase;
266 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
267 sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr +
268 sizeof(image_nt_header));
271 * The test here is to see if the RVA falls somewhere
272 * inside the section, based on the section's start RVA
273 * and its length. However it seems sometimes the
274 * virtual length isn't enough to cover the entire
275 * area of the section. We fudge by taking into account
276 * the section alignment and rounding the section length
277 * up to a page boundary.
279 while (i++ < sections) {
280 fixedlen = sect_hdr->ish_misc.ish_vsize;
281 fixedlen += ((opt_hdr.ioh_sectalign - 1) -
282 sect_hdr->ish_misc.ish_vsize) &
283 (opt_hdr.ioh_sectalign - 1);
284 if (sect_hdr->ish_vaddr <= (u_int32_t)rva &&
285 (sect_hdr->ish_vaddr + fixedlen) >
294 return((vm_offset_t)(imgbase + rva - sect_hdr->ish_vaddr +
295 sect_hdr->ish_rawdataaddr));
299 * Get the section header for a particular section. Note that
300 * section names can be anything, but there are some standard
301 * ones (.text, .data, .rdata, .reloc).
305 pe_get_section(vm_offset_t imgbase, image_section_header *hdr,
308 image_dos_header *dos_hdr;
309 image_nt_header *nt_hdr;
310 image_section_header *sect_hdr;
314 if (imgbase == 0 || hdr == NULL)
317 if (pe_is_nt_image(imgbase))
320 sections = pe_numsections(imgbase);
322 dos_hdr = (image_dos_header *)imgbase;
323 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
324 sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr +
325 sizeof(image_nt_header));
327 for (i = 0; i < sections; i++) {
328 if (!strcmp ((char *)§_hdr->ish_name, name)) {
329 bcopy((char *)sect_hdr, (char *)hdr,
330 sizeof(image_section_header));
340 * Apply the base relocations to this image. The relocation table
341 * resides within the .reloc section. Relocations are specified in
342 * blocks which refer to a particular page. We apply the relocations
343 * one page block at a time.
347 pe_relocate(vm_offset_t imgbase)
349 image_section_header sect;
350 image_base_reloc *relhdr;
352 uint32_t base, delta, *lloc;
356 base = pe_imagebase(imgbase);
357 pe_get_section(imgbase, §, ".text");
358 txt = pe_translate_addr(imgbase, sect.ish_vaddr);
359 delta = (uint32_t)(txt) - base - sect.ish_vaddr;
361 pe_get_section(imgbase, §, ".reloc");
363 relhdr = (image_base_reloc *)(imgbase + sect.ish_rawdataaddr);
366 count = (relhdr->ibr_blocksize -
367 (sizeof(uint32_t) * 2)) / sizeof(uint16_t);
368 for (i = 0; i < count; i++) {
369 rel = relhdr->ibr_rel[i];
370 switch (IMR_RELTYPE(rel)) {
371 case IMAGE_REL_BASED_ABSOLUTE:
373 case IMAGE_REL_BASED_HIGHLOW:
374 lloc = (uint32_t *)pe_translate_addr(imgbase,
375 relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
376 *lloc = pe_translate_addr(imgbase,
379 case IMAGE_REL_BASED_HIGH:
380 sloc = (uint16_t *)pe_translate_addr(imgbase,
381 relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
382 *sloc += (delta & 0xFFFF0000) >> 16;
384 case IMAGE_REL_BASED_LOW:
385 sloc = (uint16_t *)pe_translate_addr(imgbase,
386 relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
387 *sloc += (delta & 0xFFFF);
390 printf ("[%d]reloc type: %d\n",i,
395 relhdr = (image_base_reloc *)((vm_offset_t)relhdr +
396 relhdr->ibr_blocksize);
397 } while (relhdr->ibr_blocksize);
403 * Return the import descriptor for a particular module. An image
404 * may be linked against several modules, typically HAL.dll, ntoskrnl.exe
405 * and NDIS.SYS. For each module, there is a list of imported function
406 * names and their addresses.
410 pe_get_import_descriptor(vm_offset_t imgbase, image_import_descriptor *desc,
414 image_import_descriptor *imp_desc;
417 if (imgbase == 0 || module == NULL || desc == NULL)
420 offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_IMPORT);
424 imp_desc = (void *)offset;
426 while (imp_desc->iid_nameaddr) {
427 modname = (char *)pe_translate_addr(imgbase,
428 imp_desc->iid_nameaddr);
429 if (!strncmp(module, modname, strlen(module))) {
430 bcopy((char *)imp_desc, (char *)desc,
431 sizeof(image_import_descriptor));
441 pe_get_messagetable(vm_offset_t imgbase, message_resource_data **md)
443 image_resource_directory *rdir, *rtype;
444 image_resource_directory_entry *dent, *dent2;
445 image_resource_data_entry *rent;
452 offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_RESOURCE);
456 rdir = (image_resource_directory *)offset;
458 dent = (image_resource_directory_entry *)(offset +
459 sizeof(image_resource_directory));
461 for (i = 0; i < rdir->ird_id_entries; i++){
462 if (dent->irde_name != RT_MESSAGETABLE) {
467 while (dent2->irde_dataoff & RESOURCE_DIR_FLAG) {
468 rtype = (image_resource_directory *)(offset +
469 (dent2->irde_dataoff & ~RESOURCE_DIR_FLAG));
470 dent2 = (image_resource_directory_entry *)
472 sizeof(image_resource_directory));
474 rent = (image_resource_data_entry *)(offset +
475 dent2->irde_dataoff);
476 *md = (message_resource_data *)pe_translate_addr(imgbase,
485 pe_get_message(vm_offset_t imgbase, uint32_t id, char **str, int *len,
488 message_resource_data *md = NULL;
489 message_resource_block *mb;
490 message_resource_entry *me;
493 pe_get_messagetable(imgbase, &md);
498 mb = (message_resource_block *)((uintptr_t)md +
499 sizeof(message_resource_data));
501 for (i = 0; i < md->mrd_numblocks; i++) {
502 if (id >= mb->mrb_lowid && id <= mb->mrb_highid) {
503 me = (message_resource_entry *)((uintptr_t)md +
505 for (i = id - mb->mrb_lowid; i > 0; i--)
506 me = (message_resource_entry *)((uintptr_t)me +
510 *flags = me->mre_flags;
520 * Find the function that matches a particular name. This doesn't
521 * need to be particularly speedy since it's only run when loading
522 * a module for the first time.
526 pe_functbl_match(image_patch_table *functbl, char *name)
528 image_patch_table *p;
530 if (functbl == NULL || name == NULL)
535 while (p->ipt_name != NULL) {
536 if (!strcmp(p->ipt_name, name))
537 return((vm_offset_t)p->ipt_func);
540 printf ("no match for %s\n", name);
541 return((vm_offset_t)p->ipt_func);
545 * Patch the imported function addresses for a given module.
546 * The caller must specify the module name and provide a table
547 * of function pointers that will be patched into the jump table.
548 * Note that there are actually two copies of the jump table: one
549 * copy is left alone. In a .SYS file, the jump tables are usually
550 * merged into the INIT segment.
554 pe_patch_imports(vm_offset_t imgbase, char *module,
555 image_patch_table *functbl)
557 image_import_descriptor imp_desc;
559 vm_offset_t *nptr, *fptr;
562 if (imgbase == 0 || module == NULL || functbl == NULL)
565 if (pe_get_import_descriptor(imgbase, &imp_desc, module))
568 nptr = (vm_offset_t *)pe_translate_addr(imgbase,
569 imp_desc.iid_import_name_table_addr);
570 fptr = (vm_offset_t *)pe_translate_addr(imgbase,
571 imp_desc.iid_import_address_table_addr);
573 while (nptr != NULL && pe_translate_addr(imgbase, *nptr)) {
574 fname = (char *)pe_translate_addr(imgbase, (*nptr) + 2);
575 func = pe_functbl_match(functbl, fname);