def _fn(instr, dat, addr): txt, code, length = instr immdata = dat[len(code):] info = InstructionInfo() info.length = length dst, src = txt.split()[1].split(',') p_dst_w = set_op(dst, immdata, addr) p_dst_r = load_op(dst, immdata, addr) p_src_r = load_op(src, immdata, addr) fn = None if p_dst_r[1] is not None and p_src_r[1] is not None and p_dst_w[1] is not None: fn = [lambda il: il.append(p_dst_w[1](il, getattr(il, il_op)(p_dst_r[2], p_dst_r[1](il), p_src_r[1](il), flags = flags if flags else None )))] return ( [tT(op), tS(' '), *p_dst_w[0], tS(', '), *p_src_r[0]], info, fn )
def dec(instr, dat, addr): txt, code, length = instr immdata = dat[len(code):] info = InstructionInfo() info.length = length dst = txt.split()[1] p_dst_w = set_op(dst, immdata, addr) p_dst_r = load_op(dst, immdata, addr) fn = None if p_dst_r[1] is not None and p_dst_w[1] is not None: fn = [lambda il: il.append(p_dst_w[1](il, il.sub(p_dst_r[2], p_dst_r[1](il), il.const(p_dst_r[2], 1), flags="z", )))] return ( [tT('DEC'), tS(' '), *p_dst_w[0]], info, fn )
def ex(instr, dat, addr): txt, code, length = instr immdata = dat[len(code):] info = InstructionInfo() info.length = length dst, src = txt.split()[1].split(',') p_dst_w = set_op(dst, immdata, addr) p_dst_r = load_op(dst, immdata, addr) p_src_w = set_op(src, immdata, addr) p_src_r = load_op(src, immdata, addr) fn = None if p_dst_r[1] is not None and p_src_r[1] is not None and p_dst_w[1] is not None and p_src_w[1] is not None: fn = [ lambda il: il.append(p_dst_w[1](il, p_src_r[1](il))), lambda il: il.append(p_src_w[1](il, p_dst_r[1](il))) ] return ( [tT('EX'), tS(' '), *p_dst_w[0], tS(', '), *p_src_r[0]], info, fn )
def get_instruction_info(self, data, addr): (instruction_text, instruction_len) = dis.lazy_disasm(data) if instruction_len == 0: return None result = InstructionInfo() result.length = instruction_len if len(instruction_text) == 0: return result if instruction_text[0].lower() == 'b': tokens = instruction_text.split() token = tokens[1] # Unconditional Branch if all(char in string.hexdigits for char in token): # --HACK: base address offset dest = int('0x' + token, 16) - 0x400000 result.add_branch(BranchType.UnconditionalBranch, dest) return result # Conditional Branch if op.is_conditional_branch(instruction_text): tokens = instruction_text.split() for token in tokens: csv = token.split(",") check = csv[-1] if all(char in string.hexdigits for char in check): # --HACK: base address offset dest = int('0x' + check, 16) - 0x400000 result.add_branch(BranchType.TrueBranch, dest) result.add_branch(BranchType.FalseBranch, addr + instruction_len) return result return result
def rete(instr, dat, addr): txt, code, length = instr info = InstructionInfo() info.length = length info.add_branch(BranchType.FunctionReturn) return ( [tT('RETE')], info, [lambda il: il.append(il.ret(il.pop(2)))] )
def perform_get_instruction_info(self, data, addr): if len(data) < 2: print "perform_get_instruction_info(%s, 0x%04x), not enough data!" % ( tohex(data), addr) return None if addr % 2 != 0: print "perform_get_instruction_info(%s, 0x%04x), address not aligned!" % ( tohex(data), addr) return None #print "perform_get_instruction_info(%s, 0x%04x)" % (tohex(data), addr) info = InstructionInfo() info.length = self.max_instr_length # workaround for a Binary Ninja bug, data is not guaranteed to be max_instr_length bytes data = data[:self.max_instr_length] instruction = unpack('<H', data)[0] bincode = instruction >> 8 if bincode >= 0x80: opcode_key = bincode & 0xc0 is_bit = False elif bincode >= 0x40: opcode_key = bincode & 0xf8 is_bit = True else: opcode_key = bincode is_bit = False try: mask, opspace, jump_action, opcode, caption = opcode_dict[ opcode_key] except KeyError: return None # TODO is it possible to get more information? operand = instruction & mask branches = { NONXT: lambda: [(BranchType.FunctionReturn, 0)], NEXTI: lambda: [], BRNCH: lambda: [(BranchType.TrueBranch, addr + 4), (BranchType.FalseBranch, addr + 2)], JUMPI: lambda: [(BranchType.UnconditionalBranch, operand * 2) ], # ROM addresses are 16 bits of data per address CALLI: lambda: [(BranchType.CallDestination, operand * 2) ] # ROM addresses are 16 bits of data per address }[jump_action]() for type, address in branches: info.add_branch(type, address) return info
def mlt(instr, dat, addr): txt, code, length = instr info = InstructionInfo() info.length = length return ( [tT('MLT')], info, [lambda il: il.append(il.set_reg(2, 'HL', il.mult(2, il.zero_extend(2, il.reg(1, 'A')), il.zero_extend(2, il.reg(1, 'L')), )))] )
def get_instruction_info(self, data, addr): tmp = self.qualifies(data, addr) if not tmp: return super(X86DeobfuscateHook, self).get_instruction_info(data, addr) (push_addr, length) = tmp print( '%08X: push+ret found, informing binja of unconditional branch to 0x%X' % (addr, push_addr)) result = InstructionInfo() result.length = length result.add_branch(BranchType.UnconditionalBranch, push_addr) return result
def push(instr, dat, addr): txt, code, length = instr immdata = dat[len(code):] op = txt.split()[1] p_op = load_op(op, immdata, addr) info = InstructionInfo() info.length = length return ( [tT('PUSH'), tS(' '), *p_op[0]], info, [lambda il: il.append(il.push(p_op[2], p_op[1](il)))] )
def decode(dat, addr): if len(dat) < 1: return None b0 = dat[0] instr = instructions[b0] if instr is not None and len(instr) != 3: # multi-byte encoding if len(dat) < 2: return None b1 = dat[1] instr = instr[b1] if instr is None or len(dat) < instr[2]: return None txt, code, length = instr info = InstructionInfo() info.length = length op = txt.split()[0] if op == 'LD': return load(instr, dat, addr) elif op == 'JRL': return jrl(instr, dat, addr) elif op == 'JRS': return jrs(instr, dat, addr) elif op == 'CARL': return carl(instr, dat, addr) elif op == 'RET': return ret(instr, dat, addr) elif op == 'RETE': return rete(instr, dat, addr) elif op == 'PUSH': return push(instr, dat, addr) elif op == 'POP': return pop(instr, dat, addr) elif op == 'MLT': return mlt(instr, dat, addr) elif op == 'ADD': return add(instr, dat, addr) elif op == 'SUB': return sub(instr, dat, addr) elif op == 'AND': return f_and(instr, dat, addr) elif op == 'OR': return f_or(instr, dat, addr) elif op == 'XOR': return f_xor(instr, dat, addr) elif op == 'INC': return inc(instr, dat, addr) elif op == 'DEC': return dec(instr, dat, addr) elif op == 'CP': return cp(instr, dat, addr) elif op == 'EX': return ex(instr, dat, addr) elif op == 'INT': return f_int(instr, dat, addr) elif op == 'DJR': return djr(instr, dat, addr) return ([tT(txt)], info, None)
def djr(instr, dat, addr): txt, code, length = instr immdata = dat[len(code):] rel = immdata[0] if rel & 0x80: rel -= 0x100 target = (addr + rel + length - 1) & 0xffff info = InstructionInfo() info.length = length info.add_branch(BranchType.TrueBranch, target) info.add_branch(BranchType.FalseBranch, addr + length) return ( [tT('DJR'), tS(' '), tA(hex(target), target)], info, [ lambda il: il_branch( il, il.compare_not_equal(1, il.reg(1, 'B'), il.const(1, 0)), il.const_pointer(2, target), il.const_pointer(2, addr + length)) ] )
def carl(instr, dat, addr): txt, code, length = instr immdata = dat[len(code):] if txt.split()[1] != '{3}': return None rel = immdata[0] + (immdata[1] << 8) target = (addr + rel + length - 1) & 0xffff info = InstructionInfo() info.length = length info.add_branch(BranchType.CallDestination, target) return ( [tT('CARL'), tS(' '), tA(hex(target), target)], info, [lambda il: il_jump(il, il.const_pointer(2, target), is_call=True)] )
def f_int(instr, dat, addr): txt, code, length = instr immdata = dat[len(code):] op = txt.split()[1] if op != '[{0}h]': return None rel = immdata[0] target = rel & 0xff info = InstructionInfo() info.length = length info.add_branch(BranchType.CallDestination, target) return ( [tT('INT'), tS(' '), tA(hex(target), target)], info, [lambda il: il.append(il.jump(il.const_pointer(2, target)))] )
def pop(instr, dat, addr): txt, code, length = instr immdata = dat[len(code):] op = txt.split()[1] info = InstructionInfo() info.length = length sz = 0 if op in REGS_1: sz = 1 elif op in REGS_2: sz = 2 else: return None return ( [tT('POP'), tS(' '), tR(op)], info, [lambda il: il.append(il.set_reg(sz, op, il.pop(sz)))] )
def perform_get_instruction_info(self, data, addr): if not len(data): return # edge case during linear sweep nfo = InstructionInfo() # ana size, branch = self.lut.branches[ord(data[0])] nfo.length = size # emu if branch: branch_type, target = branch if callable(target): target = target(data, addr, size) if size <= len(data) else 0 if branch_type == BranchType.CallDestination: # TODO: keep track of return-effect functions, tweak target +=dx pass # TODO: arch is probably global; need to store this in bv somehow :| nfo.add_branch(branch_type, target=target) if branch_type == BranchType.TrueBranch: nfo.add_branch(BranchType.FalseBranch, addr + size) return nfo
def get_instruction_info(self, data, addr): # instruction lookup instruction = self.instructions[ord(data[0])] if instruction is None: return None (opcode, length) = instruction[0] result = InstructionInfo() result.length = length # add branches if opcode in ['RET', 'RETI', 'RETR']: result.add_branch(BranchType.FunctionReturn) elif opcode in ['JMP']: # TODO: memory bank selection result.add_branch(BranchType.UnconditionalBranch, CODE_ADDR((ord(data[0]) & 0xe0) << 3, ord(data[1]))) elif opcode in ['JMPP']: result.add_branch(BranchType.UnresolvedBranch) elif opcode == 'DJNZ' or opcode[0] == 'J': # conditional branches result.add_branch(BranchType.TrueBranch, CODE_ADDR(addr, ord(data[1]))) result.add_branch(BranchType.FalseBranch, addr + length) elif opcode == 'CALL': # TODO: memory bank selection result.add_branch(BranchType.CallDestination, CODE_ADDR((ord(data[0]) & 0xe0) << 3, ord(data[1]))) elif opcode == 'SEL': # FIXME: fake branches to support bank switching if instruction[1][0] == 'RB0': result.add_branch(BranchType.UnconditionalBranch, addr + length, Architecture['{}_rb{}mb{}'.format(self.device, 0, self.mb)]) elif instruction[1][0] == 'RB1': result.add_branch(BranchType.UnconditionalBranch, addr + length, Architecture['{}_rb{}mb{}'.format(self.device, 1, self.mb)]) elif instruction[1][0] == 'MB0': result.add_branch(BranchType.UnconditionalBranch, addr + length, Architecture['{}_rb{}mb{}'.format(self.device, self.rb, 0)]) elif instruction[1][0] == 'MB1': result.add_branch(BranchType.UnconditionalBranch, addr + length, Architecture['{}_rb{}mb{}'.format(self.device, self.rb, 1)]) return result
def get_instruction_info(self, data, addr): global active_vtil_file result = InstructionInfo() result.length = 1 next_vip, _, _, _, code = find_instruction(addr, active_vtil_file) if code != None and code.startswith("js"): _, _, true, false = code.split(" ") true = find_block_address(int(true, 16), active_vtil_file) false = find_block_address(int(false, 16), active_vtil_file) result.add_branch(BranchType.TrueBranch, true) result.add_branch(BranchType.FalseBranch, false) elif code != None and code.startswith("vxcall"): addr = find_block_address(next_vip[0], active_vtil_file) result.add_branch(BranchType.UnconditionalBranch, addr) elif code != None and code.startswith("jmp"): if len(next_vip) == 1: addr = find_block_address(next_vip[0], active_vtil_file) result.add_branch(BranchType.UnconditionalBranch, addr) else: result.add_branch(BranchType.IndirectBranch) for vip in next_vip: result.add_branch(BranchType.UnconditionalBranch, find_block_address(vip, active_vtil_file)) elif code != None and code.startswith("vexit"): result.add_branch(BranchType.FunctionReturn) return result
def get_instruction_info(self, data, addr): (instrTxt, instrLen) = skwrapper.disasm(data, addr) if instrLen == 0: return None result = InstructionInfo() result.length = instrLen rccs = r'(?:C|NC|Z|NZ|M|P|PE|PO)' regexes = [ \ r'^(?:JP|JR) '+rccs+r',\$(.*)$', # 0: conditional jump eg: JP PE,#DEAD r'^(?:JP|JR) \$(.*)$', # 1: unconditional jump eg: JP #DEAD r'^(?:JP|JR) \((?:HL|IX|IY)\)$', # 2: unconditional indirect eg: JP (IX) r'^DJNZ \$(.*)$', # 3: dec, jump if not zero eg: DJNZ #DEAD r'^CALL '+rccs+r',\$(.*)$', # 4: conditional call eg: CALL PE,#DEAD r'^CALL \$(.*)$', # 5: unconditional call eg: CALL #DEAD r'^RET '+rccs+'$', # 6: conditional return r'^(?:RET|RETN|RETI)$', # 7: return, return (nmi), return (interrupt) ] m = None for (i,regex) in enumerate(regexes): m = re.match(regex, instrTxt) if not m: continue if i==0 or i==3: dest = int(m.group(1), 16) result.add_branch(BranchType.TrueBranch, dest) result.add_branch(BranchType.FalseBranch, addr + instrLen) pass elif i==1: dest = int(m.group(1), 16) result.add_branch(BranchType.UnconditionalBranch, dest) pass elif i==2: result.add_branch(BranchType.IndirectBranch) pass elif i==4 or i==5: dest = int(m.group(1), 16) result.add_branch(BranchType.CallDestination, dest) pass elif i==6: pass # conditional returns don't end block elif i==7: result.add_branch(BranchType.FunctionReturn) break return result
def get_instruction_info(self, data, addr): """ Establishes instruction length and branch info """ if len(data) > 2: data = data[:2] result = InstructionInfo() result.length = 2 vars = self.dis._vars(data) baddr = vars['addr'] binfo = self.dis.get_branch_info(data) if binfo == BranchType.UnconditionalBranch or binfo == BranchType.CallDestination: result.add_branch(binfo, baddr) elif binfo == BranchType.FunctionReturn or binfo == BranchType.IndirectBranch: result.add_branch(binfo) elif binfo == BranchType.TrueBranch: result.add_branch(BranchType.TrueBranch, addr + 4) result.add_branch(BranchType.FalseBranch, addr + 2) elif binfo == BranchType.FalseBranch: result.add_branch(BranchType.TrueBranch, addr + 4) result.add_branch(BranchType.FalseBranch, addr + 2) return result
def get_instruction_info(self, data, addr): if len(data) < 2 or len(data) > 3: return None obj = decode(data, addr) if obj.name == "UNKNOWN": return None result = InstructionInfo() result.length = obj.len if obj.name in ["RET", "RET.N"]: # RETURN result.add_branch(BranchType.FunctionReturn) if obj.name in [ "BALL", "BNALL", "BANY", "BNONE", "BBC", "BBCI", "BBS", "BBSI", "BEQ", "BEQI", "BEQZ", "BNE", "BNEI", "BNEZ", "BGE", "BGEI", "BGEU", "BGEUI", "BGEZ", "BLT", "BLTI", "BLTU", "BLTUI", "BLTZ" ]: # CONDITIONAL BRANCH for l in obj.prop["format"]: if l[0] == "TYPE_LABEL": result.add_branch(BranchType.TrueBranch, l[1]) result.add_branch(BranchType.FalseBranch, addr + obj.len) if obj.name in ["J"]: # UNCONDITIONAL JUMP for l in obj.prop["format"]: if l[0] == "TYPE_LABEL": result.add_branch(BranchType.UnconditionalBranch, l[1]) if obj.name in ["CALL0", "CALL4", "CALL8", "CALL12"]: # DIRECT CALL for l in obj.prop["format"]: if l[0] == "TYPE_LABEL": result.add_branch(BranchType.CallDestination, l[1]) if obj.name in ["JX"]: # UNCONDITIONAL JUMP TO REGISTER result.add_branch(BranchType.IndirectBranch) #if obj.name in ["CALLX0", "CALLX4", "CALLX8", "CALLX12"]: # CALL TO REGISTER # result.add_branch(BranchType.IndirectBranch) return result
def get_instruction_info(self, data, addr): (instruction_text, instruction_len) = dis.lazy_disasm(addr) if instruction_len == 0: return None result = InstructionInfo() result.length = instruction_len if len(instruction_text) == 0: return result tokens = instruction_text.split() arch = tokens[0] instruction = tokens[1].lower() raw_offset = tokens[-1] if 'ret' in instruction: result.add_branch(BranchType.FunctionReturn) return result if op.instruction_is_call(instruction): call_offset = addr + int(raw_offset, 16) result.add_branch(BranchType.CallDestination, call_offset) return result if not op.instruction_is_branch(instruction): return result if arch == "MIPS": # b 0x10184 # bgtz $zero, -0x6c90 # bgez $zero, 0x14ca0 # bne $v0, $s2, 0x12508 # bnez $t8, 0x14d94 # bltzall $v0, 0x13cd8 # bltzal $t3, -0x7018 # bltz $t0, 0x1371c # bltz $zero, -0x69e0 # bltz $at, 0x1502c if op.is_conditional_branch(instruction_text): branch_offset = addr + int(raw_offset, 16) result.add_branch(BranchType.TrueBranch, branch_offset) result.add_branch(BranchType.FalseBranch, addr + instruction_len) else: # UNCONDITIONAL BRANCH branch_offset = int(raw_offset, 16) result.add_branch(BranchType.UnconditionalBranch, branch_offset) elif arch == "ARM": # bicsvs r8, sl, #0x8000000 # bicsls r2, r0, r0, lsl r0 # bicsls r2, r0, r0, lsl r0 # bicsls r2, r0, r0, lsl r0 # blgt #0x814c9c # bge #0xfffd0b78 # bhi #0x200b08 # bhi #0x419078 # bvs #0x11e10 # bvs #0x1225c is_overflow_set = 'bvs' in instruction_text if op.is_conditional_branch(instruction_text) or is_overflow_set: branch_offset = int(raw_offset.replace("#", ""), 16) - BASE_ADDR result.add_branch(BranchType.TrueBranch, branch_offset) result.add_branch(BranchType.FalseBranch, addr + instruction_len) elif arch == "RISCV": # blez s8, 0x20 # bge t0, a2, 0x24 # bge sp, t2, 0x164 # bge t2, sp, 0x15c # bge t0, sp, 0x1c # bge t2, s0, 0x34 # bge s1, t0, 0x1c # j -0x24 # j -0x130 # j -0x140 # j -0x1b4 # j -0x260 # j 0x1bc # j 0x4a8 # j 0x15c # j 0x4a8 # bne t1, t0, 0x110 # bne t1, t0, 0x100 # bne t1, t0, 0xf4 # bne t1, t0, 0x48c # bnez sp, 0x40 # beqz sp, 0x148 # beqz sp, 0x140 # beqz t0, 0x20 # beqz sp, -0xbc # beq tp, t0, 0x78 # beq tp, t0, 8 if op.is_conditional_branch(instruction_text): branch_offset = addr + int(raw_offset, 16) result.add_branch(BranchType.TrueBranch, branch_offset) result.add_branch(BranchType.FalseBranch, addr + instruction_len) else: # UNCONDITIONAL JUMP branch_offset = addr + int(raw_offset, 16) result.add_branch(BranchType.UnconditionalBranch, branch_offset) elif arch == "SPARC": # brz,pn %o3, 0x15240 # bn %icc, -0x46210 # bg,a -0x6927dc # bn,a -0x3cf180 # bn,a -0x6af488 # bn,pn %icc, 0x38e98 # bn,pn %xcc, 0x90fd0 # fbne -0x69bc14 # fbn %fcc0, -0x46b2c # fbn -0x36edec # fbn 0x3b969c # fbn 0x26d94 # fbn 0x7722f0 # fblg,pn %fcc3, 0x390f4 is_branch = 'bn' in instruction_text if is_branch: branch_offset = int(raw_offset, 16) + addr result.add_branch(BranchType.UnconditionalBranch, branch_offset) return result
def get_instruction_info(self, data: bytes, addr: FileOffset) -> InstructionInfo: if not self.inialized_df: self.load_dex() ii = InstructionInfo() # Handle pseudoinstructions if data[0] == 0 and data[1] != 0: if data[1] > 3: ii.length = 2 return ii ii.length = min( self.max_instr_length, self.df.pseudoinstructions[addr]._total_size ) ii.add_branch(BranchType.FunctionReturn) return ii # Handle normal instructions insn_info = self.insns[data[0]] ii.length = insn_info.fmt.insn_len * 2 if insn_info.mnemonic.startswith("return"): ii.add_branch(BranchType.FunctionReturn) elif insn_info.mnemonic == "throw": ii.add_branch(BranchType.ExceptionBranch) # TODO elif insn_info.mnemonic.startswith("goto"): data_to_parse = endian_swap_shorts(data[: 2 * insn_info.fmt.insn_len]) args = parse_with_format(data_to_parse, insn_info.fmt.format_) offset = sign(args["A"], insn_info.fmt.format_.count("A")) ii.add_branch(BranchType.UnconditionalBranch, target=addr + offset * 2) elif ( insn_info.mnemonic == "packed-switch" or insn_info.mnemonic == "sparse-switch" ): data_to_parse = endian_swap_shorts(data[: 2 * insn_info.fmt.insn_len]) args = parse_with_format(data_to_parse, insn_info.fmt.format_) offset = sign(args["B"], insn_info.fmt.format_.count("B")) ii.add_branch(BranchType.UnresolvedBranch) # Adding more than 2 branches causes binja to segfault, so this has # to be handled in LLIL instead. elif insn_info.mnemonic == "fill-array-data": data_to_parse = endian_swap_shorts(data[: 2 * insn_info.fmt.insn_len]) args = parse_with_format(data_to_parse, insn_info.fmt.format_) offset = sign(args["B"], insn_info.fmt.format_.count("B")) ii.add_branch(BranchType.TrueBranch, target=addr + offset * 2) ii.add_branch( BranchType.FalseBranch, target=addr + insn_info.fmt.insn_len * 2 ) elif insn_info.mnemonic.startswith("if-"): data_to_parse = endian_swap_shorts(data[: 2 * insn_info.fmt.insn_len]) args = parse_with_format(data_to_parse, insn_info.fmt.format_) var = "C" if "C" in args else "B" offset = sign(args[var], insn_info.fmt.format_.count(var)) ii.add_branch(BranchType.TrueBranch, target=addr + offset * 2) ii.add_branch( BranchType.FalseBranch, target=addr + insn_info.fmt.insn_len * 2 ) elif insn_info.mnemonic.startswith("invoke-"): if insn_info.mnemonic.startswith("invoke-custom"): log_warn("Resolution of invoke-custom is not implemented") ii.add_branch(BranchType.UnresolvedBranch) else: data_to_parse = endian_swap_shorts(data[: 2 * insn_info.fmt.insn_len]) args = parse_with_format(data_to_parse, insn_info.fmt.format_) meth = self.df.method_ids[args["B"]] if meth._insns_off is not None: ii.add_branch(BranchType.CallDestination, target=meth._insns_off) return ii
def get_instruction_info(self, data, addr): result = InstructionInfo() result.length = 1 if self.vtil == None: try: self.vtil = VTILParser.from_file(get_filename()) except Exception as ex: log_error(str(ex)) return result next_vip, _, _, _, code = find_instruction(addr, self.vtil) if code != None and code.startswith("js"): _, _, true, false = code.split(" ") true = find_block_address(int(true, 16), self.vtil) false = find_block_address(int(false, 16), self.vtil) result.add_branch(BranchType.TrueBranch, true) result.add_branch(BranchType.FalseBranch, false) elif code != None and code.startswith("vxcall"): addr = find_block_address(next_vip[0], self.vtil) result.add_branch(BranchType.UnconditionalBranch, addr) elif code != None and code.startswith("jmp"): if len(next_vip) == 1: addr = find_block_address(next_vip[0], self.vtil) result.add_branch(BranchType.UnconditionalBranch, addr) else: result.add_branch(BranchType.IndirectBranch) for vip in next_vip: result.add_branch(BranchType.UnconditionalBranch, find_block_address(vip, self.vtil)) elif code != None and code.startswith("vexit"): result.add_branch(BranchType.FunctionReturn) return result
def perform_get_instruction_info(self, data, addr): instr, length, operands, flags, value = self.decode_instruction( data, addr) if instr is None: return None result = InstructionInfo() result.length = length opcode = data[0] if instr == 'JR': arg = data[1] dest = arg if arg < 128 else (256 - arg) * (-1) if opcode == 0x28 or opcode == 0x38: result.add_branch(BranchType.TrueBranch, addr + 2 + dest) result.add_branch(BranchType.FalseBranch, addr + 2) elif opcode == 0x20 or opcode == 0x30: result.add_branch(BranchType.TrueBranch, addr + 2) result.add_branch(BranchType.FalseBranch, addr + 2 + dest) else: result.add_branch(BranchType.UnconditionalBranch, addr + 2 + dest) elif instr == 'JP': if opcode == 0xe9: result.add_branch(BranchType.UnconditionalBranch, 0xdead) else: arg = struct.unpack('<H', data[1:3])[0] if opcode == 0xca or opcode == 0xda: result.add_branch(BranchType.TrueBranch, arg) result.add_branch(BranchType.FalseBranch, addr + 3) elif opcode == 0xc2 or opcode == 0xd2: result.add_branch(BranchType.TrueBranch, addr + 3) result.add_branch(BranchType.FalseBranch, arg) else: result.add_branch(BranchType.UnconditionalBranch, arg) elif instr == 'RET': result.add_branch(BranchType.FunctionReturn) elif instr == 'CALL': result.add_branch(BranchType.CallDestination, struct.unpack("<H", data[1:3])[0]) return result
def get_instruction_info(self, data, addr): decoded = decode(data, addr) # on error, return nothing if decoded.status == DECODE_STATUS.ERROR or decoded.len == 0: return None # on non-branching, return length result = InstructionInfo() result.length = decoded.len if decoded.typ != INSTRTYPE.JUMP_CALL_RETURN: return result # jp has several variations if decoded.op == OP.JP: (oper_type, oper_val) = decoded.operands[0] # jp pe,0xDEAD if oper_type == OPER_TYPE.COND: assert decoded.operands[1][0] == OPER_TYPE.ADDR result.add_branch(BranchType.TrueBranch, decoded.operands[1][1]) result.add_branch(BranchType.FalseBranch, addr + decoded.len) # jp (hl); jp (ix); jp (iy) elif oper_type in [ OPER_TYPE.REG_DEREF, OPER_TYPE.MEM_DISPL_IX, OPER_TYPE.MEM_DISPL_IY ]: result.add_branch(BranchType.IndirectBranch) # jp 0xDEAD elif oper_type == OPER_TYPE.ADDR: result.add_branch(BranchType.UnconditionalBranch, oper_val) else: raise Exception('handling JP') # jr can be conditional elif decoded.op == OP.JR: (oper_type, oper_val) = decoded.operands[0] # jr c,0xdf07 if oper_type == OPER_TYPE.COND: assert decoded.operands[1][0] == OPER_TYPE.ADDR result.add_branch(BranchType.TrueBranch, decoded.operands[1][1]) result.add_branch(BranchType.FalseBranch, addr + decoded.len) # jr 0xdf07 elif oper_type == OPER_TYPE.ADDR: result.add_branch(BranchType.UnconditionalBranch, oper_val) else: raise Exception('handling JR') # djnz is implicitly conditional elif decoded.op == OP.DJNZ: (oper_type, oper_val) = decoded.operands[0] assert oper_type == OPER_TYPE.ADDR result.add_branch(BranchType.TrueBranch, oper_val) result.add_branch(BranchType.FalseBranch, addr + decoded.len) # call can be conditional elif decoded.op == OP.CALL: (oper_type, oper_val) = decoded.operands[0] # call c,0xdf07 if oper_type == OPER_TYPE.COND: assert decoded.operands[1][0] == OPER_TYPE.ADDR result.add_branch(BranchType.CallDestination, decoded.operands[1][1]) # call 0xdf07 elif oper_type == OPER_TYPE.ADDR: result.add_branch(BranchType.CallDestination, oper_val) else: raise Exception('handling CALL') # ret can be conditional elif decoded.op == OP.RET: if decoded.operands and decoded.operands[0][0] == OPER_TYPE.COND: # conditional returns dont' end block pass else: result.add_branch(BranchType.FunctionReturn) # ret from interrupts elif decoded.op == OP.RETI or decoded.op == OP.RETN: result.add_branch(BranchType.FunctionReturn) return result
def get_instruction_info(self, data, addr): inst,args = self._get_asm(data, addr) if inst == "ill": return None res = InstructionInfo() res.length = self._inst_length(inst) if inst in ("jx"): if args[0] in self.regs: res.add_branch(BranchType.IndirectBranch) else: res.add_branch(BranchType.UnconditionalBranch, int(args[0], 16)) elif inst in ("callx0", "callx4", "callx8", "callx12"): res.add_branch(BranchType.CallDestination) elif inst in ("ret", "retw", "ret.n", "retw.n"): res.add_branch(BranchType.FunctionReturn) elif inst == "j": res.add_branch(BranchType.UnconditionalBranch, int(args[0], 16)) elif inst in ("call0", "call4", "call8", "call12"): res.add_branch(BranchType.CallDestination, int(args[0], 16)) elif inst in ("loopgtz", "loopnez"): res.add_branch(BranchType.FalseBranch, int(args[1], 16)) res.add_branch(BranchType.TrueBranch, addr + res.length) elif inst in self._branch_instrs or (inst.endswith(".n") and inst[:-2] in self._branch_instrs): res.add_branch(BranchType.TrueBranch, int(args[-1], 16)) res.add_branch(BranchType.FalseBranch, addr + res.length) return res
def perform_get_instruction_info(self, data, addr): instr, operand, length, value = self.decode_instruction(data, addr) if instr is None: return None result = InstructionInfo() result.length = length if instr == "jmp": if operand == ADDR: result.add_branch(BranchType.UnconditionalBranch, struct.unpack("<H", data[1:3])[0]) else: result.add_branch(BranchType.UnresolvedBranch) elif instr == "jsr": result.add_branch(BranchType.CallDestination, struct.unpack("<H", data[1:3])[0]) elif instr in ["rti", "rts"]: result.add_branch(BranchType.FunctionReturn) if instr in ["bcc", "bcs", "beq", "bmi", "bne", "bpl", "bvc", "bvs"]: dest = (addr + 2 + struct.unpack("b", data[1])[0]) & 0xffff result.add_branch(BranchType.TrueBranch, dest) result.add_branch(BranchType.FalseBranch, addr + 2) return result