def set_instruction(self, instruction): self.length = instruction.length self.type = instruction.type self.mode = instruction.mode self.opcode = instruction.opcode self.modrm = instruction.modrm self.sib = instruction.sib self.extindex = instruction.extindex self.fpuindex = instruction.fpuindex self.dispbytes = instruction.dispbytes self.immbytes = instruction.immbytes self.sectionbytes = instruction.sectionbytes self.flags = instruction.flags if instruction.op1.type: self.op1 = PyOperand(instruction.op1) if instruction.op2.type: self.op2 = PyOperand(instruction.op2) if instruction.op3.type: self.op3 = PyOperand(instruction.op3) # Disassembly string of instruction self.disasm = pydasm.get_instruction_string(instruction, pydasm.FORMAT_INTEL, 0x0).rstrip(" ") self.mnemonic = pydasm.get_mnemonic_string(instruction, pydasm.FORMAT_INTEL).rstrip(" ")
def set_instruction(self, instruction): self.length = instruction.length self.type = instruction.type self.mode = instruction.mode self.opcode = instruction.opcode self.modrm = instruction.modrm self.sib = instruction.sib self.extindex = instruction.extindex self.fpuindex = instruction.fpuindex self.dispbytes = instruction.dispbytes self.immbytes = instruction.immbytes self.sectionbytes = instruction.sectionbytes self.flags = instruction.flags # # In the future we'll use a PyOperand class, for now its to slow # if instruction.op1.type: self.op1 = instruction.op1 if instruction.op2.type: self.op2 = instruction.op2 if instruction.op3.type: self.op3 = instruction.op3 self.mnemonic = pydasm.get_mnemonic_string(instruction, pydasm.FORMAT_INTEL).rstrip(" ")
def find_gadget_ends(start_ea, end_ea): gadget_end_addresses = [] for opcode_byte in gadget_ends: ea = start_ea while True: ea = inp.code_search(ea, opcode_byte) if ea > end_ea or ea == None: break if inp.byte_at(ea) != 0xFF: gadget_end_addresses.append(ea) else: # An opcode starting with 0xFF is not necessarily an indirect jmp/call bytes_ahead = 10 # TODO should be smaller, probably 3, should check headroom = inp.seg_end(ea) - ea if 0 < headroom < 10: bytes_ahead = headroom ibuf = inp.bytes_at(ea, bytes_ahead) if not ibuf: print "WARNING: GetManyBytes(%.08X, %d) failed " % ( ea, bytes_ahead) instr = pydasm.get_instruction(ibuf, pydasm.MODE_32) if (instr and pydasm.get_mnemonic_string( instr, pydasm.FORMAT_INTEL) in ("call", "jmp") and (instr.op1.reg != 8 or instr.op1.basereg != 8 or instr.op1.indexreg != 8)): gadget_end_addresses.append(ea) ea += 1 return gadget_end_addresses
def __init__(self, instruction, rawinstruction, eip): self.length = instruction.length self.type = instruction.type self.mode = instruction.mode self.opcode = instruction.opcode self.modrm = instruction.modrm self.sib = instruction.sib self.extindex = instruction.extindex self.fpuindex = instruction.fpuindex self.dispbytes = instruction.dispbytes self.immbytes = instruction.immbytes self.sectionbytes = instruction.sectionbytes self.flags = instruction.flags self.eip = eip self.raw = rawinstruction[0:self.length] self.mnemonic = pydasm.get_mnemonic_string( instruction, pydasm.FORMAT_INTEL).rstrip(" ") self.disasm = pydasm.get_instruction_string(instruction, pydasm.FORMAT_INTEL, self.eip).rstrip(" ") self.description = '' self.op1 = '' self.op2 = '' self.op3 = '' # # In the future we'll use a PyOperand class, for now its to slow # if instruction.op1.type: self.op1 = instruction.op1 if instruction.op2.type: self.op2 = instruction.op2 if instruction.op3.type: self.op3 = instruction.op3
def __init__(self, instruction, rawinstruction, eip): self.length = instruction.length self.type = instruction.type self.mode = instruction.mode self.opcode = instruction.opcode self.modrm = instruction.modrm self.sib = instruction.sib self.extindex = instruction.extindex self.fpuindex = instruction.fpuindex self.dispbytes = instruction.dispbytes self.immbytes = instruction.immbytes self.sectionbytes = instruction.sectionbytes self.flags = instruction.flags self.eip = eip self.raw = rawinstruction[0:self.length] self.mnemonic = pydasm.get_mnemonic_string(instruction, pydasm.FORMAT_INTEL).rstrip(" ") self.disasm = pydasm.get_instruction_string(instruction, pydasm.FORMAT_INTEL, self.eip).rstrip(" ") self.description = '' self.op1 = '' self.op2 = '' self.op3 = '' # # In the future we'll use a PyOperand class, for now its to slow # if instruction.op1.type: self.op1 = instruction.op1 if instruction.op2.type: self.op2 = instruction.op2 if instruction.op3.type: self.op3 = instruction.op3
def set_instruction(self, instruction): self.length = instruction.length self.type = instruction.type self.mode = instruction.mode self.opcode = instruction.opcode self.modrm = instruction.modrm self.sib = instruction.sib self.extindex = instruction.extindex self.fpuindex = instruction.fpuindex self.dispbytes = instruction.dispbytes self.immbytes = instruction.immbytes self.sectionbytes = instruction.sectionbytes self.flags = instruction.flags # # In the future we'll use a PyOperand class, for now its to slow # if instruction.op1.type: self.op1 = instruction.op1 if instruction.op2.type: self.op2 = instruction.op2 if instruction.op3.type: self.op3 = instruction.op3 self.mnemonic = pydasm.get_mnemonic_string( instruction, pydasm.FORMAT_INTEL).rstrip(" ")
def find_gadget_ends(start_ea, end_ea): gadget_end_addresses = [] for opcode_byte in gadget_ends: ea = start_ea while True: ea = inp.code_search(ea, opcode_byte) if ea > end_ea or ea == None: break if inp.byte_at(ea) != 0xFF: gadget_end_addresses.append(ea) else: # An opcode starting with 0xFF is not necessarily an indirect jmp/call bytes_ahead = 10 # TODO should be smaller, probably 3, should check headroom = inp.seg_end(ea) - ea if 0 < headroom < 10: bytes_ahead = headroom ibuf = inp.bytes_at(ea, bytes_ahead) if not ibuf: print "WARNING: GetManyBytes(%.08X, %d) failed " % (ea, bytes_ahead) instr = pydasm.get_instruction(ibuf, pydasm.MODE_32) if (instr and pydasm.get_mnemonic_string(instr, pydasm.FORMAT_INTEL) in ("call", "jmp") and (instr.op1.reg != 8 or instr.op1.basereg != 8 or instr.op1.indexreg != 8)): gadget_end_addresses.append(ea) ea += 1 return gadget_end_addresses
def __init__(self, ea, bytes, spd): self.addr = ea self.bytes = bytes # copy whatever we need from the pydasm instruction object inst = pydasm.get_instruction(bytes, pydasm.MODE_32) if inst == None: print "IGNORE:", hex(ea), ''.join( ('\\x%02x' % ord(b) for b in bytes)) inst = nop self.disas = pydasm.get_instruction_string(inst, pydasm.FORMAT_INTEL, ea) self.mnem = pydasm.get_mnemonic_string(inst, pydasm.FORMAT_INTEL) self.type = inst.type self.modrm_off = inst.modrm_offset self.opc_off = inst.opcode_offset self.eflags_r = inst.eflags_used self.eflags_w = inst.eflags_affected self.uses_sib = False self.inst_len = inst.length - inst.opcode_offset # no prefixes!! self.spd = spd # stack pointer delta self.pos = -1 # instruction position after ordering self.raddr = ea # address after reordering (if changed) self.implicit = set() # registers used implicitly by this instruction self.f_entry = False # whether the instruction is a function entry point self.f_exit = inst.type == pydasm.INSTRUCTION_TYPE_RET self.regs = dict() # holds bit positions in the instruction per reg self.updated = False # for call instr, tells whether it was updated self.can_change = set() # registers that can change in a indirect call # these copies of bytes and regs are initialized by reset_changed self.cregs = None self.cbytes = None self.creg_names = None # liveness information self.succ = set() # list of successor instruction addresses self.USE = set() # regs used (read) by this instruction self.DEF = set() # regs defined (written) by this instruction self.IN = set() # regs that are live before instruction execution self.OUT = set() # regs that are live after instruction execution self.IN_old = None self.OUT_old = None # TODO: special case for lea optimization (3 operands) self._get_use_def(inst) self._store_operands(inst) self.reset_changed()
def __init__(self, ea, bytes, spd): self.addr = ea self.bytes = bytes # copy whatever we need from the pydasm instruction object inst = pydasm.get_instruction(bytes, pydasm.MODE_32) if inst == None: print "IGNORE:", hex(ea), ''.join(('\\x%02x' % ord(b) for b in bytes)) inst = nop self.disas = pydasm.get_instruction_string( inst, pydasm.FORMAT_INTEL, ea) self.mnem = pydasm.get_mnemonic_string(inst, pydasm.FORMAT_INTEL) self.type = inst.type self.modrm_off = inst.modrm_offset self.opc_off = inst.opcode_offset self.eflags_r = inst.eflags_used self.eflags_w = inst.eflags_affected self.uses_sib = False self.inst_len = inst.length - inst.opcode_offset # no prefixes!! self.spd = spd # stack pointer delta self.pos = -1 # instruction position after ordering self.raddr = ea # address after reordering (if changed) self.implicit = set() # registers used implicitly by this instruction self.f_entry = False # whether the instruction is a function entry point self.f_exit = inst.type == pydasm.INSTRUCTION_TYPE_RET self.regs = dict() # holds bit positions in the instruction per reg self.updated = False # for call instr, tells whether it was updated self.can_change = set() # registers that can change in a indirect call # these copies of bytes and regs are initialized by reset_changed self.cregs = None self.cbytes = None self.creg_names = None # liveness information self.succ = set() # list of successor instruction addresses self.USE = set() # regs used (read) by this instruction self.DEF = set() # regs defined (written) by this instruction self.IN = set() # regs that are live before instruction execution self.OUT = set() # regs that are live after instruction execution self.IN_old = None self.OUT_old = None # TODO: special case for lea optimization (3 operands) self._get_use_def(inst) self._store_operands(inst) self.reset_changed()
def swap_registers(self, r1, r2): """Swaps the registers of the instruction and checks if the resulting one is correct. Returns False if the resulting instruction is wrong or if the instruction was unchanged. On success, 'cregs' and 'cbytes' are updated accordingly.""" def update_bits(r1, r2, bytes, cregs): for byte_off, bit_off in cregs[r1]: # print map(bin, bytes) clear_mask = ~(0b111 << bit_off) bytes[byte_off] &= clear_mask # print map(bin, bytes) set_mask = REGS.index(r2) << bit_off bytes[byte_off] |= set_mask # print map(bin, bytes) return # translate register names XXX out for now .. # print 'translate:', r1, r2, '->', # r1 = self.creg_names[r1] if r1 in self.creg_names else r1 # r2 = self.creg_names[r2] if r2 in self.creg_names else r2 # print r1, r2 # check if the swap is feasible bytes = self.cbytes[:] if r1 in self.cregs: update_bits(r1, r2, bytes, self.cregs) if r2 in self.cregs: update_bits(r2, r1, bytes, self.cregs) # illegal modrm/sip states if self.modrm_off: mod = pydasm.MASK_MODRM_MOD(bytes[self.modrm_off]) prev_rm = pydasm.MASK_MODRM_RM(self.cbytes[self.modrm_off]) rm = pydasm.MASK_MODRM_RM(bytes[self.modrm_off]) if mod == 0b00 and (prev_rm == 0b101 or rm == 0b101) and prev_rm != rm: # print "modrm case 1:", self.disas, "|", r1, r2 return False if (0b00 <= mod <= 0b10 and (prev_rm == 0b100 or rm == 0b100) and prev_rm != rm): # print "modrm case 2:", self.disas, "|", r1, r2 return False if self.uses_sib: idx = pydasm.MASK_SIB_INDEX(bytes[self.modrm_off + 1]) prev_idx = pydasm.MASK_SIB_INDEX(self.cbytes[self.modrm_off + 1]) if (prev_idx == 0b100 or idx == 0b100) and prev_idx != idx: # print "sib case 1:", self.disas, "|", r1, r2 return False base = pydasm.MASK_SIB_BASE(bytes[self.modrm_off + 1]) prev_base = pydasm.MASK_SIB_BASE(self.cbytes[self.modrm_off + 1]) # XXX: there is a special sub-case here.. we can swap base with index.. if (mod == 0b00 and (prev_base == 0b101 or base == 0b101) and prev_base != base): # print "sib case 2:", self.disas, "|", r1, r2 return False # check if the newly created instruction can be decoded properly inst = pydasm.get_instruction(str(bytes), pydasm.MODE_32) if not inst: print hex(self.addr), "cant swap (", r1, r2, ")", self.disas return False # check if the mnemonic changed new_mnem = pydasm.get_mnemonic_string(inst, pydasm.FORMAT_INTEL) if self.mnem != new_mnem: print hex( self.addr), "cant swap (", r1, r2, ")", self.disas, new_mnem return False # check if the register names are the intended ones (8-bit accesses) # example: (esi <-> ebx) 'test bl, bl' -> 'test dh, dh' !!!! orig = pydasm.get_instruction(self.bytes, pydasm.MODE_32) for op in (orig.op1, orig.op2, orig.op3): if (op.type == pydasm.OPERAND_TYPE_REGISTER and # register pydasm.MASK_OT(op.flags) == pydasm.OT_b and # 8-bit (al, dl..) REGS[op.reg] in (r1, r2) and # swapped set((r1, r2)) - set( (REGS[op.reg], )) & set(REGS[4:])): # with (esi..) return False # extend with NOPs # FIXME: manualy check if eax is dest and the instruction can be compressed # for i in range(inst.length, len(bytes)): # bytes[i] = "\x90" # apply the swap! if r1 in self.cregs and r2 in self.cregs: tmp = self.cregs[r1] self.cregs[r1] = self.cregs[r2] self.cregs[r2] = tmp elif r1 in self.cregs: self.cregs[r2] = self.cregs[r1] del self.cregs[r1] elif r2 in self.cregs: self.cregs[r1] = self.cregs[r2] del self.cregs[r2] self.cbytes = bytes # update register names XXX: leave translation out for now .. # self.creg_names[r1] = r2 # self.creg_names[r2] = r1 # print 'update:', r1, r2, '->', self.creg_names[r1], self.creg_names[r2] # print self.disas, "->", pydasm.get_instruction_string(inst, pydasm.FORMAT_INTEL, self.addr) return True
def swap_registers(self, r1, r2): """Swaps the registers of the instruction and checks if the resulting one is correct. Returns False if the resulting instruction is wrong or if the instruction was unchanged. On success, 'cregs' and 'cbytes' are updated accordingly.""" def update_bits(r1, r2, bytes, cregs): for byte_off, bit_off in cregs[r1]: # print map(bin, bytes) clear_mask = ~(0b111 << bit_off) bytes[byte_off] &= clear_mask # print map(bin, bytes) set_mask = REGS.index(r2) << bit_off bytes[byte_off] |= set_mask # print map(bin, bytes) return # translate register names XXX out for now .. # print 'translate:', r1, r2, '->', # r1 = self.creg_names[r1] if r1 in self.creg_names else r1 # r2 = self.creg_names[r2] if r2 in self.creg_names else r2 # print r1, r2 # check if the swap is feasible bytes = self.cbytes[:] if r1 in self.cregs: update_bits(r1, r2, bytes, self.cregs) if r2 in self.cregs: update_bits(r2, r1, bytes, self.cregs) # illegal modrm/sip states if self.modrm_off: mod = pydasm.MASK_MODRM_MOD(bytes[self.modrm_off]) prev_rm = pydasm.MASK_MODRM_RM(self.cbytes[self.modrm_off]) rm = pydasm.MASK_MODRM_RM(bytes[self.modrm_off]) if mod == 0b00 and (prev_rm == 0b101 or rm == 0b101) and prev_rm != rm: # print "modrm case 1:", self.disas, "|", r1, r2 return False if (0b00 <= mod <= 0b10 and (prev_rm == 0b100 or rm == 0b100) and prev_rm != rm): # print "modrm case 2:", self.disas, "|", r1, r2 return False if self.uses_sib: idx = pydasm.MASK_SIB_INDEX(bytes[self.modrm_off + 1]) prev_idx = pydasm.MASK_SIB_INDEX(self.cbytes[self.modrm_off + 1]) if (prev_idx == 0b100 or idx == 0b100) and prev_idx != idx: # print "sib case 1:", self.disas, "|", r1, r2 return False base = pydasm.MASK_SIB_BASE(bytes[self.modrm_off + 1]) prev_base = pydasm.MASK_SIB_BASE(self.cbytes[self.modrm_off + 1]) # XXX: there is a special sub-case here.. we can swap base with index.. if (mod == 0b00 and (prev_base == 0b101 or base == 0b101) and prev_base != base): # print "sib case 2:", self.disas, "|", r1, r2 return False # check if the newly created instruction can be decoded properly inst = pydasm.get_instruction(str(bytes), pydasm.MODE_32) if not inst: print hex(self.addr), "cant swap (", r1, r2, ")", self.disas return False # check if the mnemonic changed new_mnem = pydasm.get_mnemonic_string(inst, pydasm.FORMAT_INTEL) if self.mnem != new_mnem: print hex(self.addr), "cant swap (", r1, r2, ")", self.disas, new_mnem return False # check if the register names are the intended ones (8-bit accesses) # example: (esi <-> ebx) 'test bl, bl' -> 'test dh, dh' !!!! orig = pydasm.get_instruction(self.bytes, pydasm.MODE_32) for op in (orig.op1, orig.op2, orig.op3): if (op.type == pydasm.OPERAND_TYPE_REGISTER and # register pydasm.MASK_OT(op.flags) == pydasm.OT_b and # 8-bit (al, dl..) REGS[op.reg] in (r1, r2) and # swapped set((r1, r2)) - set((REGS[op.reg],)) & set(REGS[4:])): # with (esi..) return False # extend with NOPs # FIXME: manualy check if eax is dest and the instruction can be compressed # for i in range(inst.length, len(bytes)): # bytes[i] = "\x90" # apply the swap! if r1 in self.cregs and r2 in self.cregs: tmp = self.cregs[r1] self.cregs[r1] = self.cregs[r2] self.cregs[r2] = tmp elif r1 in self.cregs: self.cregs[r2] = self.cregs[r1] del self.cregs[r1] elif r2 in self.cregs: self.cregs[r1] = self.cregs[r2] del self.cregs[r2] self.cbytes = bytes # update register names XXX: leave translation out for now .. # self.creg_names[r1] = r2 # self.creg_names[r2] = r1 # print 'update:', r1, r2, '->', self.creg_names[r1], self.creg_names[r2] # print self.disas, "->", pydasm.get_instruction_string(inst, pydasm.FORMAT_INTEL, self.addr) return True
def is_branch(insn): # One of the branch types or an IRET return (insn.type in x86_branches or pydasm.get_mnemonic_string(insn, pydasm.FORMAT_INTEL) == 'iret' or pydasm.get_mnemonic_string(insn, pydasm.FORMAT_INTEL) == 'sysexit')