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