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