PIMAGE_NT_HEADERS32 yr_get_pe_header( const uint8_t* buffer, size_t buffer_length) { PIMAGE_DOS_HEADER mz_header; PIMAGE_NT_HEADERS32 pe_header; size_t headers_size = 0; if (buffer_length < sizeof(IMAGE_DOS_HEADER)) return NULL; mz_header = (PIMAGE_DOS_HEADER) buffer; if (yr_le16toh(mz_header->e_magic) != IMAGE_DOS_SIGNATURE) return NULL; if ((int32_t) yr_le32toh(mz_header->e_lfanew) < 0) return NULL; headers_size = yr_le32toh(mz_header->e_lfanew) + \ sizeof(pe_header->Signature) + \ sizeof(IMAGE_FILE_HEADER); if (buffer_length < headers_size) return NULL; pe_header = (PIMAGE_NT_HEADERS32) (buffer + yr_le32toh(mz_header->e_lfanew)); headers_size += sizeof(IMAGE_OPTIONAL_HEADER32); if (yr_le32toh(pe_header->Signature) == IMAGE_NT_SIGNATURE && (yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_I386 || yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_AMD64) && buffer_length > headers_size) { return pe_header; } else { return NULL; } }
uint64_t yr_pe_rva_to_offset( PIMAGE_NT_HEADERS32 pe_header, uint64_t rva, size_t buffer_length) { int i = 0; PIMAGE_SECTION_HEADER section; DWORD section_rva; DWORD section_offset; section = IMAGE_FIRST_SECTION(pe_header); section_rva = 0; section_offset = 0; while(i < MIN(yr_le16toh(pe_header->FileHeader.NumberOfSections), 60)) { if ((uint8_t*) section - \ (uint8_t*) pe_header + sizeof(IMAGE_SECTION_HEADER) < buffer_length) { if (rva >= section->VirtualAddress && section_rva <= yr_le32toh(section->VirtualAddress)) { section_rva = yr_le32toh(section->VirtualAddress); section_offset = yr_le32toh(section->PointerToRawData); } section++; i++; } else { return 0; } } return section_offset + (rva - section_rva); }
PIMAGE_NT_HEADERS32 pe_get_header( uint8_t* data, size_t data_size) { PIMAGE_DOS_HEADER mz_header; PIMAGE_NT_HEADERS32 pe_header; size_t headers_size = 0; if (data_size < sizeof(IMAGE_DOS_HEADER)) return NULL; mz_header = (PIMAGE_DOS_HEADER) data; if (yr_le16toh(mz_header->e_magic) != IMAGE_DOS_SIGNATURE) return NULL; if (yr_le32toh(mz_header->e_lfanew) < 0) return NULL; headers_size = yr_le32toh(mz_header->e_lfanew) + \ sizeof(pe_header->Signature) + \ sizeof(IMAGE_FILE_HEADER); if (data_size < headers_size) return NULL; pe_header = (PIMAGE_NT_HEADERS32) (data + yr_le32toh(mz_header->e_lfanew)); headers_size += yr_le16toh(pe_header->FileHeader.SizeOfOptionalHeader); if (yr_le32toh(pe_header->Signature) == IMAGE_NT_SIGNATURE && (yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_UNKNOWN || yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_AM33 || yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_AMD64 || yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_ARM || yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_ARMNT || yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_ARM64 || yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_EBC || yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_I386 || yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_IA64 || yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_M32R || yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_MIPS16 || yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_MIPSFPU || yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_MIPSFPU16 || yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_POWERPC || yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_POWERPCFP || yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_R4000 || yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_SH3 || yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_SH3DSP || yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_SH4 || yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_SH5 || yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_THUMB || yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_WCEMIPSV2) && data_size > headers_size) { return pe_header; } else { return NULL; } }
static uint64_t yr_elf_rva_to_offset_64( elf64_header_t* elf_header, uint64_t rva, size_t buffer_length) { // if the binary is an executable then prefer the program headers to resolve // the offset if (yr_le16toh(elf_header->type) == ELF_ET_EXEC) { int i; elf64_program_header_t* program; if (yr_le64toh(elf_header->ph_offset) == 0 || yr_le16toh(elf_header->ph_entry_count == 0)) return 0; // check that 'ph_offset' doesn't wrap when added to the // size of entries. if(ULONG_MAX - yr_le64toh(elf_header->ph_offset) < sizeof(elf64_program_header_t) * yr_le16toh(elf_header->ph_entry_count)) return 0; // ensure we don't exceed the buffer size if (yr_le64toh(elf_header->ph_offset) + sizeof(elf64_program_header_t) * yr_le16toh(elf_header->ph_entry_count) > buffer_length) return 0; program = (elf64_program_header_t*) ((uint8_t*) elf_header + yr_le64toh(elf_header->ph_offset)); for (i = 0; i < yr_le16toh(elf_header->ph_entry_count); i++) { if (rva >= yr_le64toh(program->virt_addr) && rva < yr_le64toh(program->virt_addr) + yr_le64toh(program->mem_size)) { return yr_le64toh(program->offset) + (rva - yr_le64toh(program->virt_addr)); } program++; } } else { int i; elf64_section_header_t* section; if (yr_le64toh(elf_header->sh_offset) == 0 || yr_le16toh(elf_header->sh_entry_count) == 0) return 0; // check that 'sh_offset' doesn't wrap when added to the // size of entries. if(ULONG_MAX - yr_le64toh(elf_header->sh_offset) < sizeof(elf64_section_header_t) * yr_le16toh(elf_header->sh_entry_count)) return 0; if (yr_le64toh(elf_header->sh_offset) + sizeof(elf64_section_header_t) * yr_le16toh(elf_header->sh_entry_count) > buffer_length) return 0; section = (elf64_section_header_t*) ((uint8_t*) elf_header + yr_le64toh(elf_header->sh_offset)); for (i = 0; i < yr_le16toh(elf_header->sh_entry_count); i++) { if (yr_le32toh(section->type) != ELF_SHT_NULL && yr_le32toh(section->type) != ELF_SHT_NOBITS && rva >= yr_le64toh(section->addr) && rva < yr_le64toh(section->addr) + yr_le64toh(section->size)) { return yr_le64toh(section->offset) + (rva - yr_le64toh(section->addr)); } section++; } } return 0; }
int64_t pe_rva_to_offset( PE* pe, uint64_t rva) { PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pe->header); DWORD lowest_section_rva = 0xffffffff; DWORD section_rva = 0; DWORD section_offset = 0; DWORD section_raw_size = 0; int64_t result; int i = 0; int alignment = 0; int rest = 0; while(i < yr_min(yr_le16toh(pe->header->FileHeader.NumberOfSections), MAX_PE_SECTIONS)) { if (struct_fits_in_pe(pe, section, IMAGE_SECTION_HEADER)) { if (lowest_section_rva > yr_le32toh(section->VirtualAddress)) { lowest_section_rva = yr_le32toh(section->VirtualAddress); } if (rva >= yr_le32toh(section->VirtualAddress) && section_rva <= yr_le32toh(section->VirtualAddress)) { // Round section_offset // // Rounding everything less than 0x200 to 0 as discussed in // https://code.google.com/archive/p/corkami/wikis/PE.wiki#PointerToRawData // does not work for PE32_FILE from the test suite and for // some tinype samples where File Alignment = 4 // (http://www.phreedom.org/research/tinype/). // // If FileAlignment is >= 0x200, it is apparently ignored (see // Ero Carreras's pefile.py, PE.adjust_FileAlignment). alignment = yr_min(yr_le32toh(OptionalHeader(pe, FileAlignment)), 0x200); section_rva = yr_le32toh(section->VirtualAddress); section_offset = yr_le32toh(section->PointerToRawData); section_raw_size = yr_le32toh(section->SizeOfRawData); if (alignment) { rest = section_offset % alignment; if (rest) section_offset -= rest; } } section++; i++; } else { return -1; } } // Everything before the first section seems to get mapped straight // relative to ImageBase. if (rva < lowest_section_rva) { section_rva = 0; section_offset = 0; section_raw_size = (DWORD) pe->data_size; } // Many sections, have a raw (on disk) size smaller than their in-memory size. // Check for rva's that map to this sparse space, and therefore have no valid // associated file offset. if ((rva - section_rva) >= section_raw_size) return -1; result = section_offset + (rva - section_rva); // Check that the offset fits within the file. if (result >= pe->data_size) return -1; return result; }