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>
| 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>
|
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 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 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 <stdlib.h> 59#include <unistd.h> 60#include <string.h> 61#endif 62 63#include <compat/ndis/pe_var.h> 64 65static vm_offset_t pe_functbl_match(image_patch_table *, char *); 66 67/* 68 * Check for an MS-DOS executable header. All Windows binaries 69 * have a small MS-DOS executable prepended to them to print out 70 * the "This program requires Windows" message. Even .SYS files 71 * have this header, in spite of the fact that you're can't actually 72 * run them directly. 73 */ 74 75int 76pe_get_dos_header(imgbase, hdr) 77 vm_offset_t imgbase; 78 image_dos_header *hdr; 79{ 80 uint16_t signature; 81 82 if (imgbase == 0 || hdr == NULL) 83 return (EINVAL); 84 85 signature = *(uint16_t *)imgbase; 86 if (signature != IMAGE_DOS_SIGNATURE) 87 return (ENOEXEC); 88 89 bcopy ((char *)imgbase, (char *)hdr, sizeof(image_dos_header)); 90 91 return(0); 92} 93 94/* 95 * Verify that this image has a Windows NT PE signature. 96 */ 97 98int 99pe_is_nt_image(imgbase) 100 vm_offset_t imgbase; 101{ 102 uint32_t signature; 103 image_dos_header *dos_hdr; 104 105 if (imgbase == 0) 106 return (EINVAL); 107 108 signature = *(uint16_t *)imgbase; 109 if (signature == IMAGE_DOS_SIGNATURE) { 110 dos_hdr = (image_dos_header *)imgbase; 111 signature = *(uint32_t *)(imgbase + dos_hdr->idh_lfanew); 112 if (signature == IMAGE_NT_SIGNATURE) 113 return(0); 114 } 115 116 return(ENOEXEC); 117} 118 119/* 120 * Return a copy of the optional header. This contains the 121 * executable entry point and the directory listing which we 122 * need to find the relocations and imports later. 123 */ 124 125int 126pe_get_optional_header(imgbase, hdr) 127 vm_offset_t imgbase; 128 image_optional_header *hdr; 129{ 130 image_dos_header *dos_hdr; 131 image_nt_header *nt_hdr; 132 133 if (imgbase == 0 || hdr == NULL) 134 return(EINVAL); 135 136 if (pe_is_nt_image(imgbase)) 137 return (EINVAL); 138 139 dos_hdr = (image_dos_header *)(imgbase); 140 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); 141 142 bcopy ((char *)&nt_hdr->inh_optionalhdr, (char *)hdr, 143 sizeof(image_optional_header)); 144 145 return(0); 146} 147 148/* 149 * Return a copy of the file header. Contains the number of 150 * sections in this image. 151 */ 152 153int 154pe_get_file_header(imgbase, hdr) 155 vm_offset_t imgbase; 156 image_file_header *hdr; 157{ 158 image_dos_header *dos_hdr; 159 image_nt_header *nt_hdr; 160 161 if (imgbase == 0 || hdr == NULL) 162 return(EINVAL); 163 164 if (pe_is_nt_image(imgbase)) 165 return (EINVAL); 166 167 dos_hdr = (image_dos_header *)imgbase; 168 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); 169 170 bcopy ((char *)&nt_hdr->inh_filehdr, (char *)hdr, 171 sizeof(image_file_header)); 172 173 return(0); 174} 175 176/* 177 * Return the header of the first section in this image (usually 178 * .text). 179 */ 180 181int 182pe_get_section_header(imgbase, hdr) 183 vm_offset_t imgbase; 184 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(imgbase) 212 vm_offset_t imgbase; 213{ 214 image_file_header file_hdr; 215 216 if (pe_get_file_header(imgbase, &file_hdr)) 217 return(0); 218 219 return (file_hdr.ifh_numsections); 220} 221 222/* 223 * Return the base address that this image was linked for. 224 * This helps us calculate relocation addresses later. 225 */ 226 227vm_offset_t 228pe_imagebase(imgbase) 229 vm_offset_t imgbase; 230{ 231 image_optional_header optional_hdr; 232 233 if (pe_get_optional_header(imgbase, &optional_hdr)) 234 return(0); 235 236 return (optional_hdr.ioh_imagebase); 237} 238 239/* 240 * Return the offset of a given directory structure within the 241 * image. Directories reside within sections. 242 */ 243 244vm_offset_t 245pe_directory_offset(imgbase, diridx) 246 vm_offset_t imgbase; 247 uint32_t diridx; 248{ 249 image_optional_header opt_hdr; 250 vm_offset_t dir; 251 252 if (pe_get_optional_header(imgbase, &opt_hdr)) 253 return(0); 254 255 if (diridx >= opt_hdr.ioh_rva_size_cnt) 256 return(0); 257 258 dir = opt_hdr.ioh_datadir[diridx].idd_vaddr; 259 260 return(pe_translate_addr(imgbase, dir)); 261} 262 263vm_offset_t 264pe_translate_addr(imgbase, rva) 265 vm_offset_t imgbase; 266 uint32_t rva; 267{ 268 image_optional_header opt_hdr; 269 image_section_header *sect_hdr; 270 image_dos_header *dos_hdr; 271 image_nt_header *nt_hdr; 272 int i = 0, sections, fixedlen; 273 274 if (pe_get_optional_header(imgbase, &opt_hdr)) 275 return(0); 276 277 sections = pe_numsections(imgbase); 278 279 dos_hdr = (image_dos_header *)imgbase; 280 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); 281 sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr + 282 sizeof(image_nt_header)); 283 284 /* 285 * The test here is to see if the RVA falls somewhere 286 * inside the section, based on the section's start RVA 287 * and its length. However it seems sometimes the 288 * virtual length isn't enough to cover the entire 289 * area of the section. We fudge by taking into account 290 * the section alignment and rounding the section length 291 * up to a page boundary. 292 */ 293 while (i++ < sections) { 294 fixedlen = sect_hdr->ish_misc.ish_vsize; 295 fixedlen += ((opt_hdr.ioh_sectalign - 1) - 296 sect_hdr->ish_misc.ish_vsize) & 297 (opt_hdr.ioh_sectalign - 1); 298 if (sect_hdr->ish_vaddr <= (u_int32_t)rva && 299 (sect_hdr->ish_vaddr + fixedlen) > 300 (u_int32_t)rva) 301 break; 302 sect_hdr++; 303 } 304 305 if (i > sections) 306 return(0); 307 308 return((vm_offset_t)(imgbase + rva - sect_hdr->ish_vaddr + 309 sect_hdr->ish_rawdataaddr)); 310} 311 312/* 313 * Get the section header for a particular section. Note that 314 * section names can be anything, but there are some standard 315 * ones (.text, .data, .rdata, .reloc). 316 */ 317 318int 319pe_get_section(imgbase, hdr, name) 320 vm_offset_t imgbase; 321 image_section_header *hdr; 322 const char *name; 323{ 324 image_dos_header *dos_hdr; 325 image_nt_header *nt_hdr; 326 image_section_header *sect_hdr; 327 328 int i, sections; 329 330 if (imgbase == 0 || hdr == NULL) 331 return(EINVAL); 332 333 if (pe_is_nt_image(imgbase)) 334 return (EINVAL); 335 336 sections = pe_numsections(imgbase); 337 338 dos_hdr = (image_dos_header *)imgbase; 339 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); 340 sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr + 341 sizeof(image_nt_header)); 342 343 for (i = 0; i < sections; i++) { 344 if (!strcmp ((char *)§_hdr->ish_name, name)) { 345 bcopy((char *)sect_hdr, (char *)hdr, 346 sizeof(image_section_header)); 347 return(0); 348 } else 349 sect_hdr++; 350 } 351 352 return (ENOEXEC); 353} 354 355/* 356 * Apply the base relocations to this image. The relocation table 357 * resides within the .reloc section. Relocations are specified in 358 * blocks which refer to a particular page. We apply the relocations 359 * one page block at a time. 360 */ 361 362int 363pe_relocate(imgbase) 364 vm_offset_t imgbase; 365{ 366 image_section_header sect; 367 image_base_reloc *relhdr; 368 uint16_t rel, *sloc; 369 uint32_t base, delta, *lloc; 370 int i, count; 371 vm_offset_t txt; 372 373 base = pe_imagebase(imgbase); 374 pe_get_section(imgbase, §, ".text"); 375 txt = pe_translate_addr(imgbase, sect.ish_vaddr); 376 delta = (uint32_t)(txt) - base - sect.ish_vaddr; 377 378 pe_get_section(imgbase, §, ".reloc"); 379 380 relhdr = (image_base_reloc *)(imgbase + sect.ish_rawdataaddr); 381 382 do { 383 count = (relhdr->ibr_blocksize - 384 (sizeof(uint32_t) * 2)) / sizeof(uint16_t); 385 for (i = 0; i < count; i++) { 386 rel = relhdr->ibr_rel[i]; 387 switch (IMR_RELTYPE(rel)) { 388 case IMAGE_REL_BASED_ABSOLUTE: 389 break; 390 case IMAGE_REL_BASED_HIGHLOW: 391 lloc = (uint32_t *)pe_translate_addr(imgbase, 392 relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 393 *lloc = pe_translate_addr(imgbase, 394 (*lloc - base)); 395 break; 396 case IMAGE_REL_BASED_HIGH: 397 sloc = (uint16_t *)pe_translate_addr(imgbase, 398 relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 399 *sloc += (delta & 0xFFFF0000) >> 16; 400 break; 401 case IMAGE_REL_BASED_LOW: 402 sloc = (uint16_t *)pe_translate_addr(imgbase, 403 relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 404 *sloc += (delta & 0xFFFF); 405 break; 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 426int 427pe_get_import_descriptor(imgbase, desc, module) 428 vm_offset_t imgbase; 429 image_import_descriptor *desc; 430 char *module; 431{ 432 vm_offset_t offset; 433 image_import_descriptor *imp_desc; 434 char *modname; 435 436 if (imgbase == 0 || module == NULL || desc == NULL) 437 return(EINVAL); 438 439 offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_IMPORT); 440 if (offset == 0) 441 return (ENOENT); 442 443 imp_desc = (void *)offset; 444 445 while (imp_desc->iid_nameaddr) { 446 modname = (char *)pe_translate_addr(imgbase, 447 imp_desc->iid_nameaddr); 448 if (!strncmp(module, modname, strlen(module))) { 449 bcopy((char *)imp_desc, (char *)desc, 450 sizeof(image_import_descriptor)); 451 return(0); 452 } 453 imp_desc++; 454 } 455 456 return (ENOENT); 457} 458 459int 460pe_get_messagetable(imgbase, md) 461 vm_offset_t imgbase; 462 message_resource_data **md; 463{ 464 image_resource_directory *rdir, *rtype; 465 image_resource_directory_entry *dent, *dent2; 466 image_resource_data_entry *rent; 467 vm_offset_t offset; 468 int i; 469 470 if (imgbase == 0) 471 return(EINVAL); 472 473 offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_RESOURCE); 474 if (offset == 0) 475 return (ENOENT); 476 477 rdir = (image_resource_directory *)offset; 478 479 dent = (image_resource_directory_entry *)(offset + 480 sizeof(image_resource_directory)); 481 482 for (i = 0; i < rdir->ird_id_entries; i++){ 483 if (dent->irde_name != RT_MESSAGETABLE) { 484 dent++; 485 continue; 486 } 487 dent2 = dent; 488 while (dent2->irde_dataoff & RESOURCE_DIR_FLAG) { 489 rtype = (image_resource_directory *)(offset + 490 (dent2->irde_dataoff & ~RESOURCE_DIR_FLAG)); 491 dent2 = (image_resource_directory_entry *) 492 ((uintptr_t)rtype + 493 sizeof(image_resource_directory)); 494 } 495 rent = (image_resource_data_entry *)(offset + 496 dent2->irde_dataoff); 497 *md = (message_resource_data *)pe_translate_addr(imgbase, 498 rent->irde_offset); 499 return(0); 500 } 501 502 return(ENOENT); 503} 504 505int 506pe_get_message(imgbase, id, str, len, flags) 507 vm_offset_t imgbase; 508 uint32_t id; 509 char **str; 510 int *len; 511 uint16_t *flags; 512{ 513 message_resource_data *md = NULL; 514 message_resource_block *mb; 515 message_resource_entry *me; 516 uint32_t i; 517 518 pe_get_messagetable(imgbase, &md); 519 520 if (md == NULL) 521 return(ENOENT); 522 523 mb = (message_resource_block *)((uintptr_t)md + 524 sizeof(message_resource_data)); 525 526 for (i = 0; i < md->mrd_numblocks; i++) { 527 if (id >= mb->mrb_lowid && id <= mb->mrb_highid) { 528 me = (message_resource_entry *)((uintptr_t)md + 529 mb->mrb_entryoff); 530 for (i = id - mb->mrb_lowid; i > 0; i--) 531 me = (message_resource_entry *)((uintptr_t)me + 532 me->mre_len); 533 *str = me->mre_text; 534 *len = me->mre_len; 535 *flags = me->mre_flags; 536 return(0); 537 } 538 mb++; 539 } 540 541 return(ENOENT); 542} 543 544/* 545 * Find the function that matches a particular name. This doesn't 546 * need to be particularly speedy since it's only run when loading 547 * a module for the first time. 548 */ 549 550static vm_offset_t 551pe_functbl_match(functbl, name) 552 image_patch_table *functbl; 553 char *name; 554{ 555 image_patch_table *p; 556 557 if (functbl == NULL || name == NULL) 558 return(0); 559 560 p = functbl; 561 562 while (p->ipt_name != NULL) { 563 if (!strcmp(p->ipt_name, name)) 564 return((vm_offset_t)p->ipt_func); 565 p++; 566 } 567 printf ("no match for %s\n", name); 568 return((vm_offset_t)p->ipt_func); 569} 570 571/* 572 * Patch the imported function addresses for a given module. 573 * The caller must specify the module name and provide a table 574 * of function pointers that will be patched into the jump table. 575 * Note that there are actually two copies of the jump table: one 576 * copy is left alone. In a .SYS file, the jump tables are usually 577 * merged into the INIT segment.
| 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 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 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 <stdlib.h> 59#include <unistd.h> 60#include <string.h> 61#endif 62 63#include <compat/ndis/pe_var.h> 64 65static vm_offset_t pe_functbl_match(image_patch_table *, char *); 66 67/* 68 * Check for an MS-DOS executable header. All Windows binaries 69 * have a small MS-DOS executable prepended to them to print out 70 * the "This program requires Windows" message. Even .SYS files 71 * have this header, in spite of the fact that you're can't actually 72 * run them directly. 73 */ 74 75int 76pe_get_dos_header(imgbase, hdr) 77 vm_offset_t imgbase; 78 image_dos_header *hdr; 79{ 80 uint16_t signature; 81 82 if (imgbase == 0 || hdr == NULL) 83 return (EINVAL); 84 85 signature = *(uint16_t *)imgbase; 86 if (signature != IMAGE_DOS_SIGNATURE) 87 return (ENOEXEC); 88 89 bcopy ((char *)imgbase, (char *)hdr, sizeof(image_dos_header)); 90 91 return(0); 92} 93 94/* 95 * Verify that this image has a Windows NT PE signature. 96 */ 97 98int 99pe_is_nt_image(imgbase) 100 vm_offset_t imgbase; 101{ 102 uint32_t signature; 103 image_dos_header *dos_hdr; 104 105 if (imgbase == 0) 106 return (EINVAL); 107 108 signature = *(uint16_t *)imgbase; 109 if (signature == IMAGE_DOS_SIGNATURE) { 110 dos_hdr = (image_dos_header *)imgbase; 111 signature = *(uint32_t *)(imgbase + dos_hdr->idh_lfanew); 112 if (signature == IMAGE_NT_SIGNATURE) 113 return(0); 114 } 115 116 return(ENOEXEC); 117} 118 119/* 120 * Return a copy of the optional header. This contains the 121 * executable entry point and the directory listing which we 122 * need to find the relocations and imports later. 123 */ 124 125int 126pe_get_optional_header(imgbase, hdr) 127 vm_offset_t imgbase; 128 image_optional_header *hdr; 129{ 130 image_dos_header *dos_hdr; 131 image_nt_header *nt_hdr; 132 133 if (imgbase == 0 || hdr == NULL) 134 return(EINVAL); 135 136 if (pe_is_nt_image(imgbase)) 137 return (EINVAL); 138 139 dos_hdr = (image_dos_header *)(imgbase); 140 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); 141 142 bcopy ((char *)&nt_hdr->inh_optionalhdr, (char *)hdr, 143 sizeof(image_optional_header)); 144 145 return(0); 146} 147 148/* 149 * Return a copy of the file header. Contains the number of 150 * sections in this image. 151 */ 152 153int 154pe_get_file_header(imgbase, hdr) 155 vm_offset_t imgbase; 156 image_file_header *hdr; 157{ 158 image_dos_header *dos_hdr; 159 image_nt_header *nt_hdr; 160 161 if (imgbase == 0 || hdr == NULL) 162 return(EINVAL); 163 164 if (pe_is_nt_image(imgbase)) 165 return (EINVAL); 166 167 dos_hdr = (image_dos_header *)imgbase; 168 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); 169 170 bcopy ((char *)&nt_hdr->inh_filehdr, (char *)hdr, 171 sizeof(image_file_header)); 172 173 return(0); 174} 175 176/* 177 * Return the header of the first section in this image (usually 178 * .text). 179 */ 180 181int 182pe_get_section_header(imgbase, hdr) 183 vm_offset_t imgbase; 184 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(imgbase) 212 vm_offset_t imgbase; 213{ 214 image_file_header file_hdr; 215 216 if (pe_get_file_header(imgbase, &file_hdr)) 217 return(0); 218 219 return (file_hdr.ifh_numsections); 220} 221 222/* 223 * Return the base address that this image was linked for. 224 * This helps us calculate relocation addresses later. 225 */ 226 227vm_offset_t 228pe_imagebase(imgbase) 229 vm_offset_t imgbase; 230{ 231 image_optional_header optional_hdr; 232 233 if (pe_get_optional_header(imgbase, &optional_hdr)) 234 return(0); 235 236 return (optional_hdr.ioh_imagebase); 237} 238 239/* 240 * Return the offset of a given directory structure within the 241 * image. Directories reside within sections. 242 */ 243 244vm_offset_t 245pe_directory_offset(imgbase, diridx) 246 vm_offset_t imgbase; 247 uint32_t diridx; 248{ 249 image_optional_header opt_hdr; 250 vm_offset_t dir; 251 252 if (pe_get_optional_header(imgbase, &opt_hdr)) 253 return(0); 254 255 if (diridx >= opt_hdr.ioh_rva_size_cnt) 256 return(0); 257 258 dir = opt_hdr.ioh_datadir[diridx].idd_vaddr; 259 260 return(pe_translate_addr(imgbase, dir)); 261} 262 263vm_offset_t 264pe_translate_addr(imgbase, rva) 265 vm_offset_t imgbase; 266 uint32_t rva; 267{ 268 image_optional_header opt_hdr; 269 image_section_header *sect_hdr; 270 image_dos_header *dos_hdr; 271 image_nt_header *nt_hdr; 272 int i = 0, sections, fixedlen; 273 274 if (pe_get_optional_header(imgbase, &opt_hdr)) 275 return(0); 276 277 sections = pe_numsections(imgbase); 278 279 dos_hdr = (image_dos_header *)imgbase; 280 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); 281 sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr + 282 sizeof(image_nt_header)); 283 284 /* 285 * The test here is to see if the RVA falls somewhere 286 * inside the section, based on the section's start RVA 287 * and its length. However it seems sometimes the 288 * virtual length isn't enough to cover the entire 289 * area of the section. We fudge by taking into account 290 * the section alignment and rounding the section length 291 * up to a page boundary. 292 */ 293 while (i++ < sections) { 294 fixedlen = sect_hdr->ish_misc.ish_vsize; 295 fixedlen += ((opt_hdr.ioh_sectalign - 1) - 296 sect_hdr->ish_misc.ish_vsize) & 297 (opt_hdr.ioh_sectalign - 1); 298 if (sect_hdr->ish_vaddr <= (u_int32_t)rva && 299 (sect_hdr->ish_vaddr + fixedlen) > 300 (u_int32_t)rva) 301 break; 302 sect_hdr++; 303 } 304 305 if (i > sections) 306 return(0); 307 308 return((vm_offset_t)(imgbase + rva - sect_hdr->ish_vaddr + 309 sect_hdr->ish_rawdataaddr)); 310} 311 312/* 313 * Get the section header for a particular section. Note that 314 * section names can be anything, but there are some standard 315 * ones (.text, .data, .rdata, .reloc). 316 */ 317 318int 319pe_get_section(imgbase, hdr, name) 320 vm_offset_t imgbase; 321 image_section_header *hdr; 322 const char *name; 323{ 324 image_dos_header *dos_hdr; 325 image_nt_header *nt_hdr; 326 image_section_header *sect_hdr; 327 328 int i, sections; 329 330 if (imgbase == 0 || hdr == NULL) 331 return(EINVAL); 332 333 if (pe_is_nt_image(imgbase)) 334 return (EINVAL); 335 336 sections = pe_numsections(imgbase); 337 338 dos_hdr = (image_dos_header *)imgbase; 339 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); 340 sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr + 341 sizeof(image_nt_header)); 342 343 for (i = 0; i < sections; i++) { 344 if (!strcmp ((char *)§_hdr->ish_name, name)) { 345 bcopy((char *)sect_hdr, (char *)hdr, 346 sizeof(image_section_header)); 347 return(0); 348 } else 349 sect_hdr++; 350 } 351 352 return (ENOEXEC); 353} 354 355/* 356 * Apply the base relocations to this image. The relocation table 357 * resides within the .reloc section. Relocations are specified in 358 * blocks which refer to a particular page. We apply the relocations 359 * one page block at a time. 360 */ 361 362int 363pe_relocate(imgbase) 364 vm_offset_t imgbase; 365{ 366 image_section_header sect; 367 image_base_reloc *relhdr; 368 uint16_t rel, *sloc; 369 uint32_t base, delta, *lloc; 370 int i, count; 371 vm_offset_t txt; 372 373 base = pe_imagebase(imgbase); 374 pe_get_section(imgbase, §, ".text"); 375 txt = pe_translate_addr(imgbase, sect.ish_vaddr); 376 delta = (uint32_t)(txt) - base - sect.ish_vaddr; 377 378 pe_get_section(imgbase, §, ".reloc"); 379 380 relhdr = (image_base_reloc *)(imgbase + sect.ish_rawdataaddr); 381 382 do { 383 count = (relhdr->ibr_blocksize - 384 (sizeof(uint32_t) * 2)) / sizeof(uint16_t); 385 for (i = 0; i < count; i++) { 386 rel = relhdr->ibr_rel[i]; 387 switch (IMR_RELTYPE(rel)) { 388 case IMAGE_REL_BASED_ABSOLUTE: 389 break; 390 case IMAGE_REL_BASED_HIGHLOW: 391 lloc = (uint32_t *)pe_translate_addr(imgbase, 392 relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 393 *lloc = pe_translate_addr(imgbase, 394 (*lloc - base)); 395 break; 396 case IMAGE_REL_BASED_HIGH: 397 sloc = (uint16_t *)pe_translate_addr(imgbase, 398 relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 399 *sloc += (delta & 0xFFFF0000) >> 16; 400 break; 401 case IMAGE_REL_BASED_LOW: 402 sloc = (uint16_t *)pe_translate_addr(imgbase, 403 relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 404 *sloc += (delta & 0xFFFF); 405 break; 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 426int 427pe_get_import_descriptor(imgbase, desc, module) 428 vm_offset_t imgbase; 429 image_import_descriptor *desc; 430 char *module; 431{ 432 vm_offset_t offset; 433 image_import_descriptor *imp_desc; 434 char *modname; 435 436 if (imgbase == 0 || module == NULL || desc == NULL) 437 return(EINVAL); 438 439 offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_IMPORT); 440 if (offset == 0) 441 return (ENOENT); 442 443 imp_desc = (void *)offset; 444 445 while (imp_desc->iid_nameaddr) { 446 modname = (char *)pe_translate_addr(imgbase, 447 imp_desc->iid_nameaddr); 448 if (!strncmp(module, modname, strlen(module))) { 449 bcopy((char *)imp_desc, (char *)desc, 450 sizeof(image_import_descriptor)); 451 return(0); 452 } 453 imp_desc++; 454 } 455 456 return (ENOENT); 457} 458 459int 460pe_get_messagetable(imgbase, md) 461 vm_offset_t imgbase; 462 message_resource_data **md; 463{ 464 image_resource_directory *rdir, *rtype; 465 image_resource_directory_entry *dent, *dent2; 466 image_resource_data_entry *rent; 467 vm_offset_t offset; 468 int i; 469 470 if (imgbase == 0) 471 return(EINVAL); 472 473 offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_RESOURCE); 474 if (offset == 0) 475 return (ENOENT); 476 477 rdir = (image_resource_directory *)offset; 478 479 dent = (image_resource_directory_entry *)(offset + 480 sizeof(image_resource_directory)); 481 482 for (i = 0; i < rdir->ird_id_entries; i++){ 483 if (dent->irde_name != RT_MESSAGETABLE) { 484 dent++; 485 continue; 486 } 487 dent2 = dent; 488 while (dent2->irde_dataoff & RESOURCE_DIR_FLAG) { 489 rtype = (image_resource_directory *)(offset + 490 (dent2->irde_dataoff & ~RESOURCE_DIR_FLAG)); 491 dent2 = (image_resource_directory_entry *) 492 ((uintptr_t)rtype + 493 sizeof(image_resource_directory)); 494 } 495 rent = (image_resource_data_entry *)(offset + 496 dent2->irde_dataoff); 497 *md = (message_resource_data *)pe_translate_addr(imgbase, 498 rent->irde_offset); 499 return(0); 500 } 501 502 return(ENOENT); 503} 504 505int 506pe_get_message(imgbase, id, str, len, flags) 507 vm_offset_t imgbase; 508 uint32_t id; 509 char **str; 510 int *len; 511 uint16_t *flags; 512{ 513 message_resource_data *md = NULL; 514 message_resource_block *mb; 515 message_resource_entry *me; 516 uint32_t i; 517 518 pe_get_messagetable(imgbase, &md); 519 520 if (md == NULL) 521 return(ENOENT); 522 523 mb = (message_resource_block *)((uintptr_t)md + 524 sizeof(message_resource_data)); 525 526 for (i = 0; i < md->mrd_numblocks; i++) { 527 if (id >= mb->mrb_lowid && id <= mb->mrb_highid) { 528 me = (message_resource_entry *)((uintptr_t)md + 529 mb->mrb_entryoff); 530 for (i = id - mb->mrb_lowid; i > 0; i--) 531 me = (message_resource_entry *)((uintptr_t)me + 532 me->mre_len); 533 *str = me->mre_text; 534 *len = me->mre_len; 535 *flags = me->mre_flags; 536 return(0); 537 } 538 mb++; 539 } 540 541 return(ENOENT); 542} 543 544/* 545 * Find the function that matches a particular name. This doesn't 546 * need to be particularly speedy since it's only run when loading 547 * a module for the first time. 548 */ 549 550static vm_offset_t 551pe_functbl_match(functbl, name) 552 image_patch_table *functbl; 553 char *name; 554{ 555 image_patch_table *p; 556 557 if (functbl == NULL || name == NULL) 558 return(0); 559 560 p = functbl; 561 562 while (p->ipt_name != NULL) { 563 if (!strcmp(p->ipt_name, name)) 564 return((vm_offset_t)p->ipt_func); 565 p++; 566 } 567 printf ("no match for %s\n", name); 568 return((vm_offset_t)p->ipt_func); 569} 570 571/* 572 * Patch the imported function addresses for a given module. 573 * The caller must specify the module name and provide a table 574 * of function pointers that will be patched into the jump table. 575 * Note that there are actually two copies of the jump table: one 576 * copy is left alone. In a .SYS file, the jump tables are usually 577 * merged into the INIT segment.
|