]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/compat/ndis/subr_pe.c
ident(1): Normalizing date format
[FreeBSD/FreeBSD.git] / sys / compat / ndis / subr_pe.c
1 /*-
2  * SPDX-License-Identifier: BSD-4-Clause
3  *
4  * Copyright (c) 2003
5  *      Bill Paul <wpaul@windriver.com>.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Bill Paul.
18  * 4. Neither the name of the author nor the names of any co-contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32  * THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 /*
39  * This file contains routines for relocating and dynamically linking
40  * executable object code files in the Windows(r) PE (Portable Executable)
41  * format. In Windows, anything with a .EXE, .DLL or .SYS extension is
42  * considered an executable, and all such files have some structures in
43  * common. The PE format was apparently based largely on COFF but has
44  * mutated significantly over time. We are mainly concerned with .SYS files,
45  * so this module implements only enough routines to be able to parse the
46  * headers and sections of a .SYS object file and perform the necessary
47  * relocations and jump table patching to allow us to call into it
48  * (and to have it call back to us). Note that while this module
49  * can handle fixups for imported symbols, it knows nothing about
50  * exporting them.
51  */
52
53 #include <sys/param.h>
54 #include <sys/types.h>
55 #include <sys/errno.h>
56 #ifdef _KERNEL
57 #include <sys/systm.h>
58 #else
59 #include <stdio.h>
60 #include <stddef.h>
61 #include <stdlib.h>
62 #include <unistd.h>
63 #include <string.h>
64 #endif
65
66 #include <compat/ndis/pe_var.h>
67
68 static 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
78 int
79 pe_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
101 int
102 pe_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
128 int
129 pe_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,
146             nt_hdr->inh_filehdr.ifh_optionalhdrlen);
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
156 int
157 pe_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
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
192 int
193 pe_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);
209         sect_hdr = IMAGE_FIRST_SECTION(nt_hdr);
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
220 int
221 pe_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
237 vm_offset_t
238 pe_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
254 vm_offset_t
255 pe_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
273 vm_offset_t
274 pe_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);
291         sect_hdr = IMAGE_FIRST_SECTION(nt_hdr);
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_FIRST_SECTION(nt_hdr);
350
351         for (i = 0; i < sections; i++) {
352                 if (!strcmp ((char *)&sect_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
370 int
371 pe_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, &sect, ".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, &sect, ".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
446 int
447 pe_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
479 int
480 pe_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
525 int
526 pe_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
570 static vm_offset_t
571 pe_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
608 int
609 pe_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 }