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; }
void pe_parse( PE* pe, size_t base_address, int flags) { PIMAGE_SECTION_HEADER section; char section_name[IMAGE_SIZEOF_SHORT_NAME + 1]; #define OptionalHeader(field) \ (pe->header->FileHeader.Machine == 0x8664 ? \ ((PIMAGE_NT_HEADERS64) pe->header)->OptionalHeader.field : \ pe->header->OptionalHeader.field) set_integer( pe->header->FileHeader.Machine, pe->object, "machine"); set_integer( pe->header->FileHeader.NumberOfSections, pe->object, "number_of_sections"); set_integer( pe->header->FileHeader.TimeDateStamp, pe->object, "timestamp"); set_integer( pe->header->FileHeader.Characteristics, pe->object, "characteristics"); set_integer( flags & SCAN_FLAGS_PROCESS_MEMORY ? base_address + OptionalHeader(AddressOfEntryPoint) : pe_rva_to_offset(pe, OptionalHeader(AddressOfEntryPoint)), pe->object, "entry_point"); set_integer( OptionalHeader(ImageBase), pe->object, "image_base"); set_integer( OptionalHeader(MajorLinkerVersion), pe->object, "linker_version.major"); set_integer( OptionalHeader(MinorLinkerVersion), pe->object, "linker_version.minor"); set_integer( OptionalHeader(MajorOperatingSystemVersion), pe->object, "os_version.major"); set_integer( OptionalHeader(MinorOperatingSystemVersion), pe->object, "os_version.minor"); set_integer( OptionalHeader(MajorImageVersion), pe->object, "image_version.major"); set_integer( OptionalHeader(MinorImageVersion), pe->object, "image_version.minor"); set_integer( OptionalHeader(MajorSubsystemVersion), pe->object, "subsystem_version.major"); set_integer( OptionalHeader(MinorSubsystemVersion), pe->object, "subsystem_version.minor"); set_integer( OptionalHeader(Subsystem), pe->object, "subsystem"); pe_iterate_resources( pe, (RESOURCE_CALLBACK_FUNC) pe_find_version_info_cb, (void*) pe); section = IMAGE_FIRST_SECTION(pe); int scount = min(pe->header->FileHeader.NumberOfSections, MAX_PE_SECTIONS); for (int i = 0; i < scount; i++) { if ((uint8_t*) section - (uint8_t*) pe + sizeof(IMAGE_SECTION_HEADER) >= pe->data_size) { break; } strlcpy(section_name, (char*) section->Name, IMAGE_SIZEOF_SHORT_NAME + 1); set_string( section_name, pe->object, "sections[%i].name", i); set_integer( section->Characteristics, pe->object, "sections[%i].characteristics", i); set_integer(section->SizeOfRawData, pe->object, "sections[%i].raw_data_size", i); set_integer(section->PointerToRawData, pe->object, "sections[%i].raw_data_offset", i); set_integer(section->VirtualAddress, pe->object, "sections[%i].virtual_address", i); set_integer( section->Misc.VirtualSize, pe->object, "sections[%i].virtual_size", i); section++; } }
bool FindProtectorSection(types::simple_ptr<unsigned char> ImgBase, ProtectorSectionInfo & info) { // if the section is already found? for(UINT x = 0; x<ProtectorSections.size(); x++) { if (ProtectorSections[x].ImgBase == ImgBase) { if (ProtectorSections[x].pProtectorSection != NULL) { info = ProtectorSections[x]; return true; } return false; // caller section is found, but the .ipn1 section is not. the caller assembly is not protected } } // if not - find the section types::simple_ptr<IMAGE_DOS_HEADER> DosHeader(reinterpret_cast<IMAGE_DOS_HEADER*>((unsigned char*)ImgBase)); types::simple_ptr<IMAGE_FILE_HEADER> FileHeader(reinterpret_cast<IMAGE_FILE_HEADER*>(ImgBase + DosHeader->e_lfanew + sizeof(IMAGE_NT_SIGNATURE))); types::simple_ptr<IMAGE_OPTIONAL_HEADER> OptionalHeader(reinterpret_cast<IMAGE_OPTIONAL_HEADER*>(ImgBase + sizeof(IMAGE_FILE_HEADER))); types::simple_ptr<unsigned char> SectHeadersOffset(ImgBase + DosHeader->e_lfanew + sizeof(IMAGE_NT_SIGNATURE) + sizeof (IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER)); types::simple_ptr<unsigned char> SectionHeaderStart; types::simple_ptr<IMAGE_SECTION_HEADER> SectionHeader; for(unsigned short i = 0; i < FileHeader->NumberOfSections; i++ ) { SectionHeaderStart = types::simple_ptr<unsigned char> (SectHeadersOffset + i * sizeof(IMAGE_SECTION_HEADER)); SectionHeader = reinterpret_cast<IMAGE_SECTION_HEADER*>((unsigned char*)SectionHeaderStart); if (strcmp(const_cast<const char*>(reinterpret_cast<char*>(&SectionHeader->Name[0])), ".ipn1") == 0) { info.ImgBase = ImgBase; info.pProtectorSection = reinterpret_cast<unsigned char*>(SectionHeader->VirtualAddress); types::simple_ptr<unsigned char> position(SectionHeader->VirtualAddress + ImgBase); ReadProtectorSectionData(position, info); // Move the offset according to the RVA not the physical offset // 1. Find the correct section for the physical offset for(unsigned int j =0; j < FileHeader->NumberOfSections; j++) { SectionHeaderStart = types::simple_ptr<unsigned char>(SectHeadersOffset + j * sizeof(IMAGE_SECTION_HEADER)); SectionHeader = types::simple_ptr<IMAGE_SECTION_HEADER>(reinterpret_cast<IMAGE_SECTION_HEADER*>((unsigned char*)SectionHeaderStart)); if ((SectionHeader->PointerToRawData < info.w32HookCoreNameOffset) && (info.w32HookCoreNameOffset < SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData )) { // 2. Section found. update references unsigned int w32SectionStartRva = info.w32HookCoreNameOffset - SectionHeader->PointerToRawData; unsigned int x64SectionStartRva = info.x64HookCoreNameOffset - SectionHeader->PointerToRawData; // 3. Set the offset from the ImageBase with taking into account section virtual address info.w32HookCoreNameOffset = (unsigned int)(SectionHeader->VirtualAddress + w32SectionStartRva); info.x64HookCoreNameOffset = (unsigned int)(SectionHeader->VirtualAddress + x64SectionStartRva); break; } } return true; } } info.ImgBase = ImgBase; return false; }