📄 pe_linker.c
字号:
int ret = 0; IMAGE_IMPORT_DESCRIPTOR *dirent; IMAGE_DATA_DIRECTORY *import_data_dir; PIMAGE_OPTIONAL_HEADER opt_hdr; opt_hdr = &nt_hdr->OptionalHeader; import_data_dir = &opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; dirent = RVA2VA(image, import_data_dir->VirtualAddress, IMAGE_IMPORT_DESCRIPTOR *); for (i = 0; dirent[i].Name; i++) { name = RVA2VA(image, dirent[i].Name, char*); DBGLINKER("imports from dll: %s", name); ret += import(image, &dirent[i], name); } return ret;}static int fixup_reloc(void *image, IMAGE_NT_HEADERS *nt_hdr){ ULONG_PTR base; ULONG_PTR size; IMAGE_BASE_RELOCATION *fixup_block; IMAGE_DATA_DIRECTORY *base_reloc_data_dir; PIMAGE_OPTIONAL_HEADER opt_hdr; opt_hdr = &nt_hdr->OptionalHeader; base = opt_hdr->ImageBase; base_reloc_data_dir = &opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; if (base_reloc_data_dir->Size == 0) return 0; fixup_block = RVA2VA(image, base_reloc_data_dir->VirtualAddress, IMAGE_BASE_RELOCATION *); DBGLINKER("fixup_block=%p, image=%p", fixup_block, image); DBGLINKER("fixup_block info: %x %d", fixup_block->VirtualAddress, fixup_block->SizeOfBlock); while (fixup_block->SizeOfBlock) { int i; WORD fixup, offset; size = (fixup_block->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD); DBGLINKER("found %Lu relocations in this block", (uint64_t)size); for (i = 0; i < size; i++) { fixup = fixup_block->TypeOffset[i]; offset = fixup & 0xfff; switch ((fixup >> 12) & 0x0f) { case IMAGE_REL_BASED_ABSOLUTE: break; case IMAGE_REL_BASED_HIGHLOW: { uint32_t addr; uint32_t *loc = RVA2VA(image, fixup_block->VirtualAddress + offset, uint32_t *); addr = RVA2VA(image, (*loc - base), uint32_t); DBGLINKER("relocation: *%p (Val:%X)= %X", loc, *loc, addr); *loc = addr; } break; case IMAGE_REL_BASED_DIR64: { uint64_t addr; uint64_t *loc = RVA2VA(image, fixup_block->VirtualAddress + offset, uint64_t *); addr = RVA2VA(image, (*loc - base), uint64_t); DBGLINKER("relocation: *%p (Val:%llX)= %llx", loc, *loc, addr); *loc = addr; } break; default: ERROR("unknown fixup: %08X", (fixup >> 12) & 0x0f); return -EOPNOTSUPP; break; } } DBGLINKER("finished relocating block"); fixup_block = (IMAGE_BASE_RELOCATION *) ((void *)fixup_block + fixup_block->SizeOfBlock); }; DBGLINKER("done relocating all"); return 0;}/* Expand the image in memroy if necessary. The image on disk does not * necessarily maps the image of the driver in memory, so we have to * re-write it in order to fullfill the sections alignements. The * advantage to do that is that rva_to_va becomes a simple * addition. */static int fix_pe_image(struct pe_image *pe){ void *image; IMAGE_SECTION_HEADER *sect_hdr; int i, sections; int image_size; if (pe->size == pe->opt_hdr->SizeOfImage) { /* Nothing to do */ return 0; } image_size = pe->opt_hdr->SizeOfImage;#ifdef CONFIG_X86_64#ifdef PAGE_KERNEL_EXECUTABLE image = __vmalloc(image_size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXECUTABLE);#elif defined PAGE_KERNEL_EXEC image = __vmalloc(image_size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC);#else#error x86_64 should have either PAGE_KERNEL_EXECUTABLE or PAGE_KERNEL_EXEC#endif#else#ifdef cpu_has_nx /* hate to play with kernel macros, but PAGE_KERNEL_EXEC is * not available to modules! */ if (cpu_has_nx) image = __vmalloc(image_size, GFP_KERNEL | __GFP_HIGHMEM, __pgprot(__PAGE_KERNEL & ~_PAGE_NX)); else image = vmalloc(image_size);#else image = vmalloc(image_size);#endif#endif if (image == NULL) { ERROR("failed to allocate enough space for new image:" " %d bytes", image_size); return -ENOMEM; } /* Copy all the headers, ie everything before the first section. */ sections = pe->nt_hdr->FileHeader.NumberOfSections; sect_hdr = IMAGE_FIRST_SECTION(pe->nt_hdr); DBGLINKER("copying headers: %u bytes", sect_hdr->PointerToRawData); memcpy(image, pe->image, sect_hdr->PointerToRawData); /* Copy all the sections */ for (i = 0; i < sections; i++) { DBGLINKER("Copy section %s from %x to %x", sect_hdr->Name, sect_hdr->PointerToRawData, sect_hdr->VirtualAddress); if (sect_hdr->VirtualAddress+sect_hdr->SizeOfRawData > image_size) { ERROR("Invalid section %s in driver", sect_hdr->Name); vfree(image); return -EINVAL; } memcpy(image+sect_hdr->VirtualAddress, pe->image + sect_hdr->PointerToRawData, sect_hdr->SizeOfRawData); sect_hdr++; } vfree(pe->image); pe->image = image; pe->size = image_size; /* Update our internal pointers */ pe->nt_hdr = (IMAGE_NT_HEADERS *) (pe->image + ((IMAGE_DOS_HEADER *)pe->image)->e_lfanew); pe->opt_hdr = &pe->nt_hdr->OptionalHeader; DBGLINKER("set nt headers: nt_hdr=%p, opt_hdr=%p, image=%p", pe->nt_hdr, pe->opt_hdr, pe->image); return 0;}#if defined(CONFIG_X86_64)extern struct kuser_shared_data kuser_shared_data;void fix_user_shared_data_addr(char *driver, unsigned long length){ unsigned long i, n, max_addr, *addr; n = length - sizeof(unsigned long); max_addr = KI_USER_SHARED_DATA + sizeof(kuser_shared_data); for (i = 0; i < n; i++) { addr = (unsigned long *)(driver + i); if (*addr >= KI_USER_SHARED_DATA && *addr < max_addr) { *addr -= KI_USER_SHARED_DATA; *addr += (unsigned long)&kuser_shared_data; kuser_shared_data.reserved1 = 1; } }}#endifint link_pe_images(struct pe_image *pe_image, unsigned short n){ int i; struct pe_image *pe;#ifdef DEBUG /* Sanity checkings */ CHECK_SZ(IMAGE_SECTION_HEADER, IMAGE_SIZEOF_SECTION_HEADER); CHECK_SZ(IMAGE_FILE_HEADER, IMAGE_SIZEOF_FILE_HEADER); CHECK_SZ(IMAGE_OPTIONAL_HEADER, IMAGE_SIZEOF_NT_OPTIONAL_HEADER); CHECK_SZ(IMAGE_NT_HEADERS, 4 + IMAGE_SIZEOF_FILE_HEADER + IMAGE_SIZEOF_NT_OPTIONAL_HEADER); CHECK_SZ(IMAGE_DOS_HEADER, 0x40); CHECK_SZ(IMAGE_EXPORT_DIRECTORY, 40); CHECK_SZ(IMAGE_BASE_RELOCATION, 8); CHECK_SZ(IMAGE_IMPORT_DESCRIPTOR, 20);#endif for (i = 0; i < n; i++) { IMAGE_DOS_HEADER *dos_hdr; pe = &pe_image[i]; dos_hdr = pe->image; if (pe->size < sizeof(IMAGE_DOS_HEADER)) { TRACE1("image too small: %d", pe->size); return -EINVAL; } pe->nt_hdr = (IMAGE_NT_HEADERS *)(pe->image + dos_hdr->e_lfanew); pe->opt_hdr = &pe->nt_hdr->OptionalHeader; pe->type = check_nt_hdr(pe->nt_hdr); if (pe->type <= 0) { TRACE1("type <= 0"); return -EINVAL; } if (fix_pe_image(pe)) { TRACE1("bad PE image"); return -EINVAL; } if (read_exports(pe)) { TRACE1("read exports failed"); return -EINVAL; } } for (i = 0; i < n; i++) { pe = &pe_image[i]; if (fixup_reloc(pe->image, pe->nt_hdr)) { TRACE1("fixup reloc failed"); return -EINVAL; } if (fixup_imports(pe->image, pe->nt_hdr)) { TRACE1("fixup imports failed"); return -EINVAL; }#if defined(CONFIG_X86_64) INFO("fixing KI_USER_SHARED_DATA address in the driver"); fix_user_shared_data_addr(pe_image[i].image, pe_image[i].size);#endif flush_icache_range(pe->image, pe->size); pe->entry = RVA2VA(pe->image, pe->opt_hdr->AddressOfEntryPoint, void *); TRACE1("entry is at %p, rva at %08X", pe->entry, pe->opt_hdr->AddressOfEntryPoint); } for (i = 0; i < n; i++) { pe = &pe_image[i]; if (pe->type == IMAGE_FILE_DLL) { struct unicode_string ustring; char *buf = "0/0t0m0p00"; int (*dll_entry)(struct unicode_string *ustring) wstdcall; memset(&ustring, 0, sizeof(ustring)); ustring.buf = (wchar_t *)buf; dll_entry = (void *)get_dll_init(pe->name); TRACE1("calling dll_init at %p", dll_entry); if (!dll_entry || dll_entry(&ustring)) ERROR("DLL initialize failed for %s", pe->name); } else if (pe->type != IMAGE_FILE_EXECUTABLE_IMAGE) ERROR("illegal image type: %d", pe->type); } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -