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