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