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$"); 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 68static 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 78int 79pe_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 101int 102pe_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 128int 129pe_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 156int 157pe_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 192int 193pe_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 220int 221pe_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 237vm_offset_t 238pe_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 254vm_offset_t 255pe_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 273vm_offset_t 274pe_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 327int 328pe_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 370int 371pe_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 446int 447pe_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 479int 480pe_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 525int 526pe_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 570static vm_offset_t 571pe_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 608int 609pe_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