def update_flags_from_il(cpu, il): # FIXME what about get_flag_condition_low_level_il from binaryninja.lowlevelil import LowLevelILInstruction flags = cpu.arch.flags_written_by_flag_write_type.get(il.flags) if flags is None: return func = cpu.disasm.current_llil_func # FIXME normally we would pass il.operands but binja has a bug here operands = [i for i, _ in enumerate(il.operands)] for f in flags: expr = cpu.arch.get_flag_write_low_level_il( il.operation, il.size, il.flags, f, operands, func.low_level_il) flag_il = LowLevelILInstruction(func, expr.index) # FIXME properly invoke the implementation op_name = str(flag_il.operation).split(".")[1][len("LLIL_"):] if op_name == "UNIMPL": continue implementation = getattr(cpu, op_name) # flag_il.operands have indexes, involving the original operands. # E.g., for xor.d{*}(eax, eax), invoking `print flag_il.operands` # we get [<il: 0 ^ 1>, <il: 0>] # where 0 and 1 are the indexes. We need the operands to be # 'eax'. 'eax' flop = [] for i, o in enumerate(flag_il.operands): for j, x in enumerate(o.operands): x = il.operands[int(str(x))].op o.operands[j] = x flop.append(o) flag_il.operands = [ BinjaOperand(cpu, flag_il, x) for x in flag_il.operands ] res = implementation(*flag_il.operands)
def perform_get_instruction_low_level_il(self, data, addr, il): log('Asking to decode %d bytes at 0x%x' % (len(data), addr)) valid, instr = get_instruction(data[0:8], addr) if not valid: log('*********** Tried an failed **********') # This is _EXCEEDINGLY_ important to return on failure. # Things will break in creative ways if anything other than None # is returned for invalid data return None if instr.opcode not in InstructionLLIL: log('Adding il.undefined()') # il.append(il.unimplemented()) il.append(il.undefined()) else: il_exp = InstructionLLIL[instr.opcode](il, instr) if il_exp is not None: il.append(il_exp) log('appended: %s' % LowLevelILInstruction(il, il_exp.index)) else: log('Failed to generate il') log('Full IL Decode was successful len(il): %d' % len(il)) return 8
def IF(cpu, condition, true, false): import binaryninja.enums as enums from binaryninja.lowlevelil import LowLevelILInstruction il = cpu.disasm.disasm_il cond = condition.op.operands[0].op exp = cpu.arch.get_default_flag_condition_low_level_il( cond, il.function) cond_il = LowLevelILInstruction(cpu.disasm.current_llil_func, exp.index) implementation = getattr(cpu, cond_il.operation.name[len("LLIL_"):]) cond_il.operands = [ BinjaOperand(cpu, cond_il, x) for x in cond_il.operands ] res = implementation(*cond_il.operands) idx = true.op if res else false.op assert isinstance(idx, long) try: next_il = cpu.disasm.current_llil_func[idx] except IndexError as e: # If we got an index error this means that we have the true # branch executing one insn followed by a GOTO, and the false # branch is outside the current_llil_func and is a JUMP # FIXME verify that this is true cpu.PC += cpu.disasm.disasm_insn_size return # if we have a (real) instruction from the IF family, the next # instruction should have an address different than the current PC if next_il.address != cpu.disasm.current_pc: cpu.PC = next_il.address + cpu.disasm.entry_point_diff return # The next IL instruction has the same PC. Probably a real assembly # instruction was resolved into multiple IL instructions. Clear the # queue and execute them here last_op_in_queue = cpu.disasm.il_queue[-1][1].operation assert (last_op_in_queue == enums.LowLevelILOperation.LLIL_GOTO or last_op_in_queue == enums.LowLevelILOperation.LLIL_JUMP or last_op_in_queue == enums.LowLevelILOperation.LLIL_JUMP_TO) del cpu.disasm.il_queue[:] # the sequence of instructions sharing the same PC includes both the # True and False branches. If we start executing at the True branch, # make sure we don't also execute on the False branch break_idx = true.op if not res else false.op while idx != break_idx and next_il.address == cpu.disasm.current_pc: goto_addr = None implementation = getattr(cpu, next_il.operation.name[len("LLIL_"):]) next_il.operands = [ BinjaOperand(cpu, next_il, x) for x in next_il.operands ] cpu.disasm.insn_size = next_il.size goto_addr = implementation(*next_il.operands) try: idx += 1 next_il = cpu.disasm.current_llil_func[idx] except IndexError as e: break assert goto_addr is not None cpu.PC = goto_addr