예제 #1
0
    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"))
예제 #2
0
    def __init__(self, mapScene):
        self.mSelectionRanges = RangeSet()

        self.mMapDocument = mapScene.mapDocument()
        self.mMapScene = mapScene
        # Context
        self.mObjectGroup = None
        self.mRelatedObjects = QList()
예제 #3
0
    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)
예제 #4
0
    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
예제 #5
0
    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"))
예제 #6
0
    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()
예제 #7
0
 def __init__(self, start, end=None):
     self.ranges = RangeSet()
     self.start = start
     self.end = end
예제 #8
0
    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())