[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/compat/ndis/subr_pe.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  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: src/sys/compat/ndis/subr_pe.c,v 1.13 2007/04/06 11:18:57 pjd Exp $");
 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 *)&sect_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, &sect, ".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, &sect, ".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 }
643 

Cache object: fe8e4993994e889b417ad359bb02acae


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.