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
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
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
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)
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
def bytes_to_comparable_str(ibytes, offset): return " ".join( utils.instruction_to_str(self.disassemble( ibytes, offset)[0]).split()[2:])
def bytes_to_comparable_str(ibytes, offset): return " ".join(utils.instruction_to_str(utils.decompile(ibytes, offset)[0]).split()[2:])