subr_pe.c revision 124165
1145132Sanholt/* 2145132Sanholt * Copyright (c) 2003 3145132Sanholt * Bill Paul <wpaul@windriver.com>. All rights reserved. 4145132Sanholt * 5145132Sanholt * Redistribution and use in source and binary forms, with or without 6145132Sanholt * modification, are permitted provided that the following conditions 7145132Sanholt * are met: 8145132Sanholt * 1. Redistributions of source code must retain the above copyright 9145132Sanholt * notice, this list of conditions and the following disclaimer. 10145132Sanholt * 2. Redistributions in binary form must reproduce the above copyright 11145132Sanholt * notice, this list of conditions and the following disclaimer in the 12145132Sanholt * documentation and/or other materials provided with the distribution. 13145132Sanholt * 3. All advertising materials mentioning features or use of this software 14145132Sanholt * must display the following acknowledgement: 15145132Sanholt * This product includes software developed by Bill Paul. 16145132Sanholt * 4. Neither the name of the author nor the names of any co-contributors 17145132Sanholt * may be used to endorse or promote products derived from this software 18145132Sanholt * without specific prior written permission. 19145132Sanholt * 20145132Sanholt * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21145132Sanholt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22145132Sanholt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23145132Sanholt * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24145132Sanholt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25145132Sanholt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26145132Sanholt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27145132Sanholt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28145132Sanholt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29145132Sanholt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30145132Sanholt * THE POSSIBILITY OF SUCH DAMAGE. 31152909Sanholt */ 32152909Sanholt 33152909Sanholt#include <sys/cdefs.h> 34182080Srnoland__FBSDID("$FreeBSD: head/sys/compat/ndis/subr_pe.c 124165 2004-01-06 07:09:26Z wpaul $"); 35182080Srnoland 36182080Srnoland/* 37182080Srnoland * This file contains routines for relocating and dynamically linking 38152909Sanholt * executable object code files in the Windows(r) PE (Portable Executable) 39152909Sanholt * format. In Windows, anything with a .EXE, .DLL or .SYS extention is 40145132Sanholt * considered an executable, and all such files have some structures in 41145132Sanholt * common. The PE format was apparently based largely on COFF but has 42152909Sanholt * mutated significantly over time. We are mainly concerned with .SYS files, 43152909Sanholt * so this module implements only enough routines to be able to parse the 44152909Sanholt * headers and sections of a .SYS object file and perform the necessary 45152909Sanholt * relocations and jump table patching to allow us to call into it 46182080Srnoland * (and to have it call back to us). Note that while this module 47145132Sanholt * can handle fixups for imported symbols, it knows nothing about 48152909Sanholt * exporting them. 49152909Sanholt */ 50152909Sanholt 51152909Sanholt#include <sys/param.h> 52145132Sanholt#include <sys/types.h> 53152909Sanholt#include <sys/errno.h> 54152909Sanholt#ifdef _KERNEL 55152909Sanholt#include <sys/systm.h> 56145132Sanholt#else 57145132Sanholt#include <stdio.h> 58145132Sanholt#include <stdlib.h> 59152909Sanholt#include <unistd.h> 60152909Sanholt#include <string.h> 61152909Sanholt#endif 62152909Sanholt 63145132Sanholt#include <compat/ndis/pe_var.h> 64152909Sanholt#ifdef _KERNEL 65152909Sanholt#include <machine/bus.h> 66152909Sanholt#include <machine/resource.h> 67152909Sanholt#include <sys/bus.h> 68145132Sanholt#include <sys/rman.h> 69152909Sanholt#include <compat/ndis/resource_var.h> 70145132Sanholt#include <compat/ndis/ntoskrnl_var.h> 71145132Sanholt#include <compat/ndis/ndis_var.h> 72182080Srnoland#endif 73182080Srnoland 74145132Sanholtstatic u_int32_t pe_functbl_match(image_patch_table *, char *); 75152909Sanholt 76152909Sanholt/* 77145132Sanholt * Check for an MS-DOS executable header. All Windows binaries 78152909Sanholt * have a small MS-DOS executable prepended to them to print out 79145132Sanholt * the "This program requires Windows" message. Even .SYS files 80145132Sanholt * have this header, in spite of the fact that you're can't actually 81182080Srnoland * run them directly. 82182080Srnoland */ 83145132Sanholt 84152909Sanholtint 85152909Sanholtpe_get_dos_header(imgbase, hdr) 86145132Sanholt vm_offset_t imgbase; 87152909Sanholt image_dos_header *hdr; 88145132Sanholt{ 89145132Sanholt uint16_t signature; 90182080Srnoland 91182080Srnoland if (imgbase == 0 || hdr == NULL) 92183573Srnoland return (EINVAL); 93145132Sanholt 94145132Sanholt signature = *(uint16_t *)imgbase; 95152909Sanholt if (signature != IMAGE_DOS_SIGNATURE) 96152909Sanholt return (ENOEXEC); 97152909Sanholt 98145132Sanholt bcopy ((char *)imgbase, (char *)hdr, sizeof(image_dos_header)); 99145132Sanholt 100145132Sanholt return(0); 101145132Sanholt} 102145132Sanholt 103152909Sanholt/* 104152909Sanholt * Verify that this image has a Windows NT PE signature. 105145132Sanholt */ 106152909Sanholt 107152909Sanholtint 108152909Sanholtpe_is_nt_image(imgbase) 109152909Sanholt vm_offset_t imgbase; 110145132Sanholt{ 111152909Sanholt uint32_t signature; 112152909Sanholt image_dos_header *dos_hdr; 113152909Sanholt 114152909Sanholt if (imgbase == 0) 115145132Sanholt return (EINVAL); 116152909Sanholt 117145132Sanholt signature = *(uint16_t *)imgbase; 118152909Sanholt if (signature == IMAGE_DOS_SIGNATURE) { 119152909Sanholt dos_hdr = (image_dos_header *)imgbase; 120145132Sanholt signature = *(uint32_t *)(imgbase + dos_hdr->idh_lfanew); 121145132Sanholt if (signature == IMAGE_NT_SIGNATURE) 122145132Sanholt return(0); 123145132Sanholt } 124152909Sanholt 125152909Sanholt return(ENOEXEC); 126145132Sanholt} 127152909Sanholt 128152909Sanholt/* 129152909Sanholt * Return a copy of the optional header. This contains the 130152909Sanholt * executable entry point and the directory listing which we 131152909Sanholt * need to find the relocations and imports later. 132145132Sanholt */ 133145132Sanholt 134145132Sanholtint 135145132Sanholtpe_get_optional_header(imgbase, hdr) 136152909Sanholt vm_offset_t imgbase; 137145132Sanholt image_optional_header *hdr; 138145132Sanholt{ 139145132Sanholt image_dos_header *dos_hdr; 140145132Sanholt image_nt_header *nt_hdr; 141145132Sanholt 142183573Srnoland if (imgbase == 0 || hdr == NULL) 143182080Srnoland return(EINVAL); 144182080Srnoland 145182080Srnoland if (pe_is_nt_image(imgbase)) 146145132Sanholt return (EINVAL); 147152909Sanholt 148152909Sanholt dos_hdr = (image_dos_header *)(imgbase); 149152909Sanholt nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); 150152909Sanholt 151145132Sanholt bcopy ((char *)&nt_hdr->inh_optionalhdr, (char *)hdr, 152183573Srnoland sizeof(image_optional_header)); 153145132Sanholt 154145478Sanholt return(0); 155145132Sanholt} 156145132Sanholt 157145132Sanholt/* 158145132Sanholt * Return a copy of the file header. Contains the number of 159145132Sanholt * sections in this image. 160145132Sanholt */ 161145132Sanholt 162145132Sanholtint 163145132Sanholtpe_get_file_header(imgbase, hdr) 164183573Srnoland vm_offset_t imgbase; 165183573Srnoland image_file_header *hdr; 166183573Srnoland{ 167145132Sanholt image_dos_header *dos_hdr; 168182080Srnoland image_nt_header *nt_hdr; 169182080Srnoland 170145132Sanholt if (imgbase == 0 || hdr == NULL) 171145132Sanholt return(EINVAL); 172183573Srnoland 173145132Sanholt if (pe_is_nt_image(imgbase)) 174145132Sanholt return (EINVAL); 175145132Sanholt 176145132Sanholt dos_hdr = (image_dos_header *)imgbase; 177145132Sanholt nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); 178145132Sanholt 179182080Srnoland bcopy ((char *)&nt_hdr->inh_filehdr, (char *)hdr, 180145132Sanholt sizeof(image_file_header)); 181145132Sanholt 182145132Sanholt return(0); 183145132Sanholt} 184145132Sanholt 185145132Sanholt/* 186152909Sanholt * Return the header of the first section in this image (usually 187182080Srnoland * .text). 188182080Srnoland */ 189182080Srnoland 190182080Srnolandint 191182080Srnolandpe_get_section_header(imgbase, hdr) 192182080Srnoland vm_offset_t imgbase; 193182080Srnoland image_section_header *hdr; 194182080Srnoland{ 195182080Srnoland image_dos_header *dos_hdr; 196182080Srnoland image_nt_header *nt_hdr; 197182080Srnoland image_section_header *sect_hdr; 198145132Sanholt 199152909Sanholt if (imgbase == 0 || hdr == NULL) 200152909Sanholt return(EINVAL); 201152909Sanholt 202152909Sanholt if (pe_is_nt_image(imgbase)) 203152909Sanholt return (EINVAL); 204152909Sanholt 205152909Sanholt dos_hdr = (image_dos_header *)imgbase; 206152909Sanholt nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); 207152909Sanholt sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr + 208152909Sanholt sizeof(image_nt_header)); 209182080Srnoland 210182080Srnoland bcopy ((char *)sect_hdr, (char *)hdr, sizeof(image_section_header)); 211152909Sanholt 212145132Sanholt return(0); 213145132Sanholt} 214145132Sanholt 215145132Sanholt/* 216182080Srnoland * Return the number of sections in this executable, or 0 on error. 217182080Srnoland */ 218145132Sanholt 219145132Sanholtint 220145132Sanholtpe_numsections(imgbase) 221145132Sanholt vm_offset_t imgbase; 222152909Sanholt{ 223152909Sanholt image_file_header file_hdr; 224152909Sanholt 225152909Sanholt if (pe_get_file_header(imgbase, &file_hdr)) 226152909Sanholt return(0); 227152909Sanholt 228152909Sanholt return (file_hdr.ifh_numsections); 229152909Sanholt} 230152909Sanholt 231152909Sanholt/* 232152909Sanholt * Return the base address that this image was linked for. 233145132Sanholt * This helps us calculate relocation addresses later. 234182080Srnoland */ 235182080Srnoland 236145132Sanholtvm_offset_t 237152909Sanholtpe_imagebase(imgbase) 238152909Sanholt vm_offset_t imgbase; 239145132Sanholt{ 240145132Sanholt image_optional_header optional_hdr; 241152909Sanholt 242145132Sanholt if (pe_get_optional_header(imgbase, &optional_hdr)) 243182080Srnoland return(0); 244182080Srnoland 245145132Sanholt return (optional_hdr.ioh_imagebase); 246145132Sanholt} 247145132Sanholt 248145132Sanholt/* 249145132Sanholt * Return the offset of a given directory structure within the 250145132Sanholt * image. Directories reside within sections. 251145132Sanholt */ 252152909Sanholt 253152909Sanholtvm_offset_t 254152909Sanholtpe_directory_offset(imgbase, diridx) 255152909Sanholt vm_offset_t imgbase; 256152909Sanholt uint32_t diridx; 257152909Sanholt{ 258152909Sanholt image_optional_header opt_hdr; 259152909Sanholt vm_offset_t dir; 260152909Sanholt 261182080Srnoland if (pe_get_optional_header(imgbase, &opt_hdr)) 262182080Srnoland return(0); 263152909Sanholt 264183573Srnoland if (diridx >= opt_hdr.ioh_rva_size_cnt) 265152909Sanholt return(0); 266152909Sanholt 267152909Sanholt dir = opt_hdr.ioh_datadir[diridx].idd_vaddr; 268152909Sanholt 269182080Srnoland return(pe_translate_addr(imgbase, dir)); 270152909Sanholt} 271182080Srnoland 272182080Srnolandvm_offset_t 273152909Sanholtpe_translate_addr(imgbase, rva) 274152909Sanholt vm_offset_t imgbase; 275182080Srnoland uint32_t rva; 276182080Srnoland{ 277152909Sanholt image_optional_header opt_hdr; 278152909Sanholt image_section_header *sect_hdr; 279152909Sanholt image_dos_header *dos_hdr; 280152909Sanholt image_nt_header *nt_hdr; 281182080Srnoland int i = 0, sections, fixedlen; 282182080Srnoland 283182080Srnoland if (pe_get_optional_header(imgbase, &opt_hdr)) 284182080Srnoland return(0); 285182080Srnoland 286182080Srnoland sections = pe_numsections(imgbase); 287145132Sanholt 288182080Srnoland dos_hdr = (image_dos_header *)imgbase; 289182080Srnoland nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); 290145132Sanholt sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr + 291145132Sanholt sizeof(image_nt_header)); 292145132Sanholt 293145132Sanholt /* 294145132Sanholt * The test here is to see if the RVA falls somewhere 295182080Srnoland * inside the section, based on the section's start RVA 296145132Sanholt * and its length. However it seems sometimes the 297145132Sanholt * virtual length isn't enough to cover the entire 298145132Sanholt * area of the section. We fudge by taking into account 299145132Sanholt * the section alignment and rounding the section length 300145132Sanholt * up to a page boundary. 301145132Sanholt */ 302145132Sanholt while (i++ < sections) { 303145132Sanholt fixedlen = sect_hdr->ish_misc.ish_vsize; 304145132Sanholt fixedlen += ((opt_hdr.ioh_sectalign - 1) - 305145132Sanholt sect_hdr->ish_misc.ish_vsize) & 306145132Sanholt (opt_hdr.ioh_sectalign - 1); 307145132Sanholt if (sect_hdr->ish_vaddr <= (u_int32_t)rva && 308145132Sanholt (sect_hdr->ish_vaddr + fixedlen) > 309145132Sanholt (u_int32_t)rva) 310152909Sanholt break; 311145132Sanholt sect_hdr++; 312145132Sanholt } 313145132Sanholt 314145132Sanholt if (i > sections) 315145132Sanholt return(0); 316145132Sanholt 317145132Sanholt return((vm_offset_t)(imgbase + rva - sect_hdr->ish_vaddr + 318145132Sanholt sect_hdr->ish_rawdataaddr)); 319145132Sanholt} 320145132Sanholt 321145132Sanholt/* 322152909Sanholt * Get the section header for a particular section. Note that 323145132Sanholt * section names can be anything, but there are some standard 324182080Srnoland * ones (.text, .data, .rdata, .reloc). 325182080Srnoland */ 326182080Srnoland 327145132Sanholtint 328145132Sanholtpe_get_section(imgbase, hdr, name) 329145132Sanholt vm_offset_t imgbase; 330145132Sanholt image_section_header *hdr; 331145132Sanholt const char *name; 332145132Sanholt{ 333145132Sanholt image_dos_header *dos_hdr; 334145132Sanholt image_nt_header *nt_hdr; 335145132Sanholt image_section_header *sect_hdr; 336145132Sanholt 337145132Sanholt int i, sections; 338145132Sanholt 339145132Sanholt if (imgbase == 0 || hdr == NULL) 340145132Sanholt return(EINVAL); 341182080Srnoland 342182080Srnoland if (pe_is_nt_image(imgbase)) 343145132Sanholt return (EINVAL); 344145132Sanholt 345183573Srnoland sections = pe_numsections(imgbase); 346145132Sanholt 347145132Sanholt dos_hdr = (image_dos_header *)imgbase; 348145132Sanholt nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew); 349182080Srnoland sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr + 350145132Sanholt sizeof(image_nt_header)); 351145132Sanholt 352145132Sanholt for (i = 0; i < sections; i++) { 353145132Sanholt if (!strcmp ((char *)§_hdr->ish_name, name)) { 354145132Sanholt bcopy((char *)sect_hdr, (char *)hdr, 355145132Sanholt sizeof(image_section_header)); 356145132Sanholt return(0); 357182080Srnoland } else 358145132Sanholt sect_hdr++; 359145132Sanholt } 360152909Sanholt 361145132Sanholt return (ENOEXEC); 362145132Sanholt} 363145132Sanholt 364145132Sanholt/* 365145132Sanholt * Apply the base relocations to this image. The relocation table 366145132Sanholt * resides within the .reloc section. Relocations are specified in 367145132Sanholt * blocks which refer to a particular page. We apply the relocations 368182080Srnoland * one page block at a time. 369182080Srnoland */ 370145132Sanholt 371145132Sanholtint 372145132Sanholtpe_relocate(imgbase) 373145132Sanholt vm_offset_t imgbase; 374145132Sanholt{ 375152909Sanholt image_section_header sect; 376145132Sanholt image_base_reloc *relhdr; 377145132Sanholt uint16_t rel, *sloc; 378145132Sanholt uint32_t base, delta, *lloc; 379145132Sanholt int i, count; 380145132Sanholt vm_offset_t txt; 381145132Sanholt 382145132Sanholt base = pe_imagebase(imgbase); 383145132Sanholt pe_get_section(imgbase, §, ".text"); 384145132Sanholt txt = pe_translate_addr(imgbase, sect.ish_vaddr); 385145132Sanholt delta = (uint32_t)(txt) - base - sect.ish_vaddr; 386145132Sanholt 387145132Sanholt pe_get_section(imgbase, §, ".reloc"); 388145132Sanholt 389145132Sanholt relhdr = (image_base_reloc *)(imgbase + sect.ish_rawdataaddr); 390145132Sanholt 391145132Sanholt do { 392183573Srnoland count = (relhdr->ibr_blocksize - 393145132Sanholt (sizeof(uint32_t) * 2)) / sizeof(uint16_t); 394145132Sanholt for (i = 0; i < count; i++) { 395145132Sanholt rel = relhdr->ibr_rel[i]; 396152909Sanholt switch (IMR_RELTYPE(rel)) { 397152909Sanholt case IMAGE_REL_BASED_ABSOLUTE: 398145132Sanholt break; 399145132Sanholt case IMAGE_REL_BASED_HIGHLOW: 400145132Sanholt lloc = (uint32_t *)pe_translate_addr(imgbase, 401145132Sanholt relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 402145132Sanholt *lloc = pe_translate_addr(imgbase, 403145132Sanholt (*lloc - base)); 404145132Sanholt break; 405145132Sanholt case IMAGE_REL_BASED_HIGH: 406145132Sanholt sloc = (uint16_t *)pe_translate_addr(imgbase, 407145132Sanholt relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 408145132Sanholt *sloc += (delta & 0xFFFF0000) >> 16; 409145132Sanholt break; 410145132Sanholt case IMAGE_REL_BASED_LOW: 411145132Sanholt sloc = (uint16_t *)pe_translate_addr(imgbase, 412145132Sanholt relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 413145132Sanholt *sloc += (delta & 0xFFFF); 414145132Sanholt break; 415145132Sanholt default: 416183573Srnoland printf ("[%d]reloc type: %d\n",i, 417145132Sanholt IMR_RELTYPE(rel)); 418145132Sanholt break; 419145132Sanholt } 420145132Sanholt } 421145132Sanholt relhdr = (image_base_reloc *)((vm_offset_t)relhdr + 422145132Sanholt relhdr->ibr_blocksize); 423183573Srnoland } while (relhdr->ibr_blocksize); 424183573Srnoland 425183573Srnoland return(0); 426183573Srnoland} 427183573Srnoland 428183573Srnoland/* 429183573Srnoland * Return the import descriptor for a particular module. An image 430145132Sanholt * may be linked against several modules, typically HAL.dll, ntoskrnl.exe 431152909Sanholt * and NDIS.SYS. For each module, there is a list of imported function 432152909Sanholt * names and their addresses. 433152909Sanholt */ 434152909Sanholt 435152909Sanholtint 436152909Sanholtpe_get_import_descriptor(imgbase, desc, module) 437152909Sanholt vm_offset_t imgbase; 438152909Sanholt image_import_descriptor *desc; 439152909Sanholt char *module; 440152909Sanholt{ 441152909Sanholt vm_offset_t offset; 442152909Sanholt image_import_descriptor *imp_desc; 443152909Sanholt char *modname; 444152909Sanholt 445152909Sanholt if (imgbase == 0 || module == NULL || desc == NULL) 446152909Sanholt return(EINVAL); 447152909Sanholt 448182080Srnoland offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_IMPORT); 449152909Sanholt if (offset == 0) 450152909Sanholt return (ENOENT); 451145132Sanholt 452145132Sanholt imp_desc = (void *)offset; 453145132Sanholt 454145132Sanholt while (imp_desc->iid_nameaddr) { 455183573Srnoland modname = (char *)pe_translate_addr(imgbase, 456182080Srnoland imp_desc->iid_nameaddr); 457145132Sanholt if (!strncmp(module, modname, strlen(module))) { 458145132Sanholt bcopy((char *)imp_desc, (char *)desc, 459145132Sanholt sizeof(image_import_descriptor)); 460145132Sanholt return(0); 461145132Sanholt } 462145132Sanholt imp_desc++; 463145132Sanholt } 464183573Srnoland 465145132Sanholt return (ENOENT); 466145132Sanholt} 467145132Sanholt 468145132Sanholt#ifdef _KERNEL 469145132Sanholtint 470145132Sanholtpe_get_messagetable(imgbase, md) 471145132Sanholt vm_offset_t imgbase; 472145132Sanholt message_resource_data **md; 473145132Sanholt{ 474145132Sanholt image_resource_directory *rdir, *rtype; 475145132Sanholt image_resource_directory_entry *dent, *dent2; 476182080Srnoland image_resource_data_entry *rent; 477145132Sanholt vm_offset_t offset; 478183573Srnoland int i; 479145132Sanholt 480145132Sanholt if (imgbase == 0) 481145132Sanholt return(EINVAL); 482145132Sanholt 483145132Sanholt offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_RESOURCE); 484145132Sanholt if (offset == 0) 485182080Srnoland return (ENOENT); 486145132Sanholt 487145132Sanholt rdir = (image_resource_directory *)offset; 488145132Sanholt 489145132Sanholt dent = (image_resource_directory_entry *)(offset + 490145132Sanholt sizeof(image_resource_directory)); 491145132Sanholt 492145132Sanholt for (i = 0; i < rdir->ird_id_entries; i++){ 493183573Srnoland if (dent->irde_name != RT_MESSAGETABLE) { 494145132Sanholt dent++; 495145132Sanholt continue; 496145132Sanholt } 497145132Sanholt dent2 = dent; 498145132Sanholt while (dent2->irde_dataoff & RESOURCE_DIR_FLAG) { 499145132Sanholt rtype = (image_resource_directory *)(offset + 500145132Sanholt (dent2->irde_dataoff & ~RESOURCE_DIR_FLAG)); 501182080Srnoland dent2 = (image_resource_directory_entry *) 502145132Sanholt ((uintptr_t)rtype + 503145132Sanholt sizeof(image_resource_directory)); 504145132Sanholt } 505183573Srnoland rent = (image_resource_data_entry *)(offset + 506145132Sanholt dent2->irde_dataoff); 507145132Sanholt *md = (message_resource_data *)pe_translate_addr(imgbase, 508145132Sanholt rent->irde_offset); 509145132Sanholt return(0); 510145132Sanholt } 511145132Sanholt 512183573Srnoland return(ENOENT); 513183573Srnoland} 514145132Sanholt 515145132Sanholtint 516145132Sanholtpe_get_message(imgbase, id, str, len) 517145132Sanholt vm_offset_t imgbase; 518145132Sanholt uint32_t id; 519145132Sanholt char **str; 520145132Sanholt int *len; 521145132Sanholt{ 522145132Sanholt message_resource_data *md = NULL; 523183573Srnoland message_resource_block *mb; 524145132Sanholt message_resource_entry *me; 525145132Sanholt int i; 526145132Sanholt char m[1024], *msg; 527145132Sanholt 528145132Sanholt pe_get_messagetable(imgbase, &md); 529145132Sanholt 530145132Sanholt if (md == NULL) 531145132Sanholt return(ENOENT); 532145132Sanholt 533145132Sanholt mb = (message_resource_block *)((uintptr_t)md + 534145132Sanholt sizeof(message_resource_data)); 535145132Sanholt 536145132Sanholt for (i = 0; i < md->mrd_numblocks; i++) { 537145132Sanholt if (id >= mb->mrb_lowid && id <= mb->mrb_highid) { 538145132Sanholt me = (message_resource_entry *)((uintptr_t)md + 539145132Sanholt mb->mrb_entryoff); 540145132Sanholt for (i = id - mb->mrb_lowid; i > 0; i--) 541145132Sanholt me = (message_resource_entry *)((uintptr_t)me + 542145132Sanholt me->mre_len); 543145132Sanholt if (me->mre_flags == MESSAGE_RESOURCE_UNICODE) { 544145132Sanholt msg = m; 545183573Srnoland ndis_unicode_to_ascii((uint16_t *)me->mre_text, 546183573Srnoland me->mre_len, &msg); 547145132Sanholt *str = m; 548145132Sanholt } else 549183573Srnoland *str = me->mre_text; 550145132Sanholt *len = me->mre_len; 551145132Sanholt return(0); 552145132Sanholt } 553145132Sanholt mb++; 554145132Sanholt } 555145132Sanholt 556145132Sanholt return(ENOENT); 557145132Sanholt} 558145132Sanholt#endif 559145132Sanholt 560145132Sanholt/* 561145132Sanholt * Find the function that matches a particular name. This doesn't 562145132Sanholt * need to be particularly speedy since it's only run when loading 563145132Sanholt * a module for the first time. 564145132Sanholt */ 565145132Sanholt 566145132Sanholtstatic vm_offset_t 567152909Sanholtpe_functbl_match(functbl, name) 568183573Srnoland image_patch_table *functbl; 569183573Srnoland char *name; 570145132Sanholt{ 571182080Srnoland image_patch_table *p; 572145132Sanholt 573183573Srnoland if (functbl == NULL || name == NULL) 574145132Sanholt return(0); 575145132Sanholt 576145132Sanholt p = functbl; 577183573Srnoland 578183573Srnoland while (p->ipt_name != NULL) { 579145132Sanholt if (!strcmp(p->ipt_name, name)) 580145132Sanholt return((uint32_t)p->ipt_func); 581145132Sanholt p++; 582145132Sanholt } 583145132Sanholt printf ("no match for %s\n", name); 584145132Sanholt return((vm_offset_t)p->ipt_func); 585183573Srnoland} 586182883Srnoland 587152909Sanholt/* 588152909Sanholt * Patch the imported function addresses for a given module. 589182883Srnoland * The caller must specify the module name and provide a table 590152909Sanholt * of function pointers that will be patched into the jump table. 591145132Sanholt * Note that there are actually two copies of the jump table: one 592145132Sanholt * copy is left alone. In a .SYS file, the jump tables are usually 593145132Sanholt * merged into the INIT segment. 594145132Sanholt * 595145132Sanholt * Note: Windows uses the _stdcall calling convention. This means 596182080Srnoland * that the callback functions provided in the function table must 597145132Sanholt * be declared using __attribute__((__stdcall__)), otherwise the 598152909Sanholt * Windows code will likely screw up the %esp register and cause 599152909Sanholt * us to jump to an invalid address when it returns. 600183573Srnoland */ 601183573Srnoland 602183573Srnolandint 603183573Srnolandpe_patch_imports(imgbase, module, functbl) 604145132Sanholt vm_offset_t imgbase; 605152909Sanholt char *module; 606145132Sanholt image_patch_table *functbl; 607183573Srnoland{ 608183573Srnoland image_import_descriptor imp_desc; 609183573Srnoland char *fname; 610145132Sanholt vm_offset_t *nptr, *fptr; 611145132Sanholt vm_offset_t func; 612145132Sanholt 613145132Sanholt if (imgbase == 0 || module == NULL || functbl == NULL) 614145132Sanholt return(EINVAL); 615145132Sanholt 616152909Sanholt if (pe_get_import_descriptor(imgbase, &imp_desc, module)) 617152909Sanholt return(ENOEXEC); 618145132Sanholt 619145132Sanholt nptr = (vm_offset_t *)pe_translate_addr(imgbase, 620182080Srnoland imp_desc.iid_import_name_table_addr); 621145132Sanholt fptr = (vm_offset_t *)pe_translate_addr(imgbase, 622183573Srnoland imp_desc.iid_import_address_table_addr); 623145132Sanholt 624145132Sanholt while (nptr != NULL && pe_translate_addr(imgbase, *nptr)) { 625145132Sanholt fname = (char *)pe_translate_addr(imgbase, (*nptr) + 2); 626145132Sanholt func = pe_functbl_match(functbl, fname); 627145132Sanholt if (func) 628145132Sanholt *fptr = func; 629145132Sanholt#ifdef notdef 630145132Sanholt if (*fptr == 0) 631182080Srnoland return(ENOENT); 632145132Sanholt#endif 633145132Sanholt nptr++; 634183573Srnoland fptr++; 635183573Srnoland } 636145132Sanholt 637145132Sanholt return(0); 638145132Sanholt} 639145132Sanholt