2
* Copyright (C) 2003-2004 Pontus Fuchs, Giridhar Pemmasani
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
21
#include <linux/types.h>
22
#include <asm/errno.h>
24
#include "pe_linker.h"
28
#include <linux/types.h>
29
#include <asm/errno.h>
31
#include "pe_linker.h"
35
static struct exports exports[40];
36
static int num_exports;
38
#define RVA2VA(image, rva, type) (type)rva_to_va(image, rva)
41
#define WRAP_EXPORT_FUNC void
42
static WRAP_EXPORT_FUNC get_export(char *name)
47
extern struct wrap_export ntoskernel_exports[], ndis_exports[],
48
misc_funcs_exports[], hal_exports[];
50
extern struct wrap_export usb_exports[];
53
static WRAP_EXPORT_FUNC get_export(char *name)
57
for (i = 0 ; ntoskernel_exports[i].name != NULL; i++)
58
if (strcmp(ntoskernel_exports[i].name, name) == 0)
59
return ntoskernel_exports[i].func;
61
for (i = 0 ; ndis_exports[i].name != NULL; i++)
62
if (strcmp(ndis_exports[i].name, name) == 0)
63
return ndis_exports[i].func;
65
for (i = 0 ; misc_funcs_exports[i].name != NULL; i++)
66
if (strcmp(misc_funcs_exports[i].name, name) == 0)
67
return misc_funcs_exports[i].func;
69
for (i = 0 ; hal_exports[i].name != NULL; i++)
70
if (strcmp(hal_exports[i].name, name) == 0)
71
return hal_exports[i].func;
74
for (i = 0 ; usb_exports[i].name != NULL; i++)
75
if (strcmp(usb_exports[i].name, name) == 0)
76
return usb_exports[i].func;
79
for (i = 0; i < num_exports; i++)
80
if (strcmp(exports[i].name, name) == 0)
81
return (void *)exports[i].addr;
87
static void *get_dll_init(char *name)
90
for (i = 0; i < num_exports; i++)
91
if ((strcmp(exports[i].dll, name) == 0) &&
92
(strcmp(exports[i].name, "DllInitialize") == 0))
93
return (void *)exports[i].addr;
97
/* rva_to_va, get_section and fixup_relocs are heavily based on
98
* Bill Paul's PE loader for ndisulator (Project Evil).
101
static ULONG_PTR rva_to_va(void *image, uint32_t rva)
103
struct optional_header *opt_hdr;
104
struct section_header *sect_hdr;
105
struct nt_header *nt_hdr;
107
ULONG_PTR nt_hdr_offset, ret;
109
nt_hdr_offset = *(ULONG_PTR *)(image+0x3c);
110
nt_hdr = (struct nt_header *)((char *)image + nt_hdr_offset);
112
sections = nt_hdr->file_hdr.num_sections;
113
opt_hdr = &nt_hdr->opt_hdr;
114
sect_hdr = (struct section_header *)((void *)nt_hdr +
115
sizeof(struct nt_header));
117
for (i = 0; i < sections; i++, sect_hdr++) {
118
int fixedlen = sect_hdr->virt_size;
119
fixedlen += ((opt_hdr->opt_nt_hdr.section_alignment - 1) -
120
sect_hdr->virt_size) &
121
(opt_hdr->opt_nt_hdr.section_alignment - 1);
123
if (sect_hdr->virt_addr <= (uint32_t)rva &&
124
(sect_hdr->virt_addr + fixedlen) > (uint32_t)rva)
131
ret = ((ULONG_PTR)(image + rva - sect_hdr->virt_addr +
132
sect_hdr->rawdata_addr));
136
static struct section_header *get_section(struct nt_header *nt_hdr,
140
struct section_header *sect_hdr;
142
sections = nt_hdr->file_hdr.num_sections;
143
sect_hdr = (struct section_header *)((char *)nt_hdr +
144
sizeof(struct nt_header));
145
for (i = 0; i < sections; i++)
146
if (!strcmp(sect_hdr->name, name))
155
* Find and validate the coff header
158
static int check_nt_hdr(struct nt_header *nt_hdr)
160
const char pe_sign[4] = {'P', 'E', 0, 0};
163
/* Validate the pe signature */
164
if (memcmp(pe_sign, nt_hdr->magic, sizeof(pe_sign)) != 0)
167
/* Make sure Image is PE32 */
168
if (nt_hdr->opt_hdr.opt_std_hdr.magic != COFF_MAGIC_PE32 &&
169
nt_hdr->opt_hdr.opt_std_hdr.magic != COFF_MAGIC_PE32PLUS)
172
if (nt_hdr->file_hdr.machine != COFF_MACHINE_I386 &&
173
nt_hdr->file_hdr.machine != COFF_MACHINE_AMD64) {
174
ERROR("driver for machine %x is not supported (yet)",
175
nt_hdr->file_hdr.machine);
179
/* Make sure this is executable image */
180
char_must = COFF_CHAR_IMAGE;
181
if ((nt_hdr->file_hdr.characteristics & char_must) != char_must)
184
/* Must be relocatable */
185
if ((nt_hdr->file_hdr.characteristics & COFF_CHAR_RELOCS_STRIPPED))
188
/* Make sure we have at least one section */
189
if (nt_hdr->file_hdr.num_sections <= 0)
192
if (nt_hdr->opt_hdr.opt_nt_hdr.section_alignment <
193
nt_hdr->opt_hdr.opt_nt_hdr.file_alignment) {
194
ERROR("Alignment mismatch: secion: 0x%x, file: 0x%x",
195
nt_hdr->opt_hdr.opt_nt_hdr.section_alignment,
196
nt_hdr->opt_hdr.opt_nt_hdr.file_alignment);
200
if ((nt_hdr->file_hdr.characteristics & COFF_CHAR_DLL))
201
return COFF_CHAR_DLL;
202
if ((nt_hdr->file_hdr.characteristics & COFF_CHAR_IMAGE))
203
return COFF_CHAR_IMAGE;
207
static int import(void *image, struct coffpe_import_dirent *dirent, char *dll)
209
ULONG_PTR *lookup_tbl, *address_tbl;
215
lookup_tbl = RVA2VA(image, dirent->import_lookup_tbl, ULONG_PTR *);
216
address_tbl = RVA2VA(image, dirent->import_address_table, ULONG_PTR *);
218
for (i = 0; lookup_tbl[i]; i++) {
219
if (lookup_tbl[i] & 0x80000000) {
220
ERROR("ordinal import not supported: %d",
221
(int) lookup_tbl[i]);
225
symname = RVA2VA(image,
226
((lookup_tbl[i] & 0x7fffffff) + 2),
230
adr = get_export(symname);
232
DBGTRACE1("found symbol: %s:%s, rva = %lu",
233
dll, symname, (unsigned long)address_tbl[i]);
235
ERROR("Unknown symbol: %s:%s", dll, symname);
238
DBGTRACE1("Importing rva: %p, %08X: %s : %s",
239
(void *)(address_tbl[i]), (UINT)adr, dll, symname);
240
address_tbl[i] = (ULONG_PTR)adr;
245
static int read_exports(void *image, struct nt_header *nt_hdr, char *dll)
247
struct section_header *export_section;
248
struct export_dir_table *export_dir_table;
249
uint32_t *export_addr_table;
251
uint32_t *name_table;
253
export_section = get_section(nt_hdr, ".edata");
255
DBGTRACE1("%s", "found exports section");
259
export_dir_table = (struct export_dir_table *)
260
(image + export_section->rawdata_addr);
261
name_table = (unsigned int *)(image + export_dir_table->name_addr_rva);
262
export_addr_table = (uint32_t *)
263
(image + export_dir_table->export_table_rva);
265
for (i = 0; i < export_dir_table->num_name_addr; i++) {
266
if (nt_hdr->opt_hdr.export_tbl.rva <= *export_addr_table ||
267
*export_addr_table >= (nt_hdr->opt_hdr.export_tbl.rva +
268
nt_hdr->opt_hdr.export_tbl.size))
269
DBGTRACE1("%s", "forwarder rva");
271
DBGTRACE1("export symbol: %s, at %p",
272
(char *)(image + *name_table),
273
(void *)(image + *export_addr_table));
275
exports[num_exports].dll = dll;
276
exports[num_exports].name = (char *)(image + *name_table);
277
exports[num_exports].addr = (ULONG_PTR)(image +
287
static int fixup_imports(void *image, struct nt_header *nt_hdr)
292
struct coffpe_import_dirent *dirent;
294
dirent = RVA2VA(image, nt_hdr->opt_hdr.import_tbl.rva,
295
struct coffpe_import_dirent *);
297
for (i = 0; dirent[i].name_rva; i++) {
298
name = RVA2VA(image, dirent[i].name_rva, char*);
300
//printk("Imports from dll: %s\n", name);
301
ret += import(image, &dirent[i], name);
306
static int fixup_reloc(void *image, struct nt_header *nt_hdr)
308
struct section_header *sect_hdr;
309
ULONG_PTR base = nt_hdr->opt_hdr.opt_nt_hdr.image_base;
311
struct coffpe_relocs *fixup_block;
313
sect_hdr = get_section(nt_hdr, ".reloc");
314
if (sect_hdr == NULL)
316
fixup_block = (struct coffpe_relocs *)(image + sect_hdr->rawdata_addr);
320
uint16_t fixup, offset;
322
size = (fixup_block->block_size - (2 * sizeof(uint32_t))) /
324
for (i = 0; i < size; i++) {
327
fixup = fixup_block->fixup[i];
328
offset = fixup & 0xfff;
329
loc = RVA2VA(image, fixup_block->page_rva + offset,
332
switch ((fixup >> 12) & 0x0f) {
333
case COFF_FIXUP_ABSOLUTE:
335
case COFF_FIXUP_HIGHLOW:
336
addr = RVA2VA(image, (*loc - base), uint32_t);
340
ERROR("unknown fixup: %08X", fixup);
345
fixup_block = (struct coffpe_relocs *)
346
((ULONG_PTR)fixup_block + fixup_block->block_size);
347
} while (fixup_block->block_size);
352
int load_pe_images(struct pe_image *pe_image, int n)
354
struct nt_header *nt_hdr;
359
struct optional_header *opt_hdr;
361
for (i = 0; i < n; i++) {
362
image = pe_image[i].image;
363
size = pe_image[i].size;
365
/* The PE header is found at the RVA specified at offset 3c. */
368
nt_hdr_offset = *(unsigned int *)(image+0x3c);
369
nt_hdr = (struct nt_header *)((char *)image + nt_hdr_offset);
370
pe_image[i].type = check_nt_hdr(nt_hdr);
371
if (pe_image[i].type <= 0)
374
if (read_exports(image, nt_hdr, pe_image[i].name))
378
for (i = 0; i < n; i++) {
379
image = pe_image[i].image;
380
size = pe_image[i].size;
382
nt_hdr_offset = *(UINT *)(image+0x3c);
383
nt_hdr = (struct nt_header *)((char *)image + nt_hdr_offset);
384
opt_hdr = &nt_hdr->opt_hdr;
386
if (fixup_reloc(image, nt_hdr))
388
if (fixup_imports(image, nt_hdr))
390
flush_icache_range(image, pe_image[i].size);
392
pe_image[i].entry = RVA2VA(image,
393
opt_hdr->opt_std_hdr.entry_rva,
395
DBGTRACE1("entry is at %p, rva at %08X", pe_image[i].entry,
396
(unsigned int)opt_hdr->opt_std_hdr.entry_rva);
397
} for (i = 0; i < n; i++) {
398
image = pe_image[i].image;
399
size = pe_image[i].size;
401
nt_hdr_offset = *(UINT *)(image+0x3c);
402
nt_hdr = (struct nt_header *)((char *)image + nt_hdr_offset);
403
opt_hdr = &nt_hdr->opt_hdr;
405
if (pe_image[i].type == COFF_CHAR_DLL) {
406
struct ustring ustring;
407
char *buf = "0\0t0m0p00";
408
int (*dll_entry)(struct ustring *ustring) STDCALL;
410
memset(&ustring, 0, sizeof(ustring));
412
dll_entry = (void *)get_dll_init(pe_image[i].name);
414
DBGTRACE1("calling dll_init at %p", dll_entry);
415
if (!dll_entry || dll_entry(&ustring))
416
ERROR("DLL initialize failed for %s",
419
else if (pe_image[i].type == COFF_CHAR_IMAGE)
422
ERROR("illegal image type: %d", pe_image[i].type);