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>
|
34__FBSDID("$FreeBSD: head/sys/compat/ndis/subr_pe.c 141963 2005-02-16 05:41:18Z wpaul $");
| 34__FBSDID("$FreeBSD: head/sys/compat/ndis/subr_pe.c 142037 2005-02-18 04:33:34Z wpaul $");
|
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 vm_offset_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);
| 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 vm_offset_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 &&
| 298 if (sect_hdr->ish_vaddr <= (uint32_t)rva &&
|
299 (sect_hdr->ish_vaddr + fixedlen) >
| 299 (sect_hdr->ish_vaddr + fixedlen) >
|
300 (u_int32_t)rva)
| 300 (uint32_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 vm_offset_t base; 370 vm_size_t delta; 371 uint32_t *lloc; 372 uint64_t *qloc; 373 int i, count; 374 vm_offset_t txt; 375 376 base = pe_imagebase(imgbase); 377 pe_get_section(imgbase, §, ".text"); 378 txt = pe_translate_addr(imgbase, sect.ish_vaddr); 379 delta = (uint32_t)(txt) - base - sect.ish_vaddr; 380 381 pe_get_section(imgbase, §, ".reloc"); 382 383 relhdr = (image_base_reloc *)(imgbase + sect.ish_rawdataaddr); 384 385 do { 386 count = (relhdr->ibr_blocksize - 387 (sizeof(uint32_t) * 2)) / sizeof(uint16_t); 388 for (i = 0; i < count; i++) { 389 rel = relhdr->ibr_rel[i]; 390 switch (IMR_RELTYPE(rel)) { 391 case IMAGE_REL_BASED_ABSOLUTE: 392 break; 393 case IMAGE_REL_BASED_HIGHLOW: 394 lloc = (uint32_t *)pe_translate_addr(imgbase, 395 relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 396 *lloc = pe_translate_addr(imgbase, 397 (*lloc - base)); 398 break; 399 case IMAGE_REL_BASED_HIGH: 400 sloc = (uint16_t *)pe_translate_addr(imgbase, 401 relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 402 *sloc += (delta & 0xFFFF0000) >> 16; 403 break; 404 case IMAGE_REL_BASED_LOW: 405 sloc = (uint16_t *)pe_translate_addr(imgbase, 406 relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 407 *sloc += (delta & 0xFFFF); 408 break; 409 case IMAGE_REL_BASED_DIR64: 410 qloc = (uint64_t *)pe_translate_addr(imgbase, 411 relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 412 *qloc = pe_translate_addr(imgbase, 413 (*qloc - base)); 414 break; 415 416 default: 417 printf ("[%d]reloc type: %d\n",i, 418 IMR_RELTYPE(rel)); 419 break; 420 } 421 } 422 relhdr = (image_base_reloc *)((vm_offset_t)relhdr + 423 relhdr->ibr_blocksize); 424 } while (relhdr->ibr_blocksize); 425 426 return(0); 427} 428 429/* 430 * Return the import descriptor for a particular module. An image 431 * may be linked against several modules, typically HAL.dll, ntoskrnl.exe 432 * and NDIS.SYS. For each module, there is a list of imported function 433 * names and their addresses. 434 */ 435 436int 437pe_get_import_descriptor(imgbase, desc, module) 438 vm_offset_t imgbase; 439 image_import_descriptor *desc; 440 char *module; 441{ 442 vm_offset_t offset; 443 image_import_descriptor *imp_desc; 444 char *modname; 445 446 if (imgbase == 0 || module == NULL || desc == NULL) 447 return(EINVAL); 448 449 offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_IMPORT); 450 if (offset == 0) 451 return (ENOENT); 452 453 imp_desc = (void *)offset; 454 455 while (imp_desc->iid_nameaddr) { 456 modname = (char *)pe_translate_addr(imgbase, 457 imp_desc->iid_nameaddr); 458 if (!strncmp(module, modname, strlen(module))) { 459 bcopy((char *)imp_desc, (char *)desc, 460 sizeof(image_import_descriptor)); 461 return(0); 462 } 463 imp_desc++; 464 } 465 466 return (ENOENT); 467} 468 469int 470pe_get_messagetable(imgbase, md) 471 vm_offset_t imgbase; 472 message_resource_data **md; 473{ 474 image_resource_directory *rdir, *rtype; 475 image_resource_directory_entry *dent, *dent2; 476 image_resource_data_entry *rent; 477 vm_offset_t offset; 478 int i; 479 480 if (imgbase == 0) 481 return(EINVAL); 482 483 offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_RESOURCE); 484 if (offset == 0) 485 return (ENOENT); 486 487 rdir = (image_resource_directory *)offset; 488 489 dent = (image_resource_directory_entry *)(offset + 490 sizeof(image_resource_directory)); 491 492 for (i = 0; i < rdir->ird_id_entries; i++){ 493 if (dent->irde_name != RT_MESSAGETABLE) { 494 dent++; 495 continue; 496 } 497 dent2 = dent; 498 while (dent2->irde_dataoff & RESOURCE_DIR_FLAG) { 499 rtype = (image_resource_directory *)(offset + 500 (dent2->irde_dataoff & ~RESOURCE_DIR_FLAG)); 501 dent2 = (image_resource_directory_entry *) 502 ((uintptr_t)rtype + 503 sizeof(image_resource_directory)); 504 } 505 rent = (image_resource_data_entry *)(offset + 506 dent2->irde_dataoff); 507 *md = (message_resource_data *)pe_translate_addr(imgbase, 508 rent->irde_offset); 509 return(0); 510 } 511 512 return(ENOENT); 513} 514 515int 516pe_get_message(imgbase, id, str, len, flags) 517 vm_offset_t imgbase; 518 uint32_t id; 519 char **str; 520 int *len; 521 uint16_t *flags; 522{ 523 message_resource_data *md = NULL; 524 message_resource_block *mb; 525 message_resource_entry *me; 526 uint32_t i; 527 528 pe_get_messagetable(imgbase, &md); 529 530 if (md == NULL) 531 return(ENOENT); 532 533 mb = (message_resource_block *)((uintptr_t)md + 534 sizeof(message_resource_data)); 535 536 for (i = 0; i < md->mrd_numblocks; i++) { 537 if (id >= mb->mrb_lowid && id <= mb->mrb_highid) { 538 me = (message_resource_entry *)((uintptr_t)md + 539 mb->mrb_entryoff); 540 for (i = id - mb->mrb_lowid; i > 0; i--) 541 me = (message_resource_entry *)((uintptr_t)me + 542 me->mre_len); 543 *str = me->mre_text; 544 *len = me->mre_len; 545 *flags = me->mre_flags; 546 return(0); 547 } 548 mb++; 549 } 550 551 return(ENOENT); 552} 553 554/* 555 * Find the function that matches a particular name. This doesn't 556 * need to be particularly speedy since it's only run when loading 557 * a module for the first time. 558 */ 559 560static vm_offset_t 561pe_functbl_match(functbl, name) 562 image_patch_table *functbl; 563 char *name; 564{ 565 image_patch_table *p; 566 567 if (functbl == NULL || name == NULL) 568 return(0); 569 570 p = functbl; 571 572 while (p->ipt_name != NULL) { 573 if (!strcmp(p->ipt_name, name)) 574 return((vm_offset_t)p->ipt_wrap); 575 p++; 576 } 577 printf ("no match for %s\n", name); 578 579 /* 580 * Return the wrapper pointer for this routine. 581 * For x86, this is the same as the funcptr. 582 * For amd64, this points to a wrapper routine 583 * that does calling convention translation and 584 * then invokes the underlying routine. 585 */ 586 return((vm_offset_t)p->ipt_wrap); 587} 588 589/* 590 * Patch the imported function addresses for a given module. 591 * The caller must specify the module name and provide a table 592 * of function pointers that will be patched into the jump table. 593 * Note that there are actually two copies of the jump table: one 594 * copy is left alone. In a .SYS file, the jump tables are usually 595 * merged into the INIT segment. 596 */ 597 598int 599pe_patch_imports(imgbase, module, functbl) 600 vm_offset_t imgbase; 601 char *module; 602 image_patch_table *functbl; 603{ 604 image_import_descriptor imp_desc; 605 char *fname; 606 vm_offset_t *nptr, *fptr; 607 vm_offset_t func; 608 609 if (imgbase == 0 || module == NULL || functbl == NULL) 610 return(EINVAL); 611 612 if (pe_get_import_descriptor(imgbase, &imp_desc, module)) 613 return(ENOEXEC); 614 615 nptr = (vm_offset_t *)pe_translate_addr(imgbase, 616 imp_desc.iid_import_name_table_addr); 617 fptr = (vm_offset_t *)pe_translate_addr(imgbase, 618 imp_desc.iid_import_address_table_addr); 619 620 while (nptr != NULL && pe_translate_addr(imgbase, *nptr)) { 621 fname = (char *)pe_translate_addr(imgbase, (*nptr) + 2); 622 func = pe_functbl_match(functbl, fname); 623 if (func) 624 *fptr = func; 625#ifdef notdef 626 if (*fptr == 0) 627 return(ENOENT); 628#endif 629 nptr++; 630 fptr++; 631 } 632 633 return(0); 634}
| 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 vm_offset_t base; 370 vm_size_t delta; 371 uint32_t *lloc; 372 uint64_t *qloc; 373 int i, count; 374 vm_offset_t txt; 375 376 base = pe_imagebase(imgbase); 377 pe_get_section(imgbase, §, ".text"); 378 txt = pe_translate_addr(imgbase, sect.ish_vaddr); 379 delta = (uint32_t)(txt) - base - sect.ish_vaddr; 380 381 pe_get_section(imgbase, §, ".reloc"); 382 383 relhdr = (image_base_reloc *)(imgbase + sect.ish_rawdataaddr); 384 385 do { 386 count = (relhdr->ibr_blocksize - 387 (sizeof(uint32_t) * 2)) / sizeof(uint16_t); 388 for (i = 0; i < count; i++) { 389 rel = relhdr->ibr_rel[i]; 390 switch (IMR_RELTYPE(rel)) { 391 case IMAGE_REL_BASED_ABSOLUTE: 392 break; 393 case IMAGE_REL_BASED_HIGHLOW: 394 lloc = (uint32_t *)pe_translate_addr(imgbase, 395 relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 396 *lloc = pe_translate_addr(imgbase, 397 (*lloc - base)); 398 break; 399 case IMAGE_REL_BASED_HIGH: 400 sloc = (uint16_t *)pe_translate_addr(imgbase, 401 relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 402 *sloc += (delta & 0xFFFF0000) >> 16; 403 break; 404 case IMAGE_REL_BASED_LOW: 405 sloc = (uint16_t *)pe_translate_addr(imgbase, 406 relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 407 *sloc += (delta & 0xFFFF); 408 break; 409 case IMAGE_REL_BASED_DIR64: 410 qloc = (uint64_t *)pe_translate_addr(imgbase, 411 relhdr->ibr_vaddr + IMR_RELOFFSET(rel)); 412 *qloc = pe_translate_addr(imgbase, 413 (*qloc - base)); 414 break; 415 416 default: 417 printf ("[%d]reloc type: %d\n",i, 418 IMR_RELTYPE(rel)); 419 break; 420 } 421 } 422 relhdr = (image_base_reloc *)((vm_offset_t)relhdr + 423 relhdr->ibr_blocksize); 424 } while (relhdr->ibr_blocksize); 425 426 return(0); 427} 428 429/* 430 * Return the import descriptor for a particular module. An image 431 * may be linked against several modules, typically HAL.dll, ntoskrnl.exe 432 * and NDIS.SYS. For each module, there is a list of imported function 433 * names and their addresses. 434 */ 435 436int 437pe_get_import_descriptor(imgbase, desc, module) 438 vm_offset_t imgbase; 439 image_import_descriptor *desc; 440 char *module; 441{ 442 vm_offset_t offset; 443 image_import_descriptor *imp_desc; 444 char *modname; 445 446 if (imgbase == 0 || module == NULL || desc == NULL) 447 return(EINVAL); 448 449 offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_IMPORT); 450 if (offset == 0) 451 return (ENOENT); 452 453 imp_desc = (void *)offset; 454 455 while (imp_desc->iid_nameaddr) { 456 modname = (char *)pe_translate_addr(imgbase, 457 imp_desc->iid_nameaddr); 458 if (!strncmp(module, modname, strlen(module))) { 459 bcopy((char *)imp_desc, (char *)desc, 460 sizeof(image_import_descriptor)); 461 return(0); 462 } 463 imp_desc++; 464 } 465 466 return (ENOENT); 467} 468 469int 470pe_get_messagetable(imgbase, md) 471 vm_offset_t imgbase; 472 message_resource_data **md; 473{ 474 image_resource_directory *rdir, *rtype; 475 image_resource_directory_entry *dent, *dent2; 476 image_resource_data_entry *rent; 477 vm_offset_t offset; 478 int i; 479 480 if (imgbase == 0) 481 return(EINVAL); 482 483 offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_RESOURCE); 484 if (offset == 0) 485 return (ENOENT); 486 487 rdir = (image_resource_directory *)offset; 488 489 dent = (image_resource_directory_entry *)(offset + 490 sizeof(image_resource_directory)); 491 492 for (i = 0; i < rdir->ird_id_entries; i++){ 493 if (dent->irde_name != RT_MESSAGETABLE) { 494 dent++; 495 continue; 496 } 497 dent2 = dent; 498 while (dent2->irde_dataoff & RESOURCE_DIR_FLAG) { 499 rtype = (image_resource_directory *)(offset + 500 (dent2->irde_dataoff & ~RESOURCE_DIR_FLAG)); 501 dent2 = (image_resource_directory_entry *) 502 ((uintptr_t)rtype + 503 sizeof(image_resource_directory)); 504 } 505 rent = (image_resource_data_entry *)(offset + 506 dent2->irde_dataoff); 507 *md = (message_resource_data *)pe_translate_addr(imgbase, 508 rent->irde_offset); 509 return(0); 510 } 511 512 return(ENOENT); 513} 514 515int 516pe_get_message(imgbase, id, str, len, flags) 517 vm_offset_t imgbase; 518 uint32_t id; 519 char **str; 520 int *len; 521 uint16_t *flags; 522{ 523 message_resource_data *md = NULL; 524 message_resource_block *mb; 525 message_resource_entry *me; 526 uint32_t i; 527 528 pe_get_messagetable(imgbase, &md); 529 530 if (md == NULL) 531 return(ENOENT); 532 533 mb = (message_resource_block *)((uintptr_t)md + 534 sizeof(message_resource_data)); 535 536 for (i = 0; i < md->mrd_numblocks; i++) { 537 if (id >= mb->mrb_lowid && id <= mb->mrb_highid) { 538 me = (message_resource_entry *)((uintptr_t)md + 539 mb->mrb_entryoff); 540 for (i = id - mb->mrb_lowid; i > 0; i--) 541 me = (message_resource_entry *)((uintptr_t)me + 542 me->mre_len); 543 *str = me->mre_text; 544 *len = me->mre_len; 545 *flags = me->mre_flags; 546 return(0); 547 } 548 mb++; 549 } 550 551 return(ENOENT); 552} 553 554/* 555 * Find the function that matches a particular name. This doesn't 556 * need to be particularly speedy since it's only run when loading 557 * a module for the first time. 558 */ 559 560static vm_offset_t 561pe_functbl_match(functbl, name) 562 image_patch_table *functbl; 563 char *name; 564{ 565 image_patch_table *p; 566 567 if (functbl == NULL || name == NULL) 568 return(0); 569 570 p = functbl; 571 572 while (p->ipt_name != NULL) { 573 if (!strcmp(p->ipt_name, name)) 574 return((vm_offset_t)p->ipt_wrap); 575 p++; 576 } 577 printf ("no match for %s\n", name); 578 579 /* 580 * Return the wrapper pointer for this routine. 581 * For x86, this is the same as the funcptr. 582 * For amd64, this points to a wrapper routine 583 * that does calling convention translation and 584 * then invokes the underlying routine. 585 */ 586 return((vm_offset_t)p->ipt_wrap); 587} 588 589/* 590 * Patch the imported function addresses for a given module. 591 * The caller must specify the module name and provide a table 592 * of function pointers that will be patched into the jump table. 593 * Note that there are actually two copies of the jump table: one 594 * copy is left alone. In a .SYS file, the jump tables are usually 595 * merged into the INIT segment. 596 */ 597 598int 599pe_patch_imports(imgbase, module, functbl) 600 vm_offset_t imgbase; 601 char *module; 602 image_patch_table *functbl; 603{ 604 image_import_descriptor imp_desc; 605 char *fname; 606 vm_offset_t *nptr, *fptr; 607 vm_offset_t func; 608 609 if (imgbase == 0 || module == NULL || functbl == NULL) 610 return(EINVAL); 611 612 if (pe_get_import_descriptor(imgbase, &imp_desc, module)) 613 return(ENOEXEC); 614 615 nptr = (vm_offset_t *)pe_translate_addr(imgbase, 616 imp_desc.iid_import_name_table_addr); 617 fptr = (vm_offset_t *)pe_translate_addr(imgbase, 618 imp_desc.iid_import_address_table_addr); 619 620 while (nptr != NULL && pe_translate_addr(imgbase, *nptr)) { 621 fname = (char *)pe_translate_addr(imgbase, (*nptr) + 2); 622 func = pe_functbl_match(functbl, fname); 623 if (func) 624 *fptr = func; 625#ifdef notdef 626 if (*fptr == 0) 627 return(ENOENT); 628#endif 629 nptr++; 630 fptr++; 631 } 632 633 return(0); 634}
|