Пример #1
0
    def insert_detour(self, patch):
        # TODO allow special case to patch syscall wrapper epilogue
        # (not that important since we do not want to patch epilogue in syscall wrapper)
        block_addr = self.get_block_containing_inst(patch.addr)
        block = self.project.factory.block(block_addr)

        l.debug("inserting detour for patch: %s" % (map(hex, (block_addr, block.size, patch.addr))))

        detour_size = 5
        one_byte_nop = '\x90'

        # get movable instructions
        movable_instructions = self.get_movable_instructions(block)
        if len(movable_instructions) == 0:
            raise DetourException("No movable instructions found")

        # figure out where to insert the detour
        detour_pos = self.find_detour_pos(block, detour_size, patch.addr)

        # classify overwritten instructions
        detour_overwritten_bytes = range(detour_pos, detour_pos+detour_size)

        for i in movable_instructions:
            if len(set(detour_overwritten_bytes).intersection(set(range(i.address, i.address+len(i.bytes))))) > 0:
                if i.address < patch.addr:
                    i.overwritten = "pre"
                elif i.address == patch.addr:
                    i.overwritten = "culprit"
                else:
                    i.overwritten = "post"
            else:
                i.overwritten = "out"
        l.debug("\n".join([utils.instruction_to_str(i) for i in movable_instructions]))
        assert any([i.overwritten != "out" for i in movable_instructions])

        # replace overwritten instructions with nops
        for i in movable_instructions:
            if i.overwritten != "out":
                for b in xrange(i.address, i.address+len(i.bytes)):
                    if b in self.touched_bytes:
                        raise DoubleDetourException("byte has been already touched: %08x" % b)
                    else:
                        self.touched_bytes.add(b)
                self.patch_bin(i.address, one_byte_nop*len(i.bytes))

        # insert the jump detour
        detour_jmp_code = utils.compile_jmp(detour_pos, self.get_current_code_position())
        self.patch_bin(detour_pos, detour_jmp_code)
        patched_bbcode = self.read_mem_from_file(block_addr, block.size)
        patched_bbinstructions = utils.decompile(patched_bbcode, block_addr)
        l.debug("patched bb instructions:\n %s",
                "\n".join([utils.instruction_to_str(i) for i in patched_bbinstructions]))

        new_code = self.compile_moved_injected_code(movable_instructions, patch.code)

        return new_code
Пример #2
0
    def find_detour_pos(self, block, detour_size, patch_addr):
        # iterates through the instructions to find where the detour can be stored
        movable_instructions = self.get_movable_instructions(block)

        detour_attempts = range(-1 * detour_size, 0 + 1)

        movable_bb_start = movable_instructions[0].address
        movable_bb_size = self.project.factory.block(
            block.addr, num_inst=len(movable_instructions)).size
        l.debug("movable_bb_size: %d", movable_bb_size)
        l.debug(
            "movable bb instructions:\n%s", "\n".join(
                [utils.instruction_to_str(i) for i in movable_instructions]))

        # find a spot for the detour
        detour_pos = None
        for pos in detour_attempts:
            detour_start = patch_addr + pos
            detour_end = detour_start + detour_size - 1
            if detour_start >= movable_bb_start and detour_end < (
                    movable_bb_start + movable_bb_size):
                detour_pos = detour_start
                break
        if detour_pos is None:
            raise DetourException("No space in bb", hex(block.addr),
                                  hex(block.size), hex(movable_bb_start),
                                  hex(movable_bb_size))
        l.debug("detour fits at %s", hex(detour_pos))

        return detour_pos
Пример #3
0
    def find_detour_pos(self, block, detour_size, patch_addr):
        # iterates through the instructions to find where the detour can be stored
        movable_instructions = self.get_movable_instructions(block)

        movable_bb_start = movable_instructions[0].address
        movable_bb_size = self.project.factory.block(
            block.addr, num_inst=len(movable_instructions)).size
        l.debug("movable_bb_size: %d", movable_bb_size)
        l.debug(
            "movable bb instructions:\n%s", "\n".join(
                [utils.instruction_to_str(i) for i in movable_instructions]))

        # find a spot for the detour
        detour_pos = None
        for detour_start in range(
                patch_addr - detour_size,
                movable_bb_start + movable_bb_size - detour_size, 2):
            if detour_start in [i.address for i in movable_instructions]:
                detour_pos = detour_start
                break
        if detour_pos is None:
            raise DetourException("No space in bb", hex(block.addr),
                                  hex(block.size), hex(movable_bb_start),
                                  hex(movable_bb_size))
        l.debug("detour fits at %s", hex(detour_pos))
        print(hex(detour_pos))
        return detour_pos
