def enumerate_basicblocks_statically(instructions): """ Return a list of basicblock after statically parsing given instructions """ basicblocks = list() index = 0 # create the first block new_block = False block = BasicBlock(instructions[0].offset, instructions[0], name='block_%x' % instructions[0].offset) for inst in instructions: if new_block: block = BasicBlock(inst.offset, inst, name='block_%x' % inst.offset) new_block = False # add current instruction to the basicblock block.instructions.append(inst) # absolute JUMP if inst.is_branch_unconditional: block.type = BASICBLOCK_UNCONDITIONAL logging.debug("unconditional %x : %s", inst.offset, inst.name) # conditionnal JUMPI elif inst.is_branch_conditional: block.type = BASICBLOCK_CONDITIONAL logging.debug("conditional %x : %s", inst.offset, inst.name) # Halt instruction : RETURN, STOP, ... elif inst.is_halt: # and inst != instructions[-1]: block.type = BASICBLOCK_TERMINAL logging.debug("terminal %x : %s", inst.offset, inst.name) # just falls to the next instruction elif inst != instructions[-1] and \ instructions[index + 1].name == 'JUMPDEST': block.type = BASICBLOCK_FALLTHROUGH logging.debug("fallthrough %x : %s", inst.offset, inst.name) # last instruction of the entire bytecode elif inst == instructions[-1]: block.type = BASICBLOCK_TERMINAL if block.type != BASICBLOCK_DEFAULT: block.end_offset = inst.offset_end block.end_instr = inst basicblocks.append(block) new_block = True index += 1 return basicblocks
def enumerate_basicblocks_statically(instructions): """ Return a list of basicblock after statically parsing given instructions """ basicblocks = list() index = 0 # create the first block new_block = False end_block = False block = BasicBlock(instructions[0].offset, instructions[0], name='block_%x' % instructions[0].offset) for inst in instructions: if new_block: block = BasicBlock(inst.offset, inst, name='block_%x' % inst.offset) new_block = False # add current instruction to the basicblock block.instructions.append(inst) # absolute JUMP if inst.is_branch_unconditional: new_block = True # conditionnal JUMPI elif inst.is_branch_conditional: new_block = True # Halt instruction : RETURN, STOP, ... elif inst.is_halt: # and inst != instructions[-1]: new_block = True # just falls to the next instruction elif inst != instructions[-1] and \ instructions[index + 1].name == 'JUMPDEST': new_block = True # last instruction of the entire bytecode elif inst == instructions[-1]: end_block = True if new_block or end_block: block.end_offset = inst.offset_end block.end_instr = inst basicblocks.append(block) new_block = True end_block = False index += 1 return basicblocks
def enumerate_basicblocks_edges(instructions): """ Return a list of basicblock after statically parsing given instructions """ basicblocks = list() edges = list() xrefs = enumerate_xref(instructions) # create the first block new_block = True for inst in instructions: if new_block: block = BasicBlock(start_offset=inst.offset, start_instr=inst, name='block_%x' % inst.offset) new_block = False # add current instruction to the basicblock block.instructions.append(inst) # next instruction in xrefs list if (inst.offset_end + 1) in xrefs: # absolute JUMP if inst.is_branch_unconditional: edges.append( Edge(block.name, 'block_%x' % xref_of_instr(inst), EDGE_UNCONDITIONAL)) # conditionnal JUMPI / JUMPIF / ... elif inst.is_branch_conditional: edges.append( Edge(block.name, 'block_%x' % xref_of_instr(inst), EDGE_CONDITIONAL_TRUE)) edges.append( Edge(block.name, 'block_%x' % (inst.offset_end + 1), EDGE_CONDITIONAL_FALSE)) # Halt instruction : RETURN, STOP, RET, ... elif inst.is_halt: pass # just falls to the next instruction else: edges.append( Edge(block.name, 'block_%x' % (inst.offset_end + 1), EDGE_FALLTHROUGH)) block.end_offset = inst.offset_end block.end_instr = inst basicblocks.append(block) new_block = True # add the last block basicblocks.append(block) edges = list(set(edges)) return (basicblocks, edges)
def enumerate_basicblocks_statically(instructions): """ Return a list of basicblock after statically parsing given instructions """ basicblocks = list() xrefs = enumerate_xref(instructions) # create the first block new_block = True for inst in instructions: if new_block: block = BasicBlock(start_offset=inst.offset, start_instr=inst, name='block_%x' % inst.offset) new_block = False # add current instruction to the basicblock block.instructions.append(inst) # next instruction in list_ref if (inst.offset_end + 1) in xrefs: # absolute JUMP if inst.is_branch_unconditional: block.type = BASICBLOCK_UNCONDITIONAL logging.debug("unconditional %x : %s", inst.offset, inst.name) # conditionnal JUMPI / JUMPIF / ... elif inst.is_branch_conditional: block.type = BASICBLOCK_CONDITIONAL logging.debug("conditional %x : %s", inst.offset, inst.name) # Halt instruction : RETURN, STOP, RET, ... elif inst.is_halt: # and inst != func.instructions[-1]: block.type = BASICBLOCK_TERMINAL logging.debug("terminal %x : %s", inst.offset, inst.name) # just falls to the next instruction else: block.type = BASICBLOCK_FALLTHROUGH logging.debug("fallthrough %x : %s", inst.offset, inst.name) block.end_offset = inst.offset_end block.end_instr = inst basicblocks.append(block) new_block = True # add the last block basicblocks.append(block) basicblocks = list(set(basicblocks)) return basicblocks
def enum_blocks_edges(function_id, instructions): """ Return a list of basicblock after statically parsing given instructions """ basicblocks = list() edges = list() branches = [] xrefs = [] intent = 0 blocks_tmp = [] blocks_list = [] # remove last instruction that is 'end' for the funtion tt = instructions[:-1] for index, inst in enumerate(tt): if inst.is_block_terminator: start, name = blocks_tmp.pop() blocks_list.append((intent, start, inst.offset_end, name)) intent -= 1 if inst.is_block_starter: # in ['block', 'loop']: blocks_tmp.append((inst.offset, inst.name)) intent += 1 if inst.is_branch: branches.append((intent, inst)) blocks_list = sorted(blocks_list, key=lambda tup: tup[1]) for depth, inst in branches: d2 = int(inst.operand_interpretation.split(' ')[1]) rep = next(((i, s, e, n) for i, s, e, n in blocks_list if (i == (depth - d2) and s < inst.offset and e > inst.offset_end)), None) if rep: i, start, end, name = rep if name == 'loop': value = start # else name == 'block' elif name == 'block': value = end else: value = None inst.xref = value xrefs.append(value) # remove "block" instruction - not usefull graphicaly # instructions = [x for x in instructions if x.name not in ['block', 'loop']] # enumerate blocks new_block = True for index, inst in enumerate(instructions): # creation of a block if new_block: block = BasicBlock(inst.offset, inst, name=format_bb_name(function_id, inst.offset)) new_block = False # add current instruction to the basicblock block.instructions.append(inst) # next instruction is a jump target if index < (len(instructions) - 1) and \ instructions[index + 1].offset in xrefs: new_block = True # absolute jump - br elif inst.is_branch_unconditional: new_block = True # conditionnal jump - br_if elif inst.is_branch_conditional: new_block = True # end of a block elif index < (len(instructions) - 1) and \ inst.name in ['end']: # is_block_terminator new_block = True elif index < (len(instructions) - 1) and \ instructions[index + 1].name == 'else': # is_block_terminator new_block = True # start of a block elif index < (len(instructions) - 1) and \ instructions[index + 1].is_block_starter: new_block = True # last instruction of the bytecode elif inst.offset == instructions[-1].offset: new_block = True if new_block: block.end_offset = inst.offset_end block.end_instr = inst basicblocks.append(block) new_block = True # TODO: detect and remove end instruction that end loop # enumerate edges for index, block in enumerate(basicblocks): # get the last instruction inst = block.end_instr # unconditional jump - br if inst.is_branch_unconditional: edges.append(Edge(block.name, format_bb_name(function_id, inst.xref), EDGE_UNCONDITIONAL)) # conditionnal jump - br_if elif inst.is_branch_conditional: if inst.name == 'if': edges.append(Edge(block.name, format_bb_name(function_id, inst.offset_end + 1), EDGE_CONDITIONAL_TRUE)) # if 'else' in [i.name for i in basicblocks[index + 1].instructions]: # edges.append(Edge(block.name, format_bb_name(function_id, basicblocks[index + 2].start_instr.offset), EDGE_CONDITIONAL_FALSE)) edges.append(Edge(block.name, format_bb_name(function_id, basicblocks[index + 2].start_instr.offset), EDGE_CONDITIONAL_FALSE)) else: edges.append(Edge(block.name, format_bb_name(function_id, inst.xref), EDGE_CONDITIONAL_TRUE)) edges.append(Edge(block.name, format_bb_name(function_id, inst.offset_end + 1), EDGE_CONDITIONAL_FALSE)) elif inst.offset != instructions[-1].offset: # EDGE_FALLTHROUGH edges.append(Edge(block.name, format_bb_name(function_id, inst.offset_end + 1), EDGE_FALLTHROUGH)) # prevent duplicate edges edges = list(set(edges)) return basicblocks, edges
def enumerate_basicblocks_edges(function_id, instructions): """ Return a list of basicblock after statically parsing given instructions """ basicblocks = list() edges = list() labels = [] intent = 0 # find label first for index, inst in enumerate(instructions): if inst.is_block_starter: if inst.name in ['block', 'loop']: intent += 1 elif inst.name in ['end']: if intent > 0: intent -= 1 #tmp_labels.append({'intent': intent, # 'offset': inst.offset_end}) labels.append(inst.offset_end) # print(function_id) # print(labels) ''' #e = [{'intent': 0, 'offset': 15}, {'intent': 1, 'offset': 17}, {'intent': 0, 'offset': 56}] tmp_list = [] for index, x in enumerate(tmp_labels): if x.get('intent') == 0: labels += tmp_list[::-1] tmp_list = [] tmp_list.append(x.get('offset')) labels += tmp_list[::-1] print(labels) ''' # remove "block" instruction - not usefull graphicaly instructions = [x for x in instructions if x.name not in ['block', 'loop']] # create the first block new_block = False end_block = False block = BasicBlock(instructions[0].offset, instructions[0], name=format_bb_name(function_id, instructions[0].offset)) for index, inst in enumerate(instructions): if new_block: block = BasicBlock(inst.offset, inst, name=format_bb_name(function_id, inst.offset)) new_block = False # add current instruction to the basicblock block.instructions.append(inst) # absolute jump - br # br is *always* followed by end instruction if inst.is_branch_unconditional: end_block = True jump_offset = int(inst.operand_interpretation.split(' ')[1]) if instructions[index + 1].name == 'end': end_block = False edges.append( Edge(block.name, format_bb_name(function_id, labels[jump_offset] + 1), EDGE_UNCONDITIONAL)) # conditionnal jump - br_if elif inst.is_branch_conditional: end_block = True jump_offset = int(inst.operand_interpretation.split(' ')[1]) edges.append( Edge(block.name, format_bb_name(function_id, labels[jump_offset] + 1), EDGE_CONDITIONAL_TRUE)) edges.append( Edge( block.name, format_bb_name(function_id, instructions[index + 1].offset), EDGE_CONDITIONAL_FALSE)) # end of a block elif index < (len(instructions) - 1) and \ inst.name in ['end', 'else']: # is_block_terminator end_block = True if not instructions[index - 1].is_branch_unconditional: edges.append( Edge( block.name, format_bb_name(function_id, instructions[index + 1].offset), EDGE_FALLTHROUGH)) # start of a block elif index < (len(instructions) - 1) and \ instructions[index + 1].is_block_starter: end_block = True edges.append( Edge( block.name, format_bb_name(function_id, instructions[index + 1].offset), EDGE_FALLTHROUGH)) # last instruction of the entire bytecode elif inst == instructions[-1]: end_block = True if end_block: block.end_offset = inst.offset_end block.end_instr = inst basicblocks.append(block) new_block = True end_block = False edges = list(set(edges)) return basicblocks, edges