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