1 /*-
2 * Copyright (c) 2003
3 * Bill Paul <wpaul@windriver.com>. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Bill Paul.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/cdefs.h>
34 #ifdef __FreeBSD__
35 __FBSDID("$FreeBSD: src/sys/compat/ndis/subr_pe.c,v 1.7.2.3 2005/03/31 04:24:36 wpaul Exp $");
36 #endif
37 #ifdef __NetBSD__
38 __KERNEL_RCSID(0, "$NetBSD: subr_pe.c,v 1.4 2006/05/14 21:24:50 elad Exp $");
39 #endif
40
41
42 /*
43 * This file contains routines for relocating and dynamically linking
44 * executable object code files in the Windows(r) PE (Portable Executable)
45 * format. In Windows, anything with a .EXE, .DLL or .SYS extention is
46 * considered an executable, and all such files have some structures in
47 * common. The PE format was apparently based largely on COFF but has
48 * mutated significantly over time. We are mainly concerned with .SYS files,
49 * so this module implements only enough routines to be able to parse the
50 * headers and sections of a .SYS object file and perform the necessary
51 * relocations and jump table patching to allow us to call into it
52 * (and to have it call back to us). Note that while this module
53 * can handle fixups for imported symbols, it knows nothing about
54 * exporting them.
55 */
56
57 #include <sys/param.h>
58 #include <sys/types.h>
59 #include <sys/errno.h>
60 #include <sys/lock.h>
61 #ifdef _KERNEL
62 #include <sys/systm.h>
63 extern int ndis_strncasecmp(const char *, const char *, size_t);
64 #define strncasecmp(a, b, c) ndis_strncasecmp(a, b, c)
65 #else
66 #include <stdio.h>
67 #include <stdlib.h>
68 #include <unistd.h>
69 #include <string.h>
70 #endif
71
72 #include <compat/ndis/pe_var.h>
73
74 static vm_offset_t pe_functbl_match(image_patch_table *, char *);
75
76 /*
77 * Check for an MS-DOS executable header. All Windows binaries
78 * have a small MS-DOS executable prepended to them to print out
79 * the "This program requires Windows" message. Even .SYS files
80 * have this header, in spite of the fact that you're can't actually
81 * run them directly.
82 */
83
84 int
85 pe_get_dos_header(imgbase, hdr)
86 vm_offset_t imgbase;
87 image_dos_header *hdr;
88 {
89 uint16_t signature;
90
91 if (imgbase == 0 || hdr == NULL)
92 return (EINVAL);
93
94 signature = *(uint16_t *)imgbase;
95 if (signature != IMAGE_DOS_SIGNATURE)
96 return (ENOEXEC);
97
98 bcopy ((char *)imgbase, (char *)hdr, sizeof(image_dos_header));
99
100 return(0);
101 }
102
103 /*
104 * Verify that this image has a Windows NT PE signature.
105 */
106
107 int
108 pe_is_nt_image(imgbase)
109 vm_offset_t imgbase;
110 {
111 uint32_t signature;
112 image_dos_header *dos_hdr;
113
114 if (imgbase == 0)
115 return (EINVAL);
116
117 signature = *(uint16_t *)imgbase;
118 if (signature == IMAGE_DOS_SIGNATURE) {
119 dos_hdr = (image_dos_header *)imgbase;
120 signature = *(uint32_t *)(imgbase + dos_hdr->idh_lfanew);
121 if (signature == IMAGE_NT_SIGNATURE)
122 return(0);
123 }
124
125 return(ENOEXEC);
126 }
127
128 /*
129 * Return a copy of the optional header. This contains the
130 * executable entry point and the directory listing which we
131 * need to find the relocations and imports later.
132 */
133
134 int
135 pe_get_optional_header(imgbase, hdr)
136 vm_offset_t imgbase;
137 image_optional_header *hdr;
138 {
139 image_dos_header *dos_hdr;
140 image_nt_header *nt_hdr;
141
142 if (imgbase == 0 || hdr == NULL)
143 return(EINVAL);
144
145 if (pe_is_nt_image(imgbase))
146 return (EINVAL);
147
148 dos_hdr = (image_dos_header *)(imgbase);
149 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
150
151 bcopy ((char *)&nt_hdr->inh_optionalhdr, (char *)hdr,
152 sizeof(image_optional_header));
153
154 return(0);
155 }
156
157 /*
158 * Return a copy of the file header. Contains the number of
159 * sections in this image.
160 */
161
162 int
163 pe_get_file_header(imgbase, hdr)
164 vm_offset_t imgbase;
165 image_file_header *hdr;
166 {
167 image_dos_header *dos_hdr;
168 image_nt_header *nt_hdr;
169
170 if (imgbase == 0 || hdr == NULL)
171 return(EINVAL);
172
173 if (pe_is_nt_image(imgbase))
174 return (EINVAL);
175
176 dos_hdr = (image_dos_header *)imgbase;
177 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
178
179 bcopy ((char *)&nt_hdr->inh_filehdr, (char *)hdr,
180 sizeof(image_file_header));
181
182 return(0);
183 }
184
185 /*
186 * Return the header of the first section in this image (usually
187 * .text).
188 */
189
190 int
191 pe_get_section_header(imgbase, hdr)
192 vm_offset_t imgbase;
193 image_section_header *hdr;
194 {
195 image_dos_header *dos_hdr;
196 image_nt_header *nt_hdr;
197 image_section_header *sect_hdr;
198
199 if (imgbase == 0 || hdr == NULL)
200 return(EINVAL);
201
202 if (pe_is_nt_image(imgbase))
203 return (EINVAL);
204
205 dos_hdr = (image_dos_header *)imgbase;
206 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
207 sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr +
208 sizeof(image_nt_header));
209
210 bcopy ((char *)sect_hdr, (char *)hdr, sizeof(image_section_header));
211
212 return(0);
213 }
214
215 /*
216 * Return the number of sections in this executable, or 0 on error.
217 */
218
219 int
220 pe_numsections(imgbase)
221 vm_offset_t imgbase;
222 {
223 image_file_header file_hdr;
224
225 if (pe_get_file_header(imgbase, &file_hdr))
226 return(0);
227
228 return (file_hdr.ifh_numsections);
229 }
230
231 /*
232 * Return the base address that this image was linked for.
233 * This helps us calculate relocation addresses later.
234 */
235
236 vm_offset_t
237 pe_imagebase(imgbase)
238 vm_offset_t imgbase;
239 {
240 image_optional_header optional_hdr;
241
242 if (pe_get_optional_header(imgbase, &optional_hdr))
243 return(0);
244
245 return (optional_hdr.ioh_imagebase);
246 }
247
248 /*
249 * Return the offset of a given directory structure within the
250 * image. Directories reside within sections.
251 */
252
253 vm_offset_t
254 pe_directory_offset(imgbase, diridx)
255 vm_offset_t imgbase;
256 uint32_t diridx;
257 {
258 image_optional_header opt_hdr;
259 vm_offset_t dir;
260
261 if (pe_get_optional_header(imgbase, &opt_hdr))
262 return(0);
263
264 if (diridx >= opt_hdr.ioh_rva_size_cnt)
265 return(0);
266
267 dir = opt_hdr.ioh_datadir[diridx].idd_vaddr;
268
269 return(pe_translate_addr(imgbase, dir));
270 }
271
272 vm_offset_t
273 pe_translate_addr(imgbase, rva)
274 vm_offset_t imgbase;
275 vm_offset_t rva;
276 {
277 image_optional_header opt_hdr;
278 image_section_header *sect_hdr;
279 image_dos_header *dos_hdr;
280 image_nt_header *nt_hdr;
281 int i = 0, sections, fixedlen;
282
283 if (pe_get_optional_header(imgbase, &opt_hdr))
284 return(0);
285
286 sections = pe_numsections(imgbase);
287
288 dos_hdr = (image_dos_header *)imgbase;
289 nt_hdr = (image_nt_header *)(imgbase + dos_hdr->idh_lfanew);
290 sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr +
291 sizeof(image_nt_header));
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
327 int
328 pe_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);
349 sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr +
350 sizeof(image_nt_header));
351
352 for (i = 0; i < sections; i++) {
353 if (!strcmp ((char *)§_hdr->ish_name, name)) {
354 bcopy((char *)sect_hdr, (char *)hdr,
355 sizeof(image_section_header));
356 return(0);
357 } else
358 sect_hdr++;
359 }
360
361 return (ENOEXEC);
362 }
363
364 /*
365 * Apply the base relocations to this image. The relocation table
366 * resides within the .reloc section. Relocations are specified in
367 * blocks which refer to a particular page. We apply the relocations
368 * one page block at a time.
369 */
370
371 int
372 pe_relocate(imgbase)
373 vm_offset_t imgbase;
374 {
375 image_section_header sect;
376 image_base_reloc *relhdr;
377 uint16_t rel, *sloc;
378 vm_offset_t base;
379 vm_size_t delta;
380 uint32_t *lloc;
381 uint64_t *qloc;
382 int i, count;
383 vm_offset_t txt;
384
385 base = pe_imagebase(imgbase);
386 pe_get_section(imgbase, §, ".text");
387 txt = pe_translate_addr(imgbase, sect.ish_vaddr);
388 delta = (uint32_t)(txt) - base - sect.ish_vaddr;
389
390 pe_get_section(imgbase, §, ".reloc");
391
392 relhdr = (image_base_reloc *)(imgbase + sect.ish_rawdataaddr);
393
394 do {
395 count = (relhdr->ibr_blocksize -
396 (sizeof(uint32_t) * 2)) / sizeof(uint16_t);
397 for (i = 0; i < count; i++) {
398 rel = relhdr->ibr_rel[i];
399 switch (IMR_RELTYPE(rel)) {
400 case IMAGE_REL_BASED_ABSOLUTE:
401 break;
402 case IMAGE_REL_BASED_HIGHLOW:
403 lloc = (uint32_t *)pe_translate_addr(imgbase,
404 relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
405 *lloc = pe_translate_addr(imgbase,
406 (*lloc - base));
407 break;
408 case IMAGE_REL_BASED_HIGH:
409 sloc = (uint16_t *)pe_translate_addr(imgbase,
410 relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
411 *sloc += (delta & 0xFFFF0000) >> 16;
412 break;
413 case IMAGE_REL_BASED_LOW:
414 sloc = (uint16_t *)pe_translate_addr(imgbase,
415 relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
416 *sloc += (delta & 0xFFFF);
417 break;
418 case IMAGE_REL_BASED_DIR64:
419 qloc = (uint64_t *)pe_translate_addr(imgbase,
420 relhdr->ibr_vaddr + IMR_RELOFFSET(rel));
421 *qloc = pe_translate_addr(imgbase,
422 (*qloc - base));
423 break;
424
425 default:
426 printf ("[%d]reloc type: %d\n",i,
427 IMR_RELTYPE(rel));
428 break;
429 }
430 }
431 relhdr = (image_base_reloc *)((vm_offset_t)relhdr +
432 relhdr->ibr_blocksize);
433 } while (relhdr->ibr_blocksize);
434
435 return(0);
436 }
437
438 /*
439 * Return the import descriptor for a particular module. An image
440 * may be linked against several modules, typically HAL.dll, ntoskrnl.exe
441 * and NDIS.SYS. For each module, there is a list of imported function
442 * names and their addresses.
443 *
444 * Note: module names are case insensitive!
445 */
446
447 int
448 pe_get_import_descriptor(imgbase, desc, module)
449 vm_offset_t imgbase;
450 image_import_descriptor *desc;
451 const char *module;
452 {
453 vm_offset_t offset;
454 image_import_descriptor *imp_desc;
455 char *modname;
456
457 if (imgbase == 0 || module == NULL || desc == NULL)
458 return(EINVAL);
459
460 offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_IMPORT);
461 if (offset == 0)
462 return (ENOENT);
463
464 imp_desc = (void *)offset;
465
466 while (imp_desc->iid_nameaddr) {
467 modname = (char *)pe_translate_addr(imgbase,
468 imp_desc->iid_nameaddr);
469 if (!strncasecmp(module, modname, strlen(module))) {
470 bcopy((char *)imp_desc, (char *)desc,
471 sizeof(image_import_descriptor));
472 return(0);
473 }
474 imp_desc++;
475 }
476
477 return (ENOENT);
478 }
479
480 int
481 pe_get_messagetable(imgbase, md)
482 vm_offset_t imgbase;
483 message_resource_data **md;
484 {
485 image_resource_directory *rdir, *rtype;
486 image_resource_directory_entry *dent, *dent2;
487 image_resource_data_entry *rent;
488 vm_offset_t offset;
489 int i;
490
491 if (imgbase == 0)
492 return(EINVAL);
493
494 offset = pe_directory_offset(imgbase, IMAGE_DIRECTORY_ENTRY_RESOURCE);
495 if (offset == 0)
496 return (ENOENT);
497
498 rdir = (image_resource_directory *)offset;
499
500 dent = (image_resource_directory_entry *)(offset +
501 sizeof(image_resource_directory));
502
503 for (i = 0; i < rdir->ird_id_entries; i++){
504 if (dent->irde_name != RT_MESSAGETABLE) {
505 dent++;
506 continue;
507 }
508 dent2 = dent;
509 while (dent2->irde_dataoff & RESOURCE_DIR_FLAG) {
510 rtype = (image_resource_directory *)(offset +
511 (dent2->irde_dataoff & ~RESOURCE_DIR_FLAG));
512 dent2 = (image_resource_directory_entry *)
513 ((uintptr_t)rtype +
514 sizeof(image_resource_directory));
515 }
516 rent = (image_resource_data_entry *)(offset +
517 dent2->irde_dataoff);
518 *md = (message_resource_data *)pe_translate_addr(imgbase,
519 rent->irde_offset);
520 return(0);
521 }
522
523 return(ENOENT);
524 }
525
526 int
527 pe_get_message(imgbase, id, str, len, flags)
528 vm_offset_t imgbase;
529 uint32_t id;
530 char **str;
531 int *len;
532 uint16_t *flags;
533 {
534 message_resource_data *md = NULL;
535 message_resource_block *mb;
536 message_resource_entry *me;
537 uint32_t i;
538
539 pe_get_messagetable(imgbase, &md);
540
541 if (md == NULL)
542 return(ENOENT);
543
544 mb = (message_resource_block *)((uintptr_t)md +
545 sizeof(message_resource_data));
546
547 for (i = 0; i < md->mrd_numblocks; i++) {
548 if (id >= mb->mrb_lowid && id <= mb->mrb_highid) {
549 me = (message_resource_entry *)((uintptr_t)md +
550 mb->mrb_entryoff);
551 for (i = id - mb->mrb_lowid; i > 0; i--)
552 me = (message_resource_entry *)((uintptr_t)me +
553 me->mre_len);
554 *str = me->mre_text;
555 *len = me->mre_len;
556 *flags = me->mre_flags;
557 return(0);
558 }
559 mb++;
560 }
561
562 return(ENOENT);
563 }
564
565 /*
566 * Find the function that matches a particular name. This doesn't
567 * need to be particularly speedy since it's only run when loading
568 * a module for the first time.
569 */
570
571 static vm_offset_t
572 pe_functbl_match(functbl, name)
573 image_patch_table *functbl;
574 char *name;
575 {
576 image_patch_table *p;
577
578 if (functbl == NULL || name == NULL)
579 return(0);
580
581 p = functbl;
582
583 while (p->ipt_name != NULL) {
584 if (!strcmp(p->ipt_name, name))
585 return((vm_offset_t)p->ipt_wrap);
586 p++;
587 }
588 printf ("no match for %s\n", name);
589
590 /*
591 * Return the wrapper pointer for this routine.
592 * For x86, this is the same as the funcptr.
593 * For amd64, this points to a wrapper routine
594 * that does calling convention translation and
595 * then invokes the underlying routine.
596 */
597 return((vm_offset_t)p->ipt_wrap);
598 }
599
600 /*
601 * Patch the imported function addresses for a given module.
602 * The caller must specify the module name and provide a table
603 * of function pointers that will be patched into the jump table.
604 * Note that there are actually two copies of the jump table: one
605 * copy is left alone. In a .SYS file, the jump tables are usually
606 * merged into the INIT segment.
607 */
608
609 int
610 pe_patch_imports(imgbase, module, functbl)
611 vm_offset_t imgbase;
612 const char *module;
613 image_patch_table *functbl;
614 {
615 image_import_descriptor imp_desc;
616 char *fname;
617 vm_offset_t *nptr, *fptr;
618 vm_offset_t func;
619
620 if (imgbase == 0 || module == NULL || functbl == NULL)
621 return(EINVAL);
622
623 if (pe_get_import_descriptor(imgbase, &imp_desc, module))
624 return(ENOEXEC);
625
626 nptr = (vm_offset_t *)pe_translate_addr(imgbase,
627 imp_desc.iid_import_name_table_addr);
628 fptr = (vm_offset_t *)pe_translate_addr(imgbase,
629 imp_desc.iid_import_address_table_addr);
630
631 while (nptr != NULL && pe_translate_addr(imgbase, *nptr)) {
632 fname = (char *)pe_translate_addr(imgbase, (*nptr) + 2);
633 func = pe_functbl_match(functbl, fname);
634 if (func)
635 *fptr = func;
636 #ifdef notdef
637 if (*fptr == 0)
638 return(ENOENT);
639 #endif
640 nptr++;
641 fptr++;
642 }
643
644 return(0);
645 }
Cache object: 6ada95c920004905b28667b74625f7f6
|