Пример #4
0
    def insert_detour(self, patch):
        # TODO allow special case to patch syscall wrapper epilogue
        # (not that important since we do not want to patch epilogue in syscall wrapper)
        block_addr = self.get_block_containing_inst(patch.addr)
        block = self.project.factory.block(block_addr)

        l.info("inserting detour for patch: %s" %
               (map(hex, (block_addr, block.size, patch.addr))))

        addr = self.get_current_code_position()
        detour_size = len(
            self.arch.asm(self.arch.jmp(self.get_current_code_position()),
                          patch.addr))

        # get movable instructions
        movable_instructions = self.get_movable_instructions(block)
        if len(movable_instructions) == 0:
            raise DetourException("No movable instructions found")

        # figure out where to insert the detour
        detour_pos = self.find_detour_pos(block, detour_size, patch.addr)

        # TODO: Optimize when we have one byte nop
        # classify overwritten instructions
        # We need to move all instruction before patch.addr
        detour_overwritten_bytes = range(
            detour_pos, max(detour_pos + detour_size, patch.addr))

        for i in movable_instructions:
            if len(
                    set(detour_overwritten_bytes).intersection(
                        set(range(i.address, i.address + len(i.bytes))))) > 0:
                if i.address < patch.addr:
                    i.overwritten = "pre"
                elif i.address == patch.addr:
                    i.overwritten = "culprit"
                else:
                    i.overwritten = "post"
            else:
                i.overwritten = "out"
        l.info("\n".join(
            [utils.instruction_to_str(i) for i in movable_instructions]))
        assert any([i.overwritten != "out" for i in movable_instructions])

        # replace overwritten instructions with nops
        for i in movable_instructions:
            if i.overwritten != "out":
                for b in xrange(i.address, i.address + len(i.bytes)):
                    if b in self.touched_bytes:
                        raise DoubleDetourException(
                            "byte has been already touched: %08x" % b)
                    else:
                        self.touched_bytes.add(b)
                #self.patch_bin(i.address, one_byte_nop*len(i.bytes))

        detour_jmp_code = self.arch.jmp(self.get_current_code_position())
        assert (len(self.arch.asm(detour_jmp_code, detour_pos)) == detour_size)
        self.patchkit.patch(detour_pos, asm=detour_jmp_code)
        self.inject_moved_code(movable_instructions, patch.code)
Пример #5
0
    def insert_detour(self, patch):
        detour_size = 4
        ppc_nop = b"\x60\x00\x00\x00"

        if self.try_without_cfg:
            offset = self.project.loader.main_object.mapped_base if self.project.loader.main_object.pic else 0
            detour_jmp_code = self.compile_jmp(
                patch.addr,
                self.get_current_code_position() + offset)
            patched_bbcode = self.read_mem_from_file(patch.addr, detour_size)
            patched_bbinstructions = self.disassemble(patched_bbcode,
                                                      patch.addr)
            l.debug(
                "patched bb instructions:\n %s", "\n".join([
                    utils.instruction_to_str(i) for i in patched_bbinstructions
                ]))
            self.patch_bin(patch.addr, detour_jmp_code)
            new_code = self.compile_asm(
                patch.code + "\n" + "\n".join(
                    [self.capstone_to_asm(s)
                     for s in patched_bbinstructions]) +
                "\nb %s" % hex(patch.addr + 4 - offset),
                base=self.get_current_code_position(),
                name_map=self.name_map)
            return new_code
        # TODO allow special case to patch syscall wrapper epilogue
        # (not that important since we do not want to patch epilogue in syscall wrapper)
        block_addr = self.get_block_containing_inst(patch.addr)
        mem = self.read_mem_from_file(
            block_addr,
            self.project.factory.block(block_addr).size)
        block = self.project.factory.block(block_addr, byte_string=mem)

        l.debug("inserting detour for patch: %s",
                (map(hex, (block_addr, block.size, patch.addr))))

        # get movable instructions
        movable_instructions = self.get_movable_instructions(block)
        if len(movable_instructions) == 0:
            raise DetourException("No movable instructions found")

        # figure out where to insert the detour
        detour_pos = self.find_detour_pos(block, detour_size, patch.addr)

        # classify overwritten instructions
        detour_overwritten_bytes = range(detour_pos, detour_pos + detour_size)

        for i in movable_instructions:
            if len(
                    set(detour_overwritten_bytes).intersection(
                        set(range(i.address, i.address + len(i.bytes))))) > 0:
                if i.address < patch.addr:
                    i.overwritten = "pre"
                elif i.address == patch.addr:
                    i.overwritten = "culprit"
                else:
                    i.overwritten = "post"
            else:
                i.overwritten = "out"
        l.debug("\n".join(
            [utils.instruction_to_str(i) for i in movable_instructions]))
        assert any(i.overwritten != "out" for i in movable_instructions)

        # replace overwritten instructions with nops
        for i in movable_instructions:
            if i.overwritten != "out":
                for b in range(i.address, i.address + len(i.bytes)):
                    if b in self.touched_bytes:
                        raise DoubleDetourException(
                            "byte has been already touched: %08x" % b)
                    self.touched_bytes.add(b)
                self.patch_bin(i.address, ppc_nop)

        # insert the jump detour
        offset = self.project.loader.main_object.mapped_base if self.project.loader.main_object.pic else 0
        detour_jmp_code = self.compile_jmp(
            detour_pos,
            self.get_current_code_position() + offset)
        self.patch_bin(detour_pos, detour_jmp_code)
        patched_bbcode = self.read_mem_from_file(block_addr, block.size)
        patched_bbinstructions = self.disassemble(patched_bbcode, block_addr)
        l.debug(
            "patched bb instructions:\n %s", "\n".join(
                [utils.instruction_to_str(i) for i in patched_bbinstructions]))

        new_code = self.compile_moved_injected_code(movable_instructions,
                                                    patch.code,
                                                    offset=offset)

        return new_code
Пример #6
0
 def bytes_to_comparable_str(ibytes, offset):
     return " ".join(
         utils.instruction_to_str(self.disassemble(
             ibytes, offset)[0]).split()[2:])
Пример #7
0
 def bytes_to_comparable_str(ibytes, offset):
     return " ".join(utils.instruction_to_str(utils.decompile(ibytes, offset)[0]).split()[2:])