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