static int fixup_reloc(void *image, struct nt_header *nt_hdr) { struct section_header *sect_hdr; int base = nt_hdr->opt_hdr.opt_nt_hdr.image_base; int size; struct coffpe_relocs *fixup_block; sect_hdr = get_section(nt_hdr, ".reloc"); if (sect_hdr == NULL) return -EINVAL; fixup_block = (struct coffpe_relocs *)(image + sect_hdr->rawdata_addr); do { int i; uint16_t fixup, offset; size = (fixup_block->block_size - (2 * sizeof(uint32_t))) / sizeof(uint16_t); for (i = 0; i < size; i++) { uint32_t *loc; uint32_t addr; fixup = fixup_block->fixup[i]; offset = fixup & 0xfff; loc = RVA2VA(image, fixup_block->page_rva + offset, uint32_t *); switch ((fixup >> 12) & 0x0f) { case COFF_FIXUP_ABSOLUTE: break; case COFF_FIXUP_HIGHLOW: addr = RVA2VA(image, (*loc - base), uint32_t); *loc = addr; break; default: ERROR("unknown fixup: %08X", fixup); return -EOPNOTSUPP; break; } } fixup_block = (struct coffpe_relocs *) ((size_t)fixup_block + fixup_block->block_size); } while (fixup_block->block_size); return 0; }
LPVOID search_exp(LPVOID base, DWORD hash) { PIMAGE_DOS_HEADER dos; PIMAGE_NT_HEADERS nt; DWORD cnt, rva, dll_h; PIMAGE_DATA_DIRECTORY dir; PIMAGE_EXPORT_DIRECTORY exp; PDWORD adr; PDWORD sym; PWORD ord; PCHAR api, dll; LPVOID api_adr=NULL; dos = (PIMAGE_DOS_HEADER)base; nt = RVA2VA(PIMAGE_NT_HEADERS, base, dos->e_lfanew); dir = (PIMAGE_DATA_DIRECTORY)nt->OptionalHeader.DataDirectory; rva = dir[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; // if no export table, return NULL if (rva==0) return NULL; exp = (PIMAGE_EXPORT_DIRECTORY) RVA2VA(ULONG_PTR, base, rva); cnt = exp->NumberOfNames; // if no api names, return NULL if (cnt==0) return NULL; adr = RVA2VA(PDWORD,base, exp->AddressOfFunctions); sym = RVA2VA(PDWORD,base, exp->AddressOfNames); ord = RVA2VA(PWORD, base, exp->AddressOfNameOrdinals); do { // calculate hash of api string api = RVA2VA(PCHAR, base, sym[cnt-1]); // add to DLL hash and compare if (crc32c(api) + dll_h == hash) { // return address of function api_adr = RVA2VA(LPVOID, base, adr[ord[cnt-1]]); return api_adr; } } while (--cnt && api_adr==0); return api_adr; }
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; }