📄 pe_linker.c
字号:
/* * Copyright (C) 2003-2005 Pontus Fuchs, Giridhar Pemmasani * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */#ifdef TEST_LOADER#include "usr_linker.h"#else#include <linux/types.h>#include <asm/errno.h>//#define DEBUGLINKER 2#include "ntoskernel.h"#endifstruct pe_exports { char *dll; char *name; generic_func addr;};static struct pe_exports pe_exports[40];static int num_pe_exports;#if defined(CONFIG_X86_64)extern struct kuser_shared_data kuser_shared_data;#endif#define RVA2VA(image, rva, type) (type)(ULONG_PTR)((void *)image + rva)#define CHECK_SZ(a,b) { if (sizeof(a) != b) { \ ERROR("%s is bad, got %zd, expected %d", \ #a , sizeof(a), (b)); return -EINVAL; } }#if defined(DEBUGLINKER) && DEBUGLINKER > 0#define DBGLINKER(fmt, ...) printk(KERN_INFO "%s (%s:%d): " fmt "\n", \ DRIVER_NAME, __FUNCTION__, \ __LINE__ , ## __VA_ARGS__);static const char *image_directory_name[] = { "EXPORT", "IMPORT", "RESOURCE", "EXCEPTION", "SECURITY", "BASERELOC", "DEBUG", "COPYRIGHT", "GLOBALPTR", "TLS", "LOAD_CONFIG", "BOUND_IMPORT", "IAT", "DELAY_IMPORT", "COM_DESCRIPTOR" };#else#define DBGLINKER(fmt, ...) do { } while (0)#endif#ifndef TEST_LOADERextern struct wrap_export ntoskernel_exports[], ntoskernel_io_exports[], ndis_exports[], crt_exports[], hal_exports[], rtl_exports[];#ifdef CONFIG_USBextern struct wrap_export usb_exports[];#endifstatic char *get_export(char *name){ int i; for (i = 0 ; ntoskernel_exports[i].name != NULL; i++) if (strcmp(ntoskernel_exports[i].name, name) == 0) return (char *)ntoskernel_exports[i].func; for (i = 0 ; ntoskernel_io_exports[i].name != NULL; i++) if (strcmp(ntoskernel_io_exports[i].name, name) == 0) return (char *)ntoskernel_io_exports[i].func; for (i = 0 ; ndis_exports[i].name != NULL; i++) if (strcmp(ndis_exports[i].name, name) == 0) return (char *)ndis_exports[i].func; for (i = 0 ; crt_exports[i].name != NULL; i++) if (strcmp(crt_exports[i].name, name) == 0) return (char *)crt_exports[i].func; for (i = 0 ; hal_exports[i].name != NULL; i++) if (strcmp(hal_exports[i].name, name) == 0) return (char *)hal_exports[i].func; for (i = 0 ; rtl_exports[i].name != NULL; i++) if (strcmp(rtl_exports[i].name, name) == 0) return (char *)rtl_exports[i].func;#ifdef CONFIG_USB for (i = 0 ; usb_exports[i].name != NULL; i++) if (strcmp(usb_exports[i].name, name) == 0) return (char *)usb_exports[i].func;#endif for (i = 0; i < num_pe_exports; i++) if (strcmp(pe_exports[i].name, name) == 0) return (char *)pe_exports[i].addr; return NULL;}#endif // TEST_LOADERstatic void *get_dll_init(char *name){ int i; for (i = 0; i < num_pe_exports; i++) if ((strcmp(pe_exports[i].dll, name) == 0) && (strcmp(pe_exports[i].name, "DllInitialize") == 0)) return (void *)pe_exports[i].addr; return NULL;}/* * Find and validate the coff header * */static int check_nt_hdr(IMAGE_NT_HEADERS *nt_hdr){ int i; WORD attr; PIMAGE_OPTIONAL_HEADER opt_hdr; /* Validate the "PE\0\0" signature */ if (nt_hdr->Signature != IMAGE_NT_SIGNATURE) { ERROR("is this driver file? bad signature %08x", nt_hdr->Signature); return -EINVAL; } opt_hdr = &nt_hdr->OptionalHeader; /* Make sure Image is PE32 or PE32+ */#ifdef CONFIG_X86_64 if (opt_hdr->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) { ERROR("kernel is 64-bit, but Windows driver is not 64-bit;" "bad magic: %04X", opt_hdr->Magic); return -EINVAL; }#else if (opt_hdr->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ERROR("kernel is 32-bit, but Windows driver is not 32-bit;" "bad magic: %04X", opt_hdr->Magic); return -EINVAL; }#endif /* Validate the image for the current architecture. */#ifdef CONFIG_X86_64 if (nt_hdr->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) { ERROR("kernel is 64-bit, but Windows driver is not 64-bit;" " (PE signature is %04X)", nt_hdr->FileHeader.Machine); return -EINVAL; }#else if (nt_hdr->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) { ERROR("kernel is 32-bit, but Windows driver is not 32-bit;" " (PE signature is %04X)", nt_hdr->FileHeader.Machine); return -EINVAL; }#endif /* Must have attributes */#ifdef CONFIG_X86_64 attr = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LARGE_ADDRESS_AWARE;#else attr = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_32BIT_MACHINE;#endif if ((nt_hdr->FileHeader.Characteristics & attr) != attr) return -EINVAL; /* Must be relocatable */ attr = IMAGE_FILE_RELOCS_STRIPPED; if ((nt_hdr->FileHeader.Characteristics & attr)) return -EINVAL; /* Make sure we have at least one section */ if (nt_hdr->FileHeader.NumberOfSections == 0) return -EINVAL; if (opt_hdr->SectionAlignment < opt_hdr->FileAlignment) { ERROR("alignment mismatch: secion: 0x%x, file: 0x%x", opt_hdr->SectionAlignment, opt_hdr->FileAlignment); return -EINVAL; } DBGLINKER("number of datadictionary entries %d", opt_hdr->NumberOfRvaAndSizes); for (i = 0; i < opt_hdr->NumberOfRvaAndSizes; i++) { DBGLINKER("datadirectory %s RVA:%X Size:%d", (i<=IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)? image_directory_name[i] : "unknown", opt_hdr->DataDirectory[i].VirtualAddress, opt_hdr->DataDirectory[i].Size); } if ((nt_hdr->FileHeader.Characteristics & IMAGE_FILE_DLL)) return IMAGE_FILE_DLL; if ((nt_hdr->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)) return IMAGE_FILE_EXECUTABLE_IMAGE; return -EINVAL;}static int import(void *image, IMAGE_IMPORT_DESCRIPTOR *dirent, char *dll){ ULONG_PTR *lookup_tbl, *address_tbl; char *symname = NULL; int i; int ret = 0; void *adr; lookup_tbl = RVA2VA(image, dirent->u.OriginalFirstThunk, ULONG_PTR *); address_tbl = RVA2VA(image, dirent->FirstThunk, ULONG_PTR *); for (i = 0; lookup_tbl[i]; i++) { if (IMAGE_SNAP_BY_ORDINAL(lookup_tbl[i])) { ERROR("ordinal import not supported: %Lu", (uint64_t)lookup_tbl[i]); return -1; } else { symname = RVA2VA(image, ((lookup_tbl[i] & ~IMAGE_ORDINAL_FLAG) + 2), char *); } adr = get_export(symname); if (adr == NULL) { ERROR("unknown symbol: %s:'%s'", dll, symname); ret = -1; } else { DBGLINKER("found symbol: %s:%s: addr: %p, rva = %Lu", dll, symname, adr, (uint64_t)address_tbl[i]); address_tbl[i] = (ULONG_PTR)adr; } } return ret;}static int read_exports(struct pe_image *pe){ IMAGE_EXPORT_DIRECTORY *export_dir_table; uint32_t *export_addr_table; int i; uint32_t *name_table; PIMAGE_OPTIONAL_HEADER opt_hdr; IMAGE_DATA_DIRECTORY *export_data_dir; opt_hdr = &pe->nt_hdr->OptionalHeader; export_data_dir = &opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; if (export_data_dir->Size == 0) { DBGLINKER("no exports"); return 0; } export_dir_table = RVA2VA(pe->image, export_data_dir->VirtualAddress, IMAGE_EXPORT_DIRECTORY *); name_table = (unsigned int *)(pe->image + export_dir_table->AddressOfNames); export_addr_table = (uint32_t *) (pe->image + export_dir_table->AddressOfFunctions); for (i = 0; i < export_dir_table->NumberOfNames; i++) { if (export_data_dir->VirtualAddress <= *export_addr_table || *export_addr_table >= (export_data_dir->VirtualAddress + export_data_dir->Size)) DBGLINKER("forwarder rva"); DBGLINKER("export symbol: %s, at %p", (char *)(pe->image + *name_table), pe->image + *export_addr_table); pe_exports[num_pe_exports].dll = pe->name; pe_exports[num_pe_exports].name = pe->image + *name_table; pe_exports[num_pe_exports].addr = pe->image + *export_addr_table; num_pe_exports++; name_table++; export_addr_table++; } return 0;}static int fixup_imports(void *image, IMAGE_NT_HEADERS *nt_hdr)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -