def djnz_helper(self, il, addr, reg): # decrement the register self.wreg_set(il, reg, il.sub(1, self.wreg_get(il, reg), il.const(1, 1))) # try to find a label for the branch target taken = il.get_label_for_address(il.arch, addr) # create taken target taken_found = True if taken is None: taken = LowLevelILLabel() taken_found = False # create untaken target untaken_found = True untaken = il.get_label_for_address(il.arch, il.current_address + 2) if untaken is None: untaken = LowLevelILLabel() untaken_found = False # generate the conditional branch LLIL il.append(il.if_expr(il.compare_not_equal(1, self.wreg_get(il, reg), il.const(1, 0)), taken, untaken)) # generate a jump to the branch target if a label couldn't be found if not taken_found: il.mark_label(taken) il.append(il.jump(il.const(2, addr))) # generate a label for the untaken branch if not untaken_found: il.mark_label(untaken)
def _lift_inc_dec(self, il, regs, df_values): if not isinstance(regs, tuple): regs = (regs, ) if df_values is not None and df_values.type == RegisterValueType.ConstantValue: if df_values.value: for reg in regs: il.append( il.set_reg(2, reg, il.sub(2, il.reg(2, reg), il.const(2, 1)))) else: for reg in regs: il.append( il.set_reg(2, reg, il.add(2, il.reg(2, reg), il.const(2, 1)))) else: inc_label, dec_label = LowLevelILLabel(), LowLevelILLabel() post_label = LowLevelILLabel() il.append(il.if_expr(il.flag('d'), dec_label, inc_label)) il.mark_label(inc_label) for reg in regs: il.append( il.set_reg(2, reg, il.add(2, il.reg(2, reg), il.const(2, 1)))) il.append(il.goto(post_label)) il.mark_label(dec_label) for reg in regs: il.append( il.set_reg(2, reg, il.sub(2, il.reg(2, reg), il.const(2, 1)))) il.append(il.goto(post_label)) il.mark_label(post_label)
def il_branch(il, cond, tdest, fdest): # lookup the true branch t_target = None if il[tdest].operation == LowLevelILOperation.LLIL_CONST: t_target = il.get_label_for_address(Architecture['s1c88:s1c88'], il[tdest].constant) # if the label doesn't exist, create a new one indirect = False if t_target is None: t_target = LowLevelILLabel() indirect = True # create the false branch f_target = LowLevelILLabel() # create the if_expr il.append(il.if_expr(cond, t_target, f_target)) # handle true target if indirect if indirect: il.mark_label(t_target) il.append(il.jump(tdest)) # mark false branch il.mark_label(f_target)
def lift(self, il, addr): overflow_label = LowLevelILLabel() normal_label = LowLevelILLabel() il.append(il.if_expr(il.flag('o'), overflow_label, normal_label)) il.mark_label(overflow_label) Int.lift(self, il, addr) il.mark_label(normal_label)
def append_conditional_instr(cond, instr, il): if cond == CC.ALWAYS: il.append(instr) else: t = LowLevelILLabel() f = LowLevelILLabel() #if cond in CC_UN_NOT: # ant = jcc_to_flag_cond(CC_UN_NOT[cond], il) # il.append(il.if_expr(ant, f, t)) #else: ant = jcc_to_flag_cond(cond, il) il.append(il.if_expr(ant, t, f)) il.mark_label(t) il.append(instr) il.mark_label(f)
def cond_branch(il, cond, dest): t = None if il[dest].operation == LowLevelILOperation.LLIL_CONST: t = il.get_label_for_address(Architecture['6502'], il[dest].value) if t is None: t = LowLevelILLabel() indirect = True else: indirect = False f = LowLevelILLabel() il.append(il.if_expr(cond, t, f)) if indirect: il.mark_label(t) il.append(il.jump(dest)) il.mark_label(f) return None
def cond_branch(il, addr, cond, arg=None): # try to find a label for the branch target taken = il.get_label_for_address(il.arch, addr) # build the conditional expression if cond == 'Z': expr = il.compare_equal(1, il.reg(1, 'A'), il.const(1, 0)) elif cond == 'NZ': expr = il.compare_not_equal(1, il.reg(1, 'A'), il.const(1, 0)) elif cond == 'B': expr = il.and_expr(1, il.reg(1, 'A'), il.const(1, 1 << arg)) else: expr = il.compare_equal(1, il.flag(cond), il.const(0, arg)) # create taken target taken_found = True if taken is None: taken = LowLevelILLabel() taken_found = False # create untaken target untaken_found = True untaken = il.get_label_for_address(il.arch, il.current_address + 2) if untaken is None: untaken = LowLevelILLabel() untaken_found = False # generate the conditional branch LLIL il.append(il.if_expr(expr, taken, untaken)) # generate a jump to the branch target if a label couldn't be found if not taken_found: il.mark_label(taken) il.append(il.jump(il.const_pointer(2, addr))) # generate a label for the untaken branch if not untaken_found: il.mark_label(untaken)
def lift(self, il, addr): untaken_label = il.get_label_for_address(il.arch, addr + self.length()) taken_label = il.get_label_for_address(il.arch, self.ip) if taken_label is None: mark_taken = True taken_label = LowLevelILLabel() else: mark_taken = False il.append( il.if_expr(self._lift_loop_cond(il), taken_label, untaken_label)) if mark_taken: il.mark_label(taken_label) il.append(il.jump(il.const(3, self.ip)))
def lift(self, il, addr): if not isinstance(self.next, InstrString): il.append(il.undefined()) return # FIXME: doesn't seem to actually work preheader_instr = il.append(il.nop()) df_values = il[preheader_instr].get_possible_flag_values('d') header_label = LowLevelILLabel() exit_label = LowLevelILLabel() il.mark_label(header_label) self.next.lift(il, addr + 1, df_values) il.append( il.set_reg(2, 'cx', il.sub(2, il.reg(2, 'cx'), il.const(2, 1)))) cond = il.compare_equal(2, il.reg(2, 'cx'), il.const(2, 0)) if self._zf_check(): zf_cond = il.compare_equal(2, il.flag('z'), il.const(1, self._zf_cond)) cond = il.or_expr(1, cond, zf_cond) il.append(il.if_expr(cond, header_label, exit_label)) il.mark_label(exit_label)
def lift(self, il, addr): untaken_label = il.get_label_for_address(il.arch, addr + self.length()) taken_label = il.get_label_for_address(il.arch, self.ip) if taken_label is None: mark_taken = True taken_label = LowLevelILLabel() else: mark_taken = False name = self.name() if name == 'jpe': il.append(il.if_expr(il.flag('p'), taken_label, untaken_label)) elif name == 'jpo': il.append(il.if_expr(il.flag('p'), untaken_label, taken_label)) else: cond = jump_cond[name] il.append( il.if_expr(il.flag_condition(cond), taken_label, untaken_label)) if mark_taken: il.mark_label(taken_label) il.append(il.jump(il.const(3, self.ip)))
def il_jump(il, dest, is_call=False): if is_call: il.append(il.call(dest)) else: # lookup label t = None if il[dest].operation == LowLevelILOperation.LLIL_CONST: t = il.get_label_for_address(Architecture['s1c88:s1c88'], il[dest].constant) # if the label doesn't exist, create a new one indirect = False if t is None: t = LowLevelILLabel() indirect = True # if it doesn't exist, create and jump if indirect: il.mark_label(t) il.append(il.jump(dest)) else: # just goto label il.append(il.goto(t))
def get_instruction_low_level_il(self, data, addr, il: LowLevelILFunction): instr = self.disassembler.instrs[addr // self.address_size] if instr is None: return None if isinstance(instr, Subleq): a, b, c = instr.a, instr.b, instr.c _, mem_a = self.get_addr_mem_il(a, il) addr_b, mem_b = self.get_addr_mem_il(b, il) sub_op = il.sub(self.address_size, mem_b, mem_a) if self.disassembler.is_register(b): store_b = il.set_reg(self.address_size, self.disassembler.symbol[b], sub_op) else: store_b = il.store(self.address_size, addr_b, sub_op) il.append(store_b) less_op = il.compare_signed_less_equal( self.address_size, mem_b, il.const(self.address_size, 0)) t_target = il.get_label_for_address(il.arch, c * self.address_size) t_label_found = True if t_target is None: t_label_found = False t_target = LowLevelILLabel() f_label_found = True f_target = il.get_label_for_address( il.arch, addr + instr.width + self.address_size) if f_target is None: f_target = LowLevelILLabel() f_label_found = False il.append(il.if_expr(less_op, t_target, f_target)) if not t_label_found: il.mark_label(t_target) il.append( il.jump(il.const(self.address_size, c * self.address_size))) if not f_label_found: il.mark_label(f_target) elif isinstance(instr, Clear): b = instr.b c = instr.c addr_b, _ = self.get_addr_mem_il(b, il) store_b = il.store(self.address_size, addr_b, il.const(self.address_size, 0)) il.append(store_b) jump_c = il.jump( il.const(self.address_size, instr.c * self.address_size)) il.append(jump_c) elif isinstance(instr, Push): v = instr.v addr_v, mem_v = self.get_addr_mem_il(v, il) push_v = il.push(self.address_size, mem_v) il.append(push_v) elif isinstance(instr, Mov): a, b = instr.a, instr.b addr_a, mem_a = self.get_addr_mem_il(a, il) addr_b, mem_b = self.get_addr_mem_il(b, il) if self.disassembler.is_register(b): mov_op = il.set_reg(self.address_size, self.disassembler.symbol[b], mem_a) else: mov_op = il.store(self.address_size, addr_b, mem_a) il.append(mov_op) elif isinstance(instr, Ret): il.append( il.ret( il.load(self.address_size, il.reg(self.address_size, "sp")))) elif isinstance(instr, Pop): v = instr.v addr_v, _ = self.get_addr_mem_il(v, il) pop_op = il.pop(self.address_size) if self.disassembler.is_register(v): store_op = il.set_reg(self.address_size, self.disassembler.symbol[v], pop_op) else: store_op = il.store(self.address_size, addr_v, pop_op) il.append(store_op) elif isinstance(instr, Call): il.append( il.call( il.const(self.address_size, instr.c * self.address_size))) elif isinstance(instr, Inc): b = instr.b addr_b, mem_b = self.get_addr_mem_il(b, il) if self.disassembler.is_register(b): store_op = il.set_reg( self.address_size, self.disassembler.symbol[b], il.add(self.address_size, mem_b, il.const(self.address_size, 1)), ) else: store_op = il.store( self.address_size, addr_b, il.add(self.address_size, mem_b, il.const(self.address_size, 1)), ) il.append(store_op) elif isinstance(instr, Dec): b = instr.b addr_b, mem_b = self.get_addr_mem_il(b, il) if self.disassembler.is_register(b): store_op = il.set_reg( self.address_size, self.disassembler.symbol[b], il.add(self.address_size, mem_b, il.const(self.address_size, -1)), ) else: store_op = il.store( self.address_size, addr_b, il.add(self.address_size, mem_b, il.const(self.address_size, -1)), ) il.append(store_op) elif isinstance(instr, Exit): il.append(il.no_ret()) elif isinstance(instr, Jmp): il.append( il.jump( il.const(self.address_size, instr.c * self.address_size))) return instr.width * self.address_size
def gen_instr_il(addr, decoded, il): (oper_type, oper_val) = decoded.operands[0] if decoded.operands else (None, None) (operb_type, operb_val) = decoded.operands[1] if decoded.operands[1:] else (None, None) if decoded.op in [OP.ADD, OP.ADC]: assert len(decoded.operands) == 2 if oper_type == OPER_TYPE.REG: size = REG_TO_SIZE[oper_val] rhs = operand_to_il(operb_type, operb_val, il, size) lhs = operand_to_il(oper_type, oper_val, il) if decoded.op == OP.ADD: tmp = il.add(size, lhs, rhs, flags='*') else: tmp = il.add_carry(size, lhs, rhs, il.flag("c"), flags='*') tmp = il.set_reg(size, reg2str(oper_val), tmp) il.append(tmp) else: il.append(il.unimplemented()) elif decoded.op == OP.AND: tmp = il.reg(1, 'A') tmp = il.and_expr(1, operand_to_il(oper_type, oper_val, il, 1), tmp, flags='z') tmp = il.set_reg(1, 'A', tmp) il.append(tmp) elif decoded.op == OP.BIT: assert oper_type == OPER_TYPE.IMM assert oper_val >= 0 and oper_val <= 7 mask = il.const(1, 1 << oper_val) operand = operand_to_il(operb_type, operb_val, il, 1) il.append(il.and_expr(1, operand, mask, flags='*')) elif decoded.op == OP.CALL: if oper_type == OPER_TYPE.ADDR: il.append(il.call(il.const_pointer(2, oper_val))) else: # TODO: handle the conditional il.append(il.unimplemented()) elif decoded.op == OP.CCF: il.append(il.set_flag('c', il.not_expr(0, il.flag('c')))) elif decoded.op == OP.CP: # sub, but do not write to register lhs = il.reg(1, 'A') rhs = operand_to_il(oper_type, oper_val, il, 1) sub = il.sub(1, lhs, rhs, flags='*') il.append(sub) elif decoded.op == OP.DJNZ: # decrement B tmp = il.reg(1, 'B') tmp = il.add(1, tmp, il.const(1, -1)) tmp = il.set_reg(1, 'B', tmp) il.append(tmp) # if nonzero, jump! (the "go" is built into il.if_expr) t = il.get_label_for_address(Architecture['Z80'], oper_val) if not t: il.append(il.unimplemented()) return f = il.get_label_for_address(Architecture['Z80'], addr + decoded.len) if not f: il.append(il.unimplemented()) return tmp = il.compare_not_equal(1, il.reg(1, 'B'), il.const(1, 0)) il.append(il.if_expr(tmp, t, f)) elif decoded.op == OP.EX: # temp0 = lhs il.append( il.expr(LowLevelILOperation.LLIL_SET_REG, LLIL_TEMP(0), operand_to_il(oper_type, oper_val, il, 2), size=2)) # lhs = rhs rhs = operand_to_il(operb_type, operb_val, il, 2) if oper_type == OPER_TYPE.REG: il.append(il.set_reg(2, reg2str(oper_val), rhs)) else: il.append( il.store( 2, operand_to_il(oper_type, oper_val, il, 2, peel_load=True), rhs)) # rhs = temp0 il.append( il.set_reg(2, reg2str(operb_val), il.expr(LowLevelILOperation.LLIL_REG, LLIL_TEMP(0), 2))) elif decoded.op == OP.INC: # inc reg can be 1-byte or 2-byte if oper_type == OPER_TYPE.REG: size = REG_TO_SIZE[oper_val] tmp = il.add(size, operand_to_il(oper_type, oper_val, il), il.const(1, 1)) tmp = il.set_reg(size, reg2str(oper_val), tmp) else: tmp = il.add(1, operand_to_il(oper_type, oper_val, il), il.const(1, 1)) tmp = il.store( 1, operand_to_il(oper_type, oper_val, il, 1, peel_load=True), tmp) il.append(tmp) elif decoded.op in [OP.JP, OP.JR]: if oper_type == OPER_TYPE.COND: append_conditional_jump(oper_val, operb_type, operb_val, addr + decoded.len, il) else: il.append(goto_or_jump(oper_type, oper_val, il)) elif decoded.op == OP.LD: assert len(decoded.operands) == 2 if oper_type == OPER_TYPE.REG: size = REG_TO_SIZE[oper_val] # for two-byte nonzero loads, guess that it's an address if size == 2 and operb_type == OPER_TYPE.IMM and operb_val != 0: operb_type = OPER_TYPE.ADDR rhs = operand_to_il(operb_type, operb_val, il, size) set_reg = il.set_reg(size, reg2str(oper_val), rhs) il.append(set_reg) else: assert operb_type in [OPER_TYPE.REG, OPER_TYPE.IMM] if operb_type == OPER_TYPE.REG: # 1 or 2 byte stores are possible here: # ld (0xcdab),bc # ld (ix-0x55),a size = REG_TO_SIZE[operb_val] elif operb_type == OPER_TYPE.IMM: # only 1 byte stores are possible # eg: ld (ix-0x55),0xcd size = 1 src = operand_to_il(operb_type, operb_val, il, size) dst = operand_to_il(oper_type, oper_val, il, size, peel_load=True) il.append(il.store(size, dst, src)) elif decoded.op in [OP.LDI, OP.LDIR]: if decoded.op == OP.LDIR: t = LowLevelILLabel() f = il.get_label_for_address(Architecture['Z80'], addr + decoded.len) il.mark_label(t) il.append(il.store(1, il.reg(2, 'DE'), il.load(1, il.reg(2, 'HL')))) il.append( il.set_reg(2, 'DE', il.add(2, il.reg(2, 'DE'), il.const(2, 1)))) il.append( il.set_reg(2, 'HL', il.add(2, il.reg(2, 'HL'), il.const(2, 1)))) il.append( il.set_reg(2, 'BC', il.sub(2, il.reg(2, 'BC'), il.const(2, 1)))) if decoded.op == OP.LDIR: do_mark = False if not f: do_mark = True f = LowLevelILLabel() il.append( il.if_expr( il.compare_not_equal(2, il.reg(2, 'BC'), il.const(2, 0)), t, f)) if do_mark: il.mark_label(f) elif decoded.op == OP.NOP: il.append(il.nop()) elif decoded.op == OP.OR: tmp = il.reg(1, 'A') tmp = il.or_expr(1, operand_to_il(oper_type, oper_val, il, 1), tmp, flags='*') tmp = il.set_reg(1, 'A', tmp) il.append(tmp) elif decoded.op == OP.POP: # possible operands are: af bc de hl ix iy flag_write_type = '*' if oper_val == REG.AF else None size = REG_TO_SIZE[oper_val] tmp = il.pop(size) tmp = il.set_reg(size, reg2str(oper_val), tmp, flag_write_type) il.append(tmp) elif decoded.op == OP.PUSH: # possible operands are: af bc de hl ix iy # when pushing AF, actually push the flags if oper_val == REG.AF: # lo byte F first il.append( il.push( 2, il.or_expr( 2, il.or_expr( 1, il.or_expr( 1, il.shift_left(1, il.flag('s'), il.const(1, 7)), il.shift_left(1, il.flag('z'), il.const(1, 6))), il.or_expr( 1, il.or_expr( 1, il.shift_left(1, il.flag('h'), il.const(1, 4)), il.shift_left(1, il.flag('pv'), il.const(1, 2))), il.or_expr( 1, il.shift_left(1, il.flag('n'), il.const(1, 1)), il.flag('c')))), il.shift_left(2, il.reg(1, 'A'), il.const(1, 8))))) else: il.append(il.push( \ REG_TO_SIZE[oper_val], \ operand_to_il(oper_type, oper_val, il))) elif decoded.op in [OP.RL, OP.RLA]: # rotate THROUGH carry: b0=c, c=b8 # z80 'RL' -> llil 'RLC' if decoded.op == OP.RLA: src = il.reg(1, 'A') else: src = operand_to_il(oper_type, oper_val, il) rot = il.rotate_left_carry(1, src, il.const(1, 1), il.flag('c'), flags='c') if decoded.op == OP.RLA: il.append(il.set_reg(1, 'A', rot)) elif oper_type == OPER_TYPE.REG: il.append(il.set_reg(1, reg2str(oper_val), rot)) else: tmp = operand_to_il(oper_type, oper_val, il, 1, peel_load=True) il.append(il.store(1, tmp2, tmp)) elif decoded.op in [OP.RLC, OP.RLCA]: # rotate and COPY to carry: b0=c, c=b8 # z80 'RL' -> llil 'ROL' if decoded.op == OP.RLCA: src = il.reg(1, 'A') else: src = operand_to_il(oper_type, oper_val, il) rot = il.rotate_left(1, src, il.const(1, 1), flags='c') if decoded.op == OP.RLCA: il.append(il.set_reg(1, 'A', rot)) elif oper_type == OPER_TYPE.REG: il.append(il.set_reg(1, reg2str(oper_val), rot)) else: tmp = operand_to_il(oper_type, oper_val, il, 1, peel_load=True) il.append(il.store(1, tmp2, tmp)) elif decoded.op == OP.RET: tmp = il.ret(il.pop(2)) if decoded.operands: append_conditional_instr(decoded.operands[0][1], tmp, il) else: il.append(tmp) elif decoded.op in [OP.RR, OP.RRA]: # rotate THROUGH carry: b7=c, c=b0 # z80 'RL' -> llil 'RRC' if decoded.op == OP.RRA: src = il.reg(1, 'A') else: src = operand_to_il(oper_type, oper_val, il, 1) rot = il.rotate_right_carry(1, src, il.const(1, 1), il.flag('c'), flags='c') if decoded.op == OP.RRA: il.append(il.set_reg(1, 'A', rot)) elif oper_type == OPER_TYPE.REG: il.append(il.set_reg(1, reg2str(oper_val), rot)) else: tmp2 = operand_to_il(oper_type, oper_val, il, 1, peel_load=True) il.append(il.store(1, tmp2, rot)) elif decoded.op == OP.SRA: tmp = operand_to_il(oper_type, oper_val, il, 1) tmp = il.arith_shift_right(1, tmp, il.const(1, 1), flags='c') if oper_type == OPER_TYPE.REG: tmp = il.set_reg(1, reg2str(oper_val), tmp) else: tmp = il.store( 1, operand_to_il(oper_type, oper_val, il, 1, peel_load=True), tmp) il.append(tmp) elif decoded.op == OP.SUB: tmp = operand_to_il(oper_type, oper_val, il, 1) tmp = il.sub(1, il.reg(1, 'A'), tmp, flags='*') tmp = il.set_reg(1, 'A', tmp) il.append(tmp) elif decoded.op == OP.DEC: if oper_type == OPER_TYPE.REG: size = REG_TO_SIZE[oper_val] reg = operand_to_il(oper_type, oper_val, il, size) fwt = 'not_c' if size == 1 else None tmp = il.sub(size, reg, il.const(1, 1), flags=fwt) tmp = il.set_reg(size, reg2str(oper_val), tmp) il.append(tmp) else: mem = operand_to_il(oper_type, oper_val, il, 1) tmp = il.sub(1, mem, il.const(1, 1), flags='not_c') tmp = il.store(1, mem, tmp) il.append(tmp) elif decoded.op == OP.SBC: size = REG_TO_SIZE[oper_val] lhs = operand_to_il(oper_type, oper_val, il, size) rhs = operand_to_il(operb_type, operb_val, il, size) tmp = il.sub_borrow(size, lhs, rhs, il.flag('c'), flags='*') tmp = il.set_reg(1, 'A', tmp) il.append(tmp) elif decoded.op == OP.XOR: tmp = il.reg(1, 'A') tmp = il.xor_expr(1, operand_to_il(oper_type, oper_val, il, 1), tmp, flags='*') tmp = il.set_reg(1, 'A', tmp) il.append(tmp) else: il.append(il.unimplemented())
def esil_to_llil(self, inst, parts, il, addr, l): stack = [] label_stack = [] skip_to_close = False # pop for reading - interprets the PC register as # the value of the next instruction def popr(): r = stack.pop() if r == "pc": return il.const_pointer(4, addr + l) return r for i, token in enumerate(parts): # No idea why I need this if token == "" and i == len(parts)-1: break if skip_to_close and token != "}": continue if token == "$$": stack.append(il.const_pointer(4, addr)) continue if token == "pc": stack.append("pc") continue if token in self.regs: stack.append(il.reg(4, token)) continue if token in self._esil_to_llil: dst = popr() src = popr() stack.append(getattr(il, self._esil_to_llil[token])(4, dst, src)) continue if token == "$z" or token == "!": stack.append(il.compare_equal(4, stack[-1], il.const(4, 0))) continue if token == "DUP": stack.append(stack[-1]) continue if token == "=": dst = stack.pop() src = popr() if dst == "pc": srci = il[src] if srci.operation == LowLevelILOperation.LLIL_CONST: self.goto_or_jmp(il, srci.operands[0]) continue il.append(il.jump(src)) continue dst = il[dst] if dst.operation != LowLevelILOperation.LLIL_REG: raise ValueError("unimplemented il store to {0!r}".format(dst)) il.append(il.set_reg(4, dst.operands[0].name, src)) continue if token == "+=": dste = stack.pop() src = popr() if dste == "pc": srci = il[src] # Note in ESIL this is w.r.t. the *next* address # For narrow branch instructions, it calculates the pc relative # wrong in the ESIL and uses 3 bytes anyway # also, srci.operands[0] is 8 bytes *signed* but ESIL # doesn't seem to reflect this? # Note: except beqz, bnez, bgez, bltz which have 12 bytes *signed* # and beqz.n and bnez.n which are 4 bytes unsigned if srci.operation == LowLevelILOperation.LLIL_CONST: offset = srci.operands[0] if inst in ("beqz", "bnez", "bgez", "bltz"): if offset > (1 << 11) - 1: offset = ((1<<12)-offset) * -1 elif inst in ("beqz.n", "bnez.n"): pass elif offset > 127: offset = (256-offset) * -1 self.goto_or_jmp(il, offset + addr + 3) else: il.append(il.jump(il.add(4, il.const_pointer(4, addr + 3), src))) continue dst = il[dste] if dst.operation != LowLevelILOperation.LLIL_REG: raise ValueError("unimplemented il store to {0!r}".format(dst)) il.append(il.set_reg(4, dst.operands[0].name, il.add(4, dste, src))) continue if token.startswith("=["): sz = int(token[2:-1]) dst = popr() src = popr() il.append(il.store(sz, dst, src)) continue if token.startswith("["): sz = int(token[1:-1]) if sz == 1 or sz == 2: stack.append(il.zero_extend(4, il.load(sz, popr()))) elif sz == 4: stack.append(il.load(4, popr())) else: raise ValueError("Invalid load size {0}".format(sz)) continue # Base 16 constants try: i = int(token, 16) except ValueError: pass else: stack.append(il.const(4, i)) continue # Base 10 constants try: i = int(token) except ValueError: pass else: stack.append(il.const(4, i)) continue # Hack to support branch instructions if token == "?{": t = None set_t = False end = parts.index("}", i+1) f = None # Don't create useless labels if this is at the end # of the instruction (e.g. a branch) if end == len(parts)-1: f = self.force_label(il, addr+l) if f is None: f = LowLevelILLabel() label_stack.append(f) inner = parts[i+1:end] fakeil = ThreaderILDuck() try: self.esil_to_llil(inst, inner, fakeil, addr, l) except AttributeError as e: pass except IndexError as e: # Tried to access the stack outside! Bad! pass except Exception as e: log.log_error("{0} {1}".format(e, inner)) raise e else: if fakeil.target is not None: t = self.force_label(il, fakeil.target) # log.log_info("Prediction successful at {0:X}, {1}, {2:X} {3} {4}".format(addr, inner, fakeil.target, t, parts)) # else: # log.log_warn("Prediction succesful but no target {0} {1}".format(inner, parts)) if t is None: set_t = True t = LowLevelILLabel() il.append(il.if_expr(stack.pop(), t, f)) if set_t: il.mark_label(t) elif len(label_stack) == 0: break else: skip_to_close = True continue if token == "}": if len(label_stack) == 0: break il.mark_label(label_stack.pop()) skip_to_close = False continue raise ValueError("Unimplemented esil {0} in {1} for {2}".format(token, esil, inst))
def get_instruction_low_level_il(self, data, addr, il): locals = threading.local() inst,args = self._get_asm(data, addr) if inst == "ill": return None l = self._inst_length(inst) if inst in ("jx"): if args[0] in self.regs: il.append(il.jump(il.reg(4, args[0]))) else: self.goto_or_jmp(il, int(args[0], 16)) return l elif inst.startswith("call"): spilled_regs = int(inst[5 if inst.startswith("callx") else 4:]) # Spill onto stack a = lambda a: "a{0}".format(a) r = lambda r: il.reg(4, "a{0}".format(r)) # if spilled_regs != 0: # for i in range(spilled_regs): # il.append(il.push(4, r(i))) # for i in range(spilled_regs, 16): # il.append(il.set_reg(4, a(i-spilled_regs), r(i))) if spilled_regs != 0 and self.VERBOSE_IL: il.append(il.set_reg(1, "PS.CALLINC", il.const(1, spilled_regs))) # return address # il.append(il.set_reg(4, a(spilled_regs), il.const(4, addr + l))) target = il.reg(4, args[0]) if inst.startswith("callx") else il.const_pointer(4, int(args[0], 16)) il.append(il.call(target)) # unspill from stack # if spilled_regs != 0: # for i in range(15, spilled_regs-1, -1): # il.append(il.set_reg(4, a(i), r(i-spilled_regs))) # for i in range(spilled_regs-1, -1, -1): # il.append(il.set_reg(4, a(i), il.pop(4))) return l elif inst in ("ret", "retw", "ret.n", "retw.n"): il.append(il.ret(il.reg(4, "a0"))) return l elif inst == "j": il.append(il.jump(il.const_pointer(4, int(args[0], 16)))) return l elif inst in ("loopgtz", "loopnez", "loop"): lbegin = addr + l lend = int(args[1], 16) r = il.reg(4, args[0]) lcount = il.sub(4, r, il.const(4,1)) # lend must come before lbegin for loop detection to work lower down if self.VERBOSE_IL: il.append(il.set_reg(4, "lend", il.const_pointer(4, lend))) il.append(il.set_reg(4, "lbegin", il.const_pointer(4, lbegin))) il.append(il.set_reg(4, "lcount", lcount)) if inst in ("loopgtz", "loopnez"): t = self.force_label(il, lbegin) f = self.force_label(il, lend) set_t = False set_f = False if t is None: set_t = True t = LowLevelILLabel() if f is None: set_f = True f = LowLevelILLabel() if inst == "loopnez": cond = il.compare_unsigned_greater_equal(4, r, il.const(4, 0)) else: cond = il.compare_signed_greater_equal(4, r, il.const(4, 0)) il.append(il.if_expr(cond, t, f)) if set_f: il.mark_label(f) self.goto_or_jmp(il, lend) if set_t: il.mark_label(t) # fallthrough with self._looplock: self.loops[lend] = lbegin return l elif inst == "entry": # Entry doesn't *do* anything, basically il.append(il.intrinsic([], "entry", [])) return l elif inst == "memw": il.append(il.intrinsic([], "memw", [])) return l # override buggy l32r in radare elif inst == "l32r" and LITBASE & 0x1 == 1: a,b = self._decode_l32r(LITBASE, addr, data) il.append(il.set_reg(4, a, il.load(4, il.const_pointer(4, b)))) return l esil = self._get_esil(data[0:l], addr) if esil == "": il.append(il.unimplemented()) return l parts = esil.split(",") # For basic instructions, interpret the ESIL self.esil_to_llil(inst, parts, il, addr, l) # Scan the function for loop instructions pointing to here lbegin = None with self._looplock: n = addr + l if n in self.loops: lbegin = self.loops[n] if lbegin is not None: cond = il.compare_unsigned_greater_than(4, il.reg(4, "lcount"), il.const(4, 0)) f = self.force_label(il, n) t = self.force_label(il, lbegin) #il.get_label_for_address(self, lbegin) set_f = False set_t = False if f is None: set_f = True f = LowLevelILLabel() if t is None: set_t = True t = LowLevelILLabel() il.append(il.if_expr(cond, t, f)) if set_t: il.mark_label(t) self.goto_or_jmp(il, lbegin) if set_f: il.mark_label(f) # fallthrough return l