def lowerToBottom(self): selectedItems = self.mMapScene.selectedObjectItems() objectGroup = RaiseLowerHelper.sameObjectGroup(selectedItems) if (not objectGroup): return if (objectGroup.drawOrder() != ObjectGroup.DrawOrder.IndexOrder): return ranges = RangeSet() for item in selectedItems: ranges.insert(int(item.zValue())) commands = QList() to = 0 for it in ranges: first = it[0] _from = first count = it[1] - first + 1 if (_from == to): to += count continue commands.append( ChangeMapObjectsOrder(self.mMapDocument, objectGroup, _from, to, count)) to += count self.push( commands, QCoreApplication.translate("Undo Commands", "Lower Object To Bottom"))
def __init__(self, mapScene): self.mSelectionRanges = RangeSet() self.mMapDocument = mapScene.mapDocument() self.mMapScene = mapScene # Context self.mObjectGroup = None self.mRelatedObjects = QList()
def removeTiles(self): view = self.currentTilesetView() if (not view): return if (not view.selectionModel().hasSelection()): return indexes = view.selectionModel().selectedIndexes() model = view.tilesetModel() tileIds = RangeSet() tiles = QList() for index in indexes: tile = model.tileAt(index) if tile: tileIds.insert(tile.id()) tiles.append(tile) def matchesAnyTile(cell): tile = cell.tile if tile: return tiles.contains(tile) return False inUse = self.hasTileReferences(self.mMapDocument, matchesAnyTile) # If the tileset is in use, warn the user and confirm removal if (inUse): warning = QMessageBox( QMessageBox.Warning, self.tr("Remove Tiles"), self.tr("One or more of the tiles to be removed are " "still in use by the map!"), QMessageBox.Yes | QMessageBox.No, self) warning.setDefaultButton(QMessageBox.Yes) warning.setInformativeText( self.tr("Remove all references to these tiles?")) if (warning.exec() != QMessageBox.Yes): return undoStack = self.mMapDocument.undoStack() undoStack.beginMacro(self.tr("Remove Tiles")) removeTileReferences(self.mMapDocument, matchesAnyTile) # Iterate backwards over the ranges in order to keep the indexes valid firstRange = tileIds.begin() it = tileIds.end() if (it == firstRange): # no range return tileset = view.tilesetModel().tileset() while (it != firstRange): it -= 1 item = tileIds.item(it) length = item[1] - item[0] + 1 undoStack.push( RemoveTiles(self.mMapDocument, tileset, item[0], length)) undoStack.endMacro() # Clear the current tiles, will be referencing the removed tiles self.setCurrentTiles(None) self.setCurrentTile(None)
def allocate(self, size, align_to=None, alignment=None, name=None, constraint=lambda x, y: True, start=None): if start is not None: result = MemoryArea(self.exploit, start, size, align_to, alignment) if (result.start, result.end) not in self.ranges: raise Exception("The range (" + hex(result.start) + ", " + hex(result.end) + ") is not allowed") else: for candidate_range in self.ranges: start, end = candidate_range result = MemoryArea(self.exploit, start, size, align_to, alignment) start += result.size while (start < end) and (not constraint( result.start, result.index)): result = MemoryArea(self.exploit, start, size, align_to, alignment) start += result.size if start < end: break else: result = None if result is None: raise AllocateFailException( "Couldn't find a position for memory area \"" + str(name) + "\" satisfying the imposed constraints before the end of the available buffer." ) else: # We have to create a hole in the appropriate range self.ranges = self.ranges - RangeSet(result.start, result.end) self.cleanup_ranges() if name is not None: self.areas[name] = result return result
def raiseToTop(self): selectedItems = self.mMapScene.selectedObjectItems() objectGroup = RaiseLowerHelper.sameObjectGroup(selectedItems) if (not objectGroup): return if (objectGroup.drawOrder() != ObjectGroup.DrawOrder.IndexOrder): return ranges = RangeSet() for item in selectedItems: ranges.insert(int(item.zValue())) # Iterate backwards over the ranges in order to keep the indexes valid size = len(ranges) if size <= 0: # no range return commands = QList() to = objectGroup.objectCount() for i in range(size - 1, -1, -1): it = ranges.item(i) first = it[0] last = it[1] count = last - first + 1 if (last + 1 == to): to -= count continue _from = first commands.append( ChangeMapObjectsOrder(self.mMapDocument, objectGroup, _from, to, count)) to -= count self.push( commands, QCoreApplication.translate("Undo Commands", "Raise Object To Top"))
def delete_(self): if (not self.mMapDocument or not self.mTile): return if (self.mTile.tileset().isExternal()): return selectionModel = self.mUi.frameList.selectionModel() indexes = selectionModel.selectedIndexes() if len(indexes) == 0: return undoStack = self.mMapDocument.undoStack() undoStack.beginMacro(self.tr("Delete Frames")) ranges = RangeSet() for index in indexes: ranges.insert(index.row()) # Iterate backwards over the ranges in order to keep the indexes valid firstRange = ranges.begin() it = ranges.end() while (it != firstRange): it -= 1 item = ranges.item(it) length = item[1] - item[0] + 1 self.mFrameListModel.removeRows(item[0], length, QModelIndex()) undoStack.endMacro()
def __init__(self, start, end=None): self.ranges = RangeSet() self.start = start self.end = end
def config_from_elf(self, path): """Load all the necessary information about the program parsing the ELF headers. Furthermore, check some pre-requisites for the exploit to be successful.""" executable_file = open(path, "r") elf = ELFFile(executable_file) get_section = lambda name: first_or_none( filter(lambda section: section.name == name, elf.iter_sections())) get_section_address = lambda section: None if (get_section( section) is None) else get_section(section).header.sh_addr # Checks if elf.header.e_type == ENUM_E_TYPE["ET_EXEC"]: raise Exception("Only non-PIE executables are supported") # Binary type self.arch = elf.header.e_machine self.little = elf.little_endian self.pointer_size = elf.elfclass / 8 self.pointer_format = ("0x%." + str(self.pointer_size * 2) + "x") self.structs = elftools.elf.structs.ELFStructs(self.little, self.pointer_size * 8) # Useful sections self.sections = { section.name: (section.header.sh_addr, section.header.sh_addr + section.header.sh_size) for section in elf.iter_sections() } self.plt = get_section_address(".plt") self.got = get_section_address(".got") self.gotplt = get_section_address(".got.plt") # Dynamic section dynamic_section = get_section(".dynamic") self.writable_dynamic = dynamic_section.header.sh_flags & SH_FLAGS.SHF_WRITE self.dynamic = dynamic_section.header.sh_addr dynamic_entries = [ self.structs.Elf_Dyn.parse(dynamic_entry) for dynamic_entry in chunks(dynamic_section.data(), self.structs.Elf_Dyn.sizeof()) ] # Dynamic symbols # TODO: we're relying on section names here symbol_table = elf.get_section_by_name(".dynsym") has_name = lambda name: lambda symbol: symbol.name == name attribute_or_default = lambda default, attribute, x: getattr( x, attribute) if x is not None else default memcpy_symbol = first_or_none( filter(has_name("memcpy"), symbol_table.iter_symbols())) self.memcpy_plt = 0 if memcpy_symbol is None else memcpy_symbol.entry.st_value # We try not to rely on section names get_dynamic = lambda name: first_or_none( map(lambda entry: entry.d_val, filter(lambda entry: entry.d_tag == name, dynamic_entries))) get_dynamic_index = lambda name: filter( lambda entry: entry[1].d_tag == name, enumerate(dynamic_entries))[ 0][0] self.dynstr = get_dynamic("DT_STRTAB") self.dynsym = get_dynamic("DT_SYMTAB") self.versym = get_dynamic("DT_VERSYM") self.verneed = get_dynamic("DT_VERNEED") self.relplt = get_dynamic("DT_JMPREL") self.addend = get_dynamic("DT_RELA") is not None self.dt_debug = self.dynamic + get_dynamic_index( "DT_DEBUG") * self.structs.Elf_Dyn.sizeof() + self.pointer_size self.full_relro = (get_dynamic("DT_FLAGS") is not None) and \ ((get_dynamic("DT_FLAGS") & DF_BIND_NOW) != 0) self.full_relro = self.full_relro or ((get_dynamic("DT_FLAGS_1") is not None) and \ ((get_dynamic("DT_FLAGS_1") & DF_1_NOW) != 0)) # Choose between Elf_Rel and Elf_Rela depending on the architecture self.rel_struct = self.structs.Elf_Rela if self.addend else self.structs.Elf_Rel # Looks like 64-bit and 32-bit have different alignment for the call to _dl_fixup self.reloc_alignment = 1 if self.pointer_size == 4 else self.rel_struct.sizeof( ) self.reloc_index_multiplier = self.rel_struct.sizeof( ) if self.pointer_size == 4 else 1 # # Find candidate writeable areas # # Collect PT_LOAD segments (what gets mapped) loaded_segments = filter( lambda segment: segment.header.p_type == "PT_LOAD", elf.iter_segments()) # Collect the segments which are writeable writeable_segments = filter( lambda segment: segment.header.p_flags & P_FLAGS.PF_W, loaded_segments) # Get their memory ranges (start, end) writeable_ranges = RangeSet.mutual_union(*map( lambda segment: (segment.header.p_vaddr, segment.header.p_vaddr + segment.header.p_memsz), writeable_segments)) # List of sections we don't want to write to dont_overwrite_sections = filter_none([ self.dynstr, self.dynsym, self.versym, self.relplt, self.dynamic, self.got, self.gotplt ]) # Memory ranges of the sections we don't want to write to dont_overwrite_ranges = RangeSet.mutual_union(*[ self.sections[self.section_from_address(start)] for start in dont_overwrite_sections ]) # Handle RELRO segment, we don't want to write there relro_segment = first_or_none( filter(lambda segment: segment.header.p_type == "PT_GNU_RELRO", elf.iter_segments())) if relro_segment is not None: dont_overwrite_ranges = dont_overwrite_ranges | RangeSet( relro_segment.header.p_vaddr, relro_segment.header.p_vaddr + relro_segment.header.p_memsz) # Compute the set of candidate memory ranges self.writeable_ranges = writeable_ranges - dont_overwrite_ranges # Save the index of the DT_FINI entry fini = filter(lambda (i, entry): entry.d_tag == "DT_FINI", enumerate(dynamic_entries)) if len(fini) > 0: self.fini = self.dynamic + self.structs.Elf_Dyn.sizeof( ) * fini[0][0] # Gadgets if self.gadgets.has_key(self.arch): executable_segments = filter( lambda segment: segment.header.p_flags & P_FLAGS.PF_X, elf.iter_segments()) for name, (info, gadget) in self.gadgets[self.arch].iteritems(): locations = find_all_strings(executable_segments, hex_bytes(gadget)) locations = map(self.ptr2str, locations) location = first_or_none( filter( lambda address: not reduce( lambda accumulate, badchar: badchar in address or accumulate, self.badchars, False), locations)) if location is None: self.gadgets[self.arch][name] = None else: self.gadgets[self.arch][name] = (info, gadget, location) # Find all '\x00\x00' in non-writeable segments self.non_writeable_segments = filter( lambda segment: not (segment.header.p_flags & P_FLAGS.PF_W), loaded_segments) self.zero_or_one_addresses = find_all_strings(self.non_writeable_segments, "\x00\x00") + \ find_all_strings(self.non_writeable_segments, "\x01\x00" if self.little else "\x00\x01") self.filler = self.ptr2str( reduce(lambda x, y: (x << 32) | 0xdeadb00b, xrange(1 + (self.pointer_size % 4)), 0)) self.relocation_type = relocation_types[self.arch] # # Find the reloc pointing to the symbol whose name is the earliest in .dynstr # relplt_section = elf.get_section_by_name( self.section_from_address(self.relplt)) dynsym_section = elf.get_section_by_name( self.section_from_address(self.dynsym)) if not (isinstance(relplt_section, RelocationSection) and \ isinstance(dynsym_section, SymbolTableSection)): raise Exception("Unexpect type for dynamic sections: " + str(relplt_section) + " " + str(dynsym_section)) # Grab .got.plt relocs symbol indexes symbol_indexes = [ reloc.entry.r_info_sym if reloc.entry.r_info_type == self.relocation_type else None for reloc in relplt_section.iter_relocations() ] # Get offsets in .dynstr names_offsets = [ dynsym_section.get_symbol(index).entry.st_name if index is not None else None for index in symbol_indexes ] # Filter out unamed offsets names_offsets = [ offset if offset > 0 else None for offset in names_offsets ] # Get the minimum value self.min_reloc_index, self.min_string_offset = min( enumerate(names_offsets), key=operator.itemgetter(1)) self.min_symbol_index = symbol_indexes[self.min_reloc_index] log(self.dump())