def emotet_control_flow_unflatten(func_addr, filename): with open(filename, 'rb') as fstream: cont = Container.from_stream(fstream) machine = Machine(cont.arch) mdis = machine.dis_engine(cont.bin_stream, loc_db=cont.loc_db) asmcfg = mdis.dis_multiblock(func_addr) ir_arch = machine.ira(mdis.loc_db) ircfg = ir_arch.new_ircfg_from_asmcfg(asmcfg) state_register = get_state_register(asmcfg, get_loc_key_at(cont.loc_db, func_addr)) if not state_register: print("[-] Function was not obfuscated") return to_patch_offsets = resolve_offsets(state_register, asmcfg, ircfg, ir_arch) to_patch_offsets.sort(key=lambda tup: tup[0]) fix_func_cfg(filename, to_patch_offsets) print("[+] Function was deobfuscated!")
class Block: def __init__(self, raw, address): self.cont = Container.fallback_container(raw + b'\xC3', vm=None, addr=address) self.address = address self.machine = Machine('x86_64') self.mdis = self.machine.dis_engine(self.cont.bin_stream, loc_db=self.cont.loc_db) self.asmcfg = self.mdis.dis_multiblock(self.address) self.head = self.asmcfg.getby_offset(self.address).loc_key self.orignal_ira = self.machine.ira(self.mdis.loc_db) self.orginal_ircfg = self.orignal_ira.new_ircfg_from_asmcfg( self.asmcfg) self.common_simplifier = IRCFGSimplifierCommon(self.orignal_ira) self.common_simplifier.simplify(self.orginal_ircfg, self.head) self.custom_ira1 = IRADelModCallStack(self.mdis.loc_db) self.custom_ira2 = IRAOutRegs(self.mdis.loc_db) self.ircfg = self.custom_ira1.new_ircfg_from_asmcfg(self.asmcfg) self.simplify() def simplify(self): simplifier = IRCFGSimplifierCommon(self.custom_ira1) simplifier.simplify(self.ircfg, self.head) for loc in self.ircfg.leaves(): irblock = self.ircfg.blocks.get(loc) if irblock is None: continue regs = {} for reg in self.custom_ira1.get_out_regs(irblock): regs[reg] = reg assignblks = list(irblock) newAssignBlk = AssignBlock(regs, assignblks[-1].instr) assignblks.append(newAssignBlk) newIrBlock = IRBlock(irblock.loc_key, assignblks) self.ircfg.blocks[loc] = newIrBlock simplifier = CustomIRCFGSimplifierSSA(self.custom_ira2) simplifier.simplify(self.ircfg, self.head)
cont = Container.from_stream(fstream) arch = args.architecture if args.architecture else cont.arch machine = Machine(arch) # Check elements elements = set() regs = machine.mn.regs.all_regs_ids_byname for element in args.element: try: elements.add(regs[element]) except KeyError: raise ValueError("Unknown element '%s'" % element) mdis = machine.dis_engine(cont.bin_stream, dont_dis_nulstart_bloc=True) ir_arch = machine.ira(mdis.loc_db) # Common argument forms init_ctx = {} if args.rename_args: if arch == "x86_32": # StdCall example for i in range(4): e_mem = ExprMem( ExprId("ESP_init", 32) + ExprInt(4 * (i + 1), 32), 32) init_ctx[e_mem] = ExprId("arg%d" % i, 32) # Disassemble the targeted function asmcfg = mdis.dis_multiblock(int(args.func_addr, 0)) # Generate IR
if args.diff: if not new_eips: break if trace.cpu.eip_before == new_eip: new_eip = new_eips.pop(0) print "%d:" % diff_no, diff_no += 1 else: continue if args.ir: loc_db = LocationDB() instr = machine.mn.dis(trace.cpu.opcode, 32) ira = machine.ira(loc_db) ircfg = ira.new_ircfg() ira.add_instr_to_ircfg(instr, ircfg) for lbl, irblock in ircfg.blocks.items(): print irblock.to_string(loc_db) else: print "{takt}:{offset}: {disas}".format( takt=trace.cpu.takt, offset=hex(trace.cpu.eip_before), disas=mnem ), if args.regs: print ';', for reg in args.regs.split(','): print "%s=0x%X," % (reg, trace.cpu.get(reg)), if args.mems: print ';', for mem in args.mems.split(','): try:
start_addr = 0x491aa0 # symbol table loc_db = LocationDB() # open the binary for analysis container = Container.from_stream(open(file_path, 'rb'), loc_db) # cpu abstraction machine = Machine(container.arch) # init disassemble engine mdis = machine.dis_engine(container.bin_stream, loc_db=loc_db) # initialize intermediate representation ira = machine.ira(mdis.loc_db) # disassemble the function at address asm_cfg = mdis.dis_multiblock(start_addr) # translate asm_cfg into ira_cfg ira_cfg = ira.new_ircfg_from_asmcfg(asm_cfg) # set opaque predicate counter opaque_counter = 0 # dictionary of byte patches patches = {} # walk over all basic blocks for basic_block in asm_cfg.blocks:
fdesc = open(sys.argv[1], 'rb') cont = Container.from_stream(fdesc) machine = Machine(cont.arch) mdis = machine.dis_engine(cont.bin_stream, loc_db=cont.loc_db) addr = cont.entry_point asmcfg = mdis.dis_multiblock(addr) ##################################### # End common section # ##################################### # Get an IRA converter # The sub call are modelised by default operators # call_func_ret and call_func_stack ir_arch_analysis = machine.ira(mdis.loc_db) # Get the IR of the asmcfg ircfg_analysis = ir_arch_analysis.new_ircfg_from_asmcfg(asmcfg) # Display each IR basic blocks for irblock in viewvalues(ircfg_analysis.blocks): print(irblock) # Output ir control flow graph in a dot file open('bin_ira_cfg.dot', 'w').write(ircfg_analysis.dot())
cont = Container.from_stream(fstream) arch = args.architecture if args.architecture else cont.arch machine = Machine(arch) # Check elements elements = set() regs = machine.mn.regs.all_regs_ids_byname for element in args.element: try: elements.add(regs[element]) except KeyError: raise ValueError("Unknown element '%s'" % element) mdis = machine.dis_engine(cont.bin_stream, dont_dis_nulstart_bloc=True) ir_arch = machine.ira(mdis.loc_db) # Common argument forms init_ctx = {} if args.rename_args: if arch == "x86_32": # StdCall example for i in range(4): e_mem = ExprMem(ExprId("ESP_init", 32) + ExprInt(4 * (i + 1), 32), 32) init_ctx[e_mem] = ExprId("arg%d" % i, 32) # Disassemble the targeted function asmcfg = mdis.dis_multiblock(int(args.func_addr, 0)) # Generate IR ircfg = ir_arch.new_ircfg_from_asmcfg(asmcfg)
from miasm.analysis.machine import Machine from miasm.core.bin_stream import bin_stream_str from miasm.arch.x86.disasm import dis_x86_32 from miasm.arch.x86.ira import ir_a_x86_64 from miasm.arch.x86.regs import all_regs_ids, all_regs_ids_init # from miasm.ir.symbexec import symbexec from miasm.analysis.cst_propag import add_state, propagate_cst_expr from miasm.expression.simplifications import expr_simp from miasm.analysis.data_flow import dead_simp, \ merge_blocks, remove_empty_assignblks mn = Machine('x86_64') # Create an intermediate representation object loc_db = LocationDB() ira = mn.ira(loc_db) # create an empty ircfg ircfg = ira.new_ircfg() # Binary path and offset of the target function offset = 0x1150 fname = "bin/simple_test.bin" # Get Miasm's binary stream bin_file = open(fname).read() bin_stream = bin_stream_str(bin_file) # Disassemble blocks of the function at 'offset' mdis = mn.dis_engine(bin_stream) disasm = mdis.dis_multiblock(offset)
machine = Machine("x86_32") loc_db = LocationDB() # Assemble and disassemble a MOV ## Ensure that attributes 'offset' and 'l' are set line = machine.mn.fromstring("MOV EAX, EBX", loc_db, 32) asm = machine.mn.asm(line)[0] # Get back block cont = Container.from_string(asm, loc_db = loc_db) mdis = machine.dis_engine(cont.bin_stream, loc_db=loc_db) mdis.lines_wd = 1 asm_block = mdis.dis_block(START_ADDR) # Translate ASM -> IR ira = machine.ira(mdis.loc_db) ircfg = ira.new_ircfg() ira.add_asmblock_to_ircfg(asm_block, ircfg) # Instantiate a Symbolic Execution engine with default value for registers symb = SymbolicExecutionEngine(ira) # Emulate one IR basic block ## Emulation of several basic blocks can be done through .emul_ir_blocks cur_addr = symb.run_at(ircfg, START_ADDR) # Modified elements print('Modified registers:') symb.dump(mems=False) print('Modified memory (should be empty):') symb.dump(ids=False)
class SSAConverter(object): def __init__(self): self.machine = Machine('x86_64') self.dis_engine, self.ira = self.machine.dis_engine, self.machine.ira self.bs = bin_stream_ida() self.mdis = self.dis_engine(self.bs) self.ssa_cache = {} self.ssa_with_state_cache = {} return def Analyze(self, addr, deep=False): todo_list = [] if addr in self.ssa_cache: return self.ssa_cache[addr] asmcfg = self.mdis.dis_multiblock(addr) ira = self.machine.ira(asmcfg.loc_db) try: ircfg = ira.new_ircfg_from_asmcfg(asmcfg) except: # Failed on converting self.ssa_cache[addr] = None return None modified = True while modified: modified = ircfg.simplify(expr_simp) ssa = SSADiGraph(ircfg) ssa.transform(asmcfg.loc_db.get_offset_location(addr)) # for lbl, irblock in ircfg.blocks.items(): # print(irblock.to_string(ircfg.loc_db)) if deep: for lbl, irblock in ircfg.blocks.items(): for blk in irblock.assignblks: for val in blk.values(): if (isinstance(val, ExprOp) and val.op == "call_func_ret" and isinstance(val.args[0], ExprLoc)): callee_addr = asmcfg.loc_db.get_location_offset( val.args[0].loc_key) if callee_addr not in todo_list: todo_list.append(callee_addr) self.ssa_cache[addr] = ircfg if deep: # Recursively analyze functions which are called by initial target function for callee_addr in todo_list: self.Analyze(callee_addr, deep) return ircfg def InitializeState(self, label, state_of_label): initial_state = {} for reg_id in attrib_to_regs[64]: initial_state[reg_id] = reg_id state_of_label[label] = initial_state return def AnalyzeWithState(self, addr, deep=False): if addr in self.ssa_with_state_cache: return self.ssa_with_state_cache[addr] ircfg = self.Analyze(addr, deep) if not ircfg: self.ssa_with_state_cache[addr] = None return None head = ircfg.loc_db.get_offset_location(addr) visited = [] # Set initial state of head state_of_label = {} # label:state self.InitializeState(head, state_of_label) todo_labels = [head] while todo_labels: lbl = todo_labels.pop(0) if lbl in visited: continue else: visited.append(lbl) irblock = ircfg.blocks[lbl] current_state = state_of_label[lbl] # Replace assignblocks to assignblocks with state new_assignblks = [] for assignblk in irblock.assignblks: # Check assignblk is for phi-related blk is_phiblk = False if len(assignblk.values()): sample_expr = assignblk.values()[0] if isinstance(sample_expr, ExprOp) and sample_expr.op == "Phi": is_phiblk = True if not is_phiblk: new_assignblk = AssignBlockWithState( assignblk, current_state.copy()) else: new_assignblk = assignblk new_assignblks.append(new_assignblk) # Process assignblocks and update current state dsts = assignblk.keys() for dst in dsts: if not isinstance(dst, ExprId): continue if dst.name == "IRDst": continue assert ("." in dst.name) org_name = dst.name[:dst.name.find(".")] org_expr = ExprId(org_name, dst.size) assert (org_expr in current_state) current_state[org_expr] = dst irblock._assignblks = tuple(new_assignblks) # Add successors to todo list and update its initial state successor_labels = ircfg.successors(lbl) todo_labels += filter(lambda x: x not in visited, successor_labels) # Update state of successors label with latest current state for successor_label in successor_labels: state_of_label[successor_label] = current_state.copy() self.ssa_with_state_cache[addr] = ircfg return ircfg
open('data.dot', 'w').write(flow_graph.dot()) ad = int(args.addr, 16) loc_db = LocationDB() print('disasm...') cont = Container.from_stream(open(args.filename, 'rb'), loc_db) machine = Machine("x86_32") mdis = machine.dis_engine(cont.bin_stream, loc_db=loc_db) mdis.follow_call = True asmcfg = mdis.dis_multiblock(ad) print('ok') print('generating dataflow graph for:') ir_arch_analysis = machine.ira(loc_db) ircfg = ir_arch_analysis.new_ircfg_from_asmcfg(asmcfg) deadrm = DeadRemoval(ir_arch_analysis) for irblock in viewvalues(ircfg.blocks): print(irblock) if args.symb: block_flow_cb = intra_block_flow_symb else: block_flow_cb = intra_block_flow_raw gen_block_data_flow_graph(ir_arch_analysis, ircfg, ad, block_flow_cb) print('*' * 40) print("""
cont = Container.from_stream(fstream, loc_db) arch = args.architecture if args.architecture else cont.arch machine = Machine(arch) # Check elements elements = set() regs = machine.mn.regs.all_regs_ids_byname for element in args.element: try: elements.add(regs[element]) except KeyError: raise ValueError("Unknown element '%s'" % element) mdis = machine.dis_engine(cont.bin_stream, dont_dis_nulstart_bloc=True, loc_db=loc_db) ir_arch = machine.ira(loc_db) # Common argument forms init_ctx = {} if args.rename_args: if arch == "x86_32": # StdCall example for i in range(4): e_mem = ExprMem(ExprId("ESP_init", 32) + ExprInt(4 * (i + 1), 32), 32) init_ctx[e_mem] = ExprId("arg%d" % i, 32) # Disassemble the targeted function asmcfg = mdis.dis_multiblock(int(args.func_addr, 0)) # Generate IR ircfg = ir_arch.new_ircfg_from_asmcfg(asmcfg)