subr_pe.c revision 331722
1/*- 2 * Copyright (c) 2003 3 * Bill Paul <wpaul@windriver.com>. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 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. 19 * 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. 31 */ 32 33#include <sys/cdefs.h> 34__FBSDID("$FreeBSD: stable/11/sys/compat/ndis/subr_pe.c 331722 2018-03-29 02:50:57Z eadler $"); 35 36/* 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 extension 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 48 * exporting them. 49 */ 50 51#include <sys/param.h> 52#include <sys/types.h> 53#include <sys/errno.h> 54#ifdef _KERNEL 55#include <sys/systm.h> 56#else 57#include <stdio.h> 58#include <stddef.h> 59#include <stdlib.h> 60#include <unistd.h> 61#include <string.h> 62#endif 63 64#include <compat/ndis/pe_var.h> 65 66static vm_offset_t pe_functbl_match(image_patch_table *, char *); 67 68/* 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 73 * run them directly. 74 */ 75 76int 77pe_get_dos_header(imgbase, hdr) 78 vm_offset_t imgbase; 79 image_dos_header *hdr; 80{ 81 uint16_t signature; 82 83 if (imgbase == 0 || hdr == NULL) 84 return (EINVAL); 85 86 signature = *(uint16_t *)imgbase; 87 if (signature != IMAGE_DOS_SIGNATURE) 88 return (ENOEXEC); 89 90 bcopy ((char *)imgbase, (char *)hdr, sizeof(image_dos_header)); 91 92 return (0); 93} 94 95/* 96 * Verify that this image has a Windows NT PE signature. 97 */ 98 99int 100pe_is_nt_image(imgbase) 101 vm_offset_t imgbase; 102{ 103 uint32_t signature; 104 image_dos_header *dos_hdr; 105 106 if (imgbase == 0) 107 return (EINVAL); 108 109 signature = *(uint16_t *)imgbase; 110 if (signature == IMAGE_DOS_SIGNATURE) { 111 dos_hdr = (image_dos_header *)imgbase; 112 signature = *(uint32_t *)(imgbase + dos_hdr->idh_lfanew); 113 if (signature == IMAGE_NT_SIGNATURE) 114 return (0); 115 } 116 117 return (ENOEXEC); 118} 119 120/* 121 * Return a copy of the optional header. This contains the 122 * executable entry point and the directory listing which we 123 * need to find the relocations and imports later. 124 */ 125 126int 127pe_get_optional_header(imgbase, hdr) 128 vm_offset_t imgbase; 129 image_optional_header *hdr; 130{ 131 image_dos_header *dos_hdr; 132 image_nt_header *nt_hdr; 133 134 if (imgbase == 0 || hdr == NULL) 135 return (EINVAL); 136 137 if (pe_is_nt_image(imgbase)) 138 return (EINVAL); 139 140 dos_hdr = (image_dos_header *)(imgbase); 141 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); 142 143 bcopy ((char *)&nt_hdr->inh_optionalhdr, (char *)hdr, 144 nt_hdr->inh_filehdr.ifh_optionalhdrlen); 145 146 return (0); 147} 148 149/* 150 * Return a copy of the file header. Contains the number of 151 * sections in this image. 152 */ 153 154int 155pe_get_file_header(imgbase, hdr) 156 vm_offset_t imgbase; 157 image_file_header *hdr; 158{ 159 image_dos_header *dos_hdr; 160 image_nt_header *nt_hdr; 161 162 if (imgbase == 0 || hdr == NULL) 163 return (EINVAL); 164 165 if (pe_is_nt_image(imgbase)) 166 return (EINVAL); 167 168 dos_hdr = (image_dos_header *)imgbase; 169 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); 170 171 /* 172 * Note: the size of the nt_header is variable since it 173 * can contain optional fields, as indicated by ifh_optionalhdrlen. 174 * However it happens we're only interested in fields in the 175 * non-variant portion of the nt_header structure, so we don't 176 * bother copying the optional parts here. 177 */ 178 179 bcopy ((char *)&nt_hdr->inh_filehdr, (char *)hdr, 180 sizeof(image_file_header)); 181 182 return (0); 183} 184 185/* 186 * Return the header of the first section in this image (usually 187 * .text). 188 */ 189 190int 191pe_get_section_header(imgbase, hdr) 192 vm_offset_t imgbase; 193 image_section_header *hdr; 194{ 195 image_dos_header *dos_hdr; 196 image_nt_header *nt_hdr; 197 image_section_header *sect_hdr; 198 199 if (imgbase == 0 || hdr == NULL) 200 return (EINVAL); 201 202 if (pe_is_nt_image(imgbase)) 203 return (EINVAL); 204 205 dos_hdr = (image_dos_header *)imgbase; 206 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); 207 sect_hdr = IMAGE_FIRST_SECTION(nt_hdr); 208 209 bcopy ((char *)sect_hdr, (char *)hdr, sizeof(image_section_header)); 210 211 return (0); 212} 213 214/* 215 * Return the number of sections in this executable, or 0 on error. 216 */ 217 218int 219pe_numsections(imgbase) 220 vm_offset_t imgbase; 221{ 222 image_file_header file_hdr; 223 224 if (pe_get_file_header(imgbase, &file_hdr)) 225 return (0); 226 227 return (file_hdr.ifh_numsections); 228} 229 230/* 231 * Return the base address that this image was linked for. 232 * This helps us calculate relocation addresses later. 233 */ 234 235vm_offset_t 236pe_imagebase(imgbase) 237 vm_offset_t imgbase; 238{ 239 image_optional_header optional_hdr; 240 241 if (pe_get_optional_header(imgbase, &optional_hdr)) 242 return (0); 243 244 return (optional_hdr.ioh_imagebase); 245} 246 247/* 248 * Return the offset of a given directory structure within the 249 * image. Directories reside within sections. 250 */ 251 252vm_offset_t 253pe_directory_offset(imgbase, diridx) 254 vm_offset_t imgbase; 255 uint32_t diridx; 256{ 257 image_optional_header opt_hdr; 258 vm_offset_t dir; 259 260 if (pe_get_optional_header(imgbase, &opt_hdr)) 261 return (0); 262 263 if (diridx >= opt_hdr.ioh_rva_size_cnt) 264 return (0); 265 266 dir = opt_hdr.ioh_datadir[diridx].idd_vaddr; 267 268 return (pe_translate_addr(imgbase, dir)); 269} 270 271vm_offset_t 272pe_translate_addr(imgbase, rva) 273 vm_offset_t imgbase; 274 vm_offset_t rva; 275{ 276 image_optional_header opt_hdr; 277 image_section_header *sect_hdr; 278 image_dos_header *dos_hdr; 279 image_nt_header *nt_hdr; 280 int i = 0, sections, fixedlen; 281 282 if (pe_get_optional_header(imgbase, &opt_hdr)) 283 return (0); 284 285 sections = pe_numsections(imgbase); 286 287 dos_hdr = (image_dos_header *)imgbase; 288 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); 289 sect_hdr = IMAGE_FIRST_SECTION(nt_hdr); 290 291 /* 292 * The test here is to see if the RVA falls somewhere 293 * inside the section, based on the section's start RVA 294 * and its length. However it seems sometimes the 295 * virtual length isn't enough to cover the entire 296 * area of the section. We fudge by taking into account 297 * the section alignment and rounding the section length 298 * up to a page boundary. 299 */ 300 while (i++ < sections) { 301 fixedlen = sect_hdr->ish_misc.ish_vsize; 302 fixedlen += ((opt_hdr.ioh_sectalign - 1) - 303 sect_hdr->ish_misc.ish_vsize) & 304 (opt_hdr.ioh_sectalign - 1); 305 if (sect_hdr->ish_vaddr <= (uint32_t)rva && 306 (sect_hdr->ish_vaddr + fixedlen) > 307 (uint32_t)rva) 308 break; 309 sect_hdr++; 310 } 311 312 if (i > sections) 313 return (0); 314 315 return ((vm_offset_t)(imgbase + rva - sect_hdr->ish_vaddr + 316 sect_hdr->ish_rawdataaddr)); 317} 318 319/* 320 * Get the section header for a particular section. Note that 321 * section names can be anything, but there are some standard 322 * ones (.text, .data, .rdata, .reloc). 323 */ 324 325int 326pe_get_section(imgbase, hdr, name) 327 vm_offset_t imgbase; 328 image_section_header *hdr; 329 const char *name; 330{ 331 image_dos_header *dos_hdr; 332 image_nt_header *nt_hdr; 333 image_section_header *sect_hdr; 334 335 int i, sections; 336 337 if (imgbase == 0 || hdr == NULL) 338 return (EINVAL); 339 340 if (pe_is_nt_image(imgbase)) 341 return (EINVAL); 342 343 sections = pe_numsections(imgbase); 344 345 dos_hdr = (image_dos_header *)imgbase; 346 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); 347 sect_hdr = IMAGE_FIRST_SECTION(nt_hdr); 348 349 for (i = 0; i < sections; i++) { 350 if (!strcmp ((char *)§_hdr->ish_name, name)) { 351 bcopy((char *)sect_hdr, (char *)hdr, 352 sizeof(image_section_header)); 353 return (0); 354 } else 355 sect_hdr++; 356 } 357 358 return (ENOEXEC); 359} 360 361/* 362 * Apply the base relocations to this image. The relocation table 363 * resides within the .reloc section. Relocations are specified in 364 * blocks which refer to a particular page. We apply the relocations 365 * one page block at a time. 366 */ 367 368int 369pe_relocate(imgbase) 370 vm_offset_t imgbase; 371{ 372 image_section_header sect; 373 image_base_reloc *relhdr; 374 uint16_t rel, *sloc; 375 vm_offset_t base; 376 vm_size_t delta; 377 uint32_t *lloc; 378 uint64_t *qloc; 379 int i, count; 380 vm_offset_t txt; 381 382 base = pe_imagebase(imgbase); 383 pe_get_section(imgbase, §, ".text"); 384 txt = pe_translate_addr(imgbase, sect.ish_vaddr); 385 delta = (uint32_t)(txt) - base - sect.ish_vaddr; 386 387 pe_get_section(imgbase, §, ".reloc"); 388 389 relhdr = (image_base_reloc *)(imgbase + sect.ish_rawdataaddr); 390 391 do { 392 count = (relhdr->ibr_blocksize - 393 (sizeof(uint32_t) * 2)) / sizeof(uint16_t); 394 for (i = 0; i < count; i++) { 395 rel = relhdr->ibr_rel[i]; 396 switch (IMR_RELTYPE(rel)) { 397 case IMAGE_REL_BASED_ABSOLUTE: 398 break; 399 case IMAGE_REL_BASED_HIGHLOW: 400 lloc = (uint32_t *)pe_translate_addr(imgbase, 401 relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 402 *lloc = pe_translate_addr(imgbase, 403 (*lloc - base)); 404 break; 405 case IMAGE_REL_BASED_HIGH: 406 sloc = (uint16_t *)pe_translate_addr(imgbase, 407 relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 408 *sloc += (delta & 0xFFFF0000) >> 16; 409 break; 410 case IMAGE_REL_BASED_LOW: 411 sloc = (uint16_t *)pe_translate_addr(imgbase, 412 relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 413 *sloc += (delta & 0xFFFF); 414 break; 415 case IMAGE_REL_BASED_DIR64: 416 qloc = (uint64_t *)pe_translate_addr(imgbase, 417 relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 418 *qloc = pe_translate_addr(imgbase, 419 (*qloc - base)); 420 break; 421 422 default: 423 printf("[%d]reloc type: %d\n",i, 424 IMR_RELTYPE(rel)); 425 break; 426 } 427 } 428 relhdr = (image_base_reloc *)((vm_offset_t)relhdr + 429 relhdr->ibr_blocksize); 430 } while (relhdr->ibr_blocksize); 431 432 return (0); 433} 434 435/* 436 * Return the import descriptor for a particular module. An image 437 * may be linked against several modules, typically HAL.dll, ntoskrnl.exe 438 * and NDIS.SYS. For each module, there is a list of imported function 439 * names and their addresses. 440 * 441 * Note: module names are case insensitive! 442 */ 443 444int 445pe_get_import_descriptor(imgbase, desc, module) 446 vm_offset_t imgbase; 447 image_import_descriptor *desc; 448 char *module; 449{ 450 vm_offset_t offset; 451 image_import_descriptor *imp_desc; 452 char *modname; 453 454 if (imgbase == 0 || module == NULL || desc == NULL) 455 return (EINVAL); 456 457 offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_IMPORT); 458 if (offset == 0) 459 return (ENOENT); 460 461 imp_desc = (void *)offset; 462 463 while (imp_desc->iid_nameaddr) { 464 modname = (char *)pe_translate_addr(imgbase, 465 imp_desc->iid_nameaddr); 466 if (!strncasecmp(module, modname, strlen(module))) { 467 bcopy((char *)imp_desc, (char *)desc, 468 sizeof(image_import_descriptor)); 469 return (0); 470 } 471 imp_desc++; 472 } 473 474 return (ENOENT); 475} 476 477int 478pe_get_messagetable(imgbase, md) 479 vm_offset_t imgbase; 480 message_resource_data **md; 481{ 482 image_resource_directory *rdir, *rtype; 483 image_resource_directory_entry *dent, *dent2; 484 image_resource_data_entry *rent; 485 vm_offset_t offset; 486 int i; 487 488 if (imgbase == 0) 489 return (EINVAL); 490 491 offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_RESOURCE); 492 if (offset == 0) 493 return (ENOENT); 494 495 rdir = (image_resource_directory *)offset; 496 497 dent = (image_resource_directory_entry *)(offset + 498 sizeof(image_resource_directory)); 499 500 for (i = 0; i < rdir->ird_id_entries; i++){ 501 if (dent->irde_name != RT_MESSAGETABLE) { 502 dent++; 503 continue; 504 } 505 dent2 = dent; 506 while (dent2->irde_dataoff & RESOURCE_DIR_FLAG) { 507 rtype = (image_resource_directory *)(offset + 508 (dent2->irde_dataoff & ~RESOURCE_DIR_FLAG)); 509 dent2 = (image_resource_directory_entry *) 510 ((uintptr_t)rtype + 511 sizeof(image_resource_directory)); 512 } 513 rent = (image_resource_data_entry *)(offset + 514 dent2->irde_dataoff); 515 *md = (message_resource_data *)pe_translate_addr(imgbase, 516 rent->irde_offset); 517 return (0); 518 } 519 520 return (ENOENT); 521} 522 523int 524pe_get_message(imgbase, id, str, len, flags) 525 vm_offset_t imgbase; 526 uint32_t id; 527 char **str; 528 int *len; 529 uint16_t *flags; 530{ 531 message_resource_data *md = NULL; 532 message_resource_block *mb; 533 message_resource_entry *me; 534 uint32_t i; 535 536 pe_get_messagetable(imgbase, &md); 537 538 if (md == NULL) 539 return (ENOENT); 540 541 mb = (message_resource_block *)((uintptr_t)md + 542 sizeof(message_resource_data)); 543 544 for (i = 0; i < md->mrd_numblocks; i++) { 545 if (id >= mb->mrb_lowid && id <= mb->mrb_highid) { 546 me = (message_resource_entry *)((uintptr_t)md + 547 mb->mrb_entryoff); 548 for (i = id - mb->mrb_lowid; i > 0; i--) 549 me = (message_resource_entry *)((uintptr_t)me + 550 me->mre_len); 551 *str = me->mre_text; 552 *len = me->mre_len; 553 *flags = me->mre_flags; 554 return (0); 555 } 556 mb++; 557 } 558 559 return (ENOENT); 560} 561 562/* 563 * Find the function that matches a particular name. This doesn't 564 * need to be particularly speedy since it's only run when loading 565 * a module for the first time. 566 */ 567 568static vm_offset_t 569pe_functbl_match(functbl, name) 570 image_patch_table *functbl; 571 char *name; 572{ 573 image_patch_table *p; 574 575 if (functbl == NULL || name == NULL) 576 return (0); 577 578 p = functbl; 579 580 while (p->ipt_name != NULL) { 581 if (!strcmp(p->ipt_name, name)) 582 return ((vm_offset_t)p->ipt_wrap); 583 p++; 584 } 585 printf("no match for %s\n", name); 586 587 /* 588 * Return the wrapper pointer for this routine. 589 * For x86, this is the same as the funcptr. 590 * For amd64, this points to a wrapper routine 591 * that does calling convention translation and 592 * then invokes the underlying routine. 593 */ 594 return ((vm_offset_t)p->ipt_wrap); 595} 596 597/* 598 * Patch the imported function addresses for a given module. 599 * The caller must specify the module name and provide a table 600 * of function pointers that will be patched into the jump table. 601 * Note that there are actually two copies of the jump table: one 602 * copy is left alone. In a .SYS file, the jump tables are usually 603 * merged into the INIT segment. 604 */ 605 606int 607pe_patch_imports(imgbase, module, functbl) 608 vm_offset_t imgbase; 609 char *module; 610 image_patch_table *functbl; 611{ 612 image_import_descriptor imp_desc; 613 char *fname; 614 vm_offset_t *nptr, *fptr; 615 vm_offset_t func; 616 617 if (imgbase == 0 || module == NULL || functbl == NULL) 618 return (EINVAL); 619 620 if (pe_get_import_descriptor(imgbase, &imp_desc, module)) 621 return (ENOEXEC); 622 623 nptr = (vm_offset_t *)pe_translate_addr(imgbase, 624 imp_desc.iid_import_name_table_addr); 625 fptr = (vm_offset_t *)pe_translate_addr(imgbase, 626 imp_desc.iid_import_address_table_addr); 627 628 while (nptr != NULL && pe_translate_addr(imgbase, *nptr)) { 629 fname = (char *)pe_translate_addr(imgbase, (*nptr) + 2); 630 func = pe_functbl_match(functbl, fname); 631 if (func) 632 *fptr = func; 633#ifdef notdef 634 if (*fptr == 0) 635 return (ENOENT); 636#endif 637 nptr++; 638 fptr++; 639 } 640 641 return (0); 642} 643