コード例 #1
0
class P2Align(Line):
    __slots__ = ('section', 'offset', 'bytelen',
        'binary', 'symbols', 'line', 'pic', 'stack', 'dead')
    def __init__(self, symbols, line, **kargs):
        Line.__init__(self, symbols)
        self.line = line
        if 'section' in kargs: self.offset = kargs['section']
        if 'offset' in kargs: self.offset = kargs['offset']
        if 'binary' in kargs: self.binary = kargs['binary']
        if 'binary' in kargs: self.bytelen = len(self.binary)
    def txt(self, asm_format=None):
        if asm_format is None:
            asm_format = self.symbols.arch.asm_format
        if asm_format == 'raw' and hasattr(self, 'binary'):
            from plasmasm.python.compatibility import hexbytes
            return "[.]nop %s[%s]" % ("".join(hexbytes(self.binary)), self.line)
            return "%s [%s]" % (self.line, "".join(hexbytes(self.binary)))
        return self.line
    def pack(self):
        if hasattr(self, 'binary'):
            return self.binary
    opname = 'nop'
    flow = None
    CPU = None
    rw = (set(), set())
    def reg_name(self, r):
        return self.symbols.arch.reg_name(r)
    def reg_from_name(self, r):
        return self.symbols.arch.reg_from_name(r)
    def copy(self):
        new = self.__class__(self.symbols, self.line)
        if hasattr(self,'offset'): new.offset = self.offset
        if hasattr(self,'binary'): new.binary = self.binary
        if hasattr(self,'dead'): new.dead = self.dead.copy()
        return new
コード例 #2
0
class Instruction(Line):
    __slots__ = ('line', 'opname', 'operands')
    CPU = None

    def __init__(self, symbols):
        Line.__init__(self, symbols)

    def from_txt(self, line):
        if line.startswith('\t'):
            line = line[1:]
        self.line = line
        r = re.match(r'\s*(\S+)\s*(.*)', line)
        if r:
            self.opname = r.groups()[0]
            self.operands = [s.strip(' ') for s in r.groups()[1].split(',')]
        return self

    def txt(self, asm_format=None):
        return self.line

    def set_asm_format(self, asm_format):
        pass

    set_asm_format = classmethod(set_asm_format)
    asm_format = None
    # Stubs... TODO
    rw = (set(), set())
コード例 #3
0
ファイル: helper.py プロジェクト: LRGH/plasmasm
def helper_parse(pool, entrypoints):
    # Parts of the binary file should be parsed
    from plasmasm.parse_bin import create_text_bloc
    job_done = set([(_.section, _.address) for _ in pool.blocs])
    lab_done = set(pool.blocs)
    for section, address in entrypoints:
        label = pool.find_symbol(address=address, section=section)
        label.insert_bloc()
        create_text_bloc(label, lab_done, job_done, set())
コード例 #4
0
ファイル: dead_registers.py プロジェクト: LRGH/plasmasm
def set_dead_reg(l, d):
    r, w = l.rw[0], l.rw[1]
    if l.CPU == 'I386' and hasattr(l, 'miasm'):
        from miasmX.expression import expression
        w = set([reg for reg in w if isinstance(reg, expression.ExprId)])
    else:
        w = set([reg for reg in w if not str(reg) in never_dead])
    l.dead = d.union(w).difference(r)
    pic_dead_non_collision(l)
コード例 #5
0
ファイル: symbols.py プロジェクト: LRGH/plasmasm
 def __init__(self, symbols, name):
     if not type(name) in [int, str]:
         raise ValueError(
             "Symbol name shoud be int or str, rather than %s" % type(name))
     self.symbols = symbols
     self.name = name
     self.nxt = None
     self._cfg = None
     self.graph = (set(), set())
     self.ender = None
     self.flow = None
     self._bloc_idx = None
     self.stack = Stack(self)
コード例 #6
0
ファイル: symbols.py プロジェクト: LRGH/plasmasm
 def set_cfg(self, cfg, graph0=None):
     if not type(cfg) in [tuple, list, set]:
         raise ValueError("CFG of %s should be a list, not %s" %
                          (self, cfg))
     self._cfg = tuple(cfg)
     # Cleanup the 'prv' of next nodes
     for label in self.graph[0]:
         label.graph[1].remove(self)
     # Reconstruct the 'prv' of next nodes
     if graph0 is None: graph0 = set(self.cfg).difference(set([None]))
     self.graph = (graph0, self.graph[1])
     for label in self.graph[0]:
         label.graph[1].add(self)
コード例 #7
0
def stack_shift(value, imm, no_copy=False):
    registers, positions = value
    if registers is False: # top
        return value
    if imm is None:
        # Happens when the source is C++, e.g. 'subq    %rax, %rsp'
        return False, set()
    if no_copy and imm == 0:
        return value
    new_pos = set()
    for pos in positions:
        new_pos.add(pos+imm)
    new_reg = {}
    for k in registers:
        new_reg[k] = set([imm+_ for _ in registers[k]])
    return new_reg, new_pos
コード例 #8
0
def stack_tracking(label, value):
    # Analyzes the use of the red zone.
    # Cf. http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/
    # Without this analysis, we cannot do push/pop on x64 without risking
    # to overwrite values in the red zone.
    # A value line.stack is created, which contains a pair:
    # - registers that contain (a shifted value of) the base address of the
    #   red zone (one may store rsp+imm in rbp and afterwards access elements
    #   in the red zone using an offset to rbp bigger than imm).
    #   Usually, it is empty or { %rbp => imm } which means
    #   that %rbp == %rsp+imm
    # - positions in the red zone that are used after the instruction has
    #   been executed (multiple of 8).
    # Functions start with 'pushq' which means the stack can be modifed, but
    # at some point there is a 'subq $imm, rsp' and things may become ugly.
    if value is None: value = {}, set()
    if not hasattr(label, 'lines'):
        return value
    # Special case:
    # Sometimes %rsp+shift is copied in %rdi
    # This is used for string copy, we need to know the size of
    # the string (in ecx) to set many positions as being accessed
    str_copy = {}
    for line in label.lines:
        # Not instructions
        if isinstance(line, Constant):
            continue
        value = update_value(line, value, str_copy)
        line.stack = value
    return value
コード例 #9
0
ファイル: dead_registers.py プロジェクト: LRGH/plasmasm
def add_line_update_dead(label, line, pos=None, dead_from=False):
    # NB: this function updates dead registers, but does not update
    # the CFG, even if 'line' is a jmp/jcc/ret/call, because it might
    # be an obscure predicate and the CFG may not correspond to a local
    # analysis of 'line'
    if isinstance(line, str):
        line = label.symbols.arch(label.symbols).from_txt(line)
        line.do_post_init()
    if pos is None: NEVER
    if dead_from == False:
        if pos < len(label.lines):
            dead = label.lines[pos].dead
        else:
            nxt_bloc = get_dst_bloc(label)
            if nxt_bloc is None: dead = set()
            else: dead = get_dead_bloc(nxt_bloc)
        set_dead_reg(line, dead)
    else:
        line.dead = dead_from.dead.copy()
    label.addline(line, pos=pos)
    if len(label.lines) >= 3 and not label.lines[-3].flow in [
            None, False
    ] and label.lines[-3].flow.startswith('D.'):
        # Line added in a delay slot
        label.lines[-3], label.lines[-2] = label.lines[-2], label.lines[-3]
    return line
コード例 #10
0
def get_instr_expr(l, my_eip, args=None, segm_to_do=set()):
    if args is None:
        args = []
    for x in l.arg:
        args.append(dict_to_Expr(x, l.m.modifs, l.opmode, l.admode,
                                 segm_to_do))
    l.arg_expr = args
    return get_instr_expr_args(l, args, my_eip)
コード例 #11
0
ファイル: symbols.py プロジェクト: LRGH/plasmasm
 def __init__(self):
     self.symbols = []
     self.symbols_byname = {}
     self.symbols_byaddress = {}
     self.blocs = []
     self.bloc_set = set()
     self.sections = Sections()
     self._numeric_label_ = 0
     self._precomputed = {}
     self.meta = {}
コード例 #12
0
def stack_merge(v1, v2):
    if v1 == v2:
        return v1
    if v2 is None:
        return v1
    if v1 is None:
        return v2
    r1, p1 = v1
    r2, p2 = v2
    if r1 is False or r2 is False: # top
        return False, set()
    if p2 != set(): p1 = p1.union(p2)
    if r1 != r2:
        new_reg = {}
        for k in r1:
            if k in r2: new_reg[k] = r1[k].union(r2[k])
            else:       new_reg[k] = r1[k]
        for k in r2:
            if not k in r1: new_reg[k] = r2[k]
        r1 = new_reg
    return r1, p1
コード例 #13
0
ファイル: symbols.py プロジェクト: LRGH/plasmasm
 def flatten_once(self):
     # Outputs the list of all known possible pairs (top, stack)
     stacks = self.stacks[:]
     marked = set()
     out = []
     while len(stacks) > 0:
         top, stack = stacks.pop()
         if isinstance(top, StackTopVoid):
             if not stack in marked:
                 marked.add(stack)
                 for _ in stack.stacks:
                     if not _ in stacks:
                         stacks.append(_)
         else:
             out.append((top, stack))
     return out
コード例 #14
0
ファイル: dead_registers.py プロジェクト: LRGH/plasmasm
def get_dst_bloc(label):
    dst = get_dst(label)
    seen = set()
    while True:
        if dst is None: return None
        if not hasattr(dst, 'lines'): return None
        if len(dst.lines) > 0: return dst
        if dst in seen:
            # This can happen, e.g. when a bloc
            #   label:
            #     jmp label
            # is modified by 'replace_jmp_pushret'
            # because temporarily it becomes an empty bloc
            # in a loop with itself
            return None
        seen.add(dst)
        dst = get_dst(dst)
コード例 #15
0
ファイル: dead_registers.py プロジェクト: LRGH/plasmasm
def pic_dead_non_collision(l):
    if not 'PIC' in l.symbols.get_meta(): return
    if not hasattr(l, 'pic'): return
    # For PIC code, even if the PIC register is written,
    # don't consider it as dead
    # The other possibility would have been to modify the PIC
    # register list when the register is dead, but this option
    # is not chosen because we need PIC registers for many
    # obfuscation primitives
    pic = set()
    for reg in l.pic[1]:
        if 'ebp' in reg: pic.add('ebp')
        if 'esp' in reg: pic.add('esp')
        else: pic.add(reg)
    for d_reg in list(l.dead):
        if str(d_reg) in pic:
            l.dead.discard(d_reg)
コード例 #16
0
ファイル: symbols.py プロジェクト: LRGH/plasmasm
 def flatten_recursive(self, marked=None):
     # Outputs the list of all known possible stacks
     if marked is None: marked = set()
     if self in marked: return []
     out = []
     marked.add(self)
     for pos, stk in sorted(self.stacks, key=lambda _: str(_[0])):
         stk = stk.flatten_recursive(marked)
         if stk == []:
             if not isinstance(pos, StackTopVoid):
                 out.append([pos])
         else:
             if isinstance(pos, StackTopVoid):
                 pos = []
             else:
                 pos = [pos]
             for s in stk:
                 out.append(pos + s)
     return out
コード例 #17
0
ファイル: dead_registers.py プロジェクト: LRGH/plasmasm
def set_dead_bloc(label, marked_blocs):
    if label in marked_blocs:
        if marked_blocs[label] == 2: return
        marked_blocs[label] += 1
    else:
        marked_blocs[label] = 1
    # Don't compute dead registers for data blocs or empty blocs
    if len(label.lines) == 0:
        return
    if getattr(label.lines[-1], 'flow', False) == False:
        return
    if getattr(label.lines[0], 'flow', False) == False:
        return
    # If the flow can continue to only one other line, then we compute
    # its dead registers
    nxt_bloc = get_dst_bloc(label)
    if nxt_bloc in label.symbols.bloc_set:
        set_dead_bloc(nxt_bloc, marked_blocs)
    d = get_dead_bloc(nxt_bloc)
    if d is None: d = set()
    # Update dead registers in the bloc
    lines = list(reversed(label.lines))
    if not label.flow in [None, False] and label.flow.startswith('D.'):
        # Delayed slot => swap the last lines
        lines[0], lines[1] = lines[1], lines[0]
        # We may want to test if it is a SPARC cpu
        # Annul bit => delay slot not executed unless conditional branch taken
        if label.flow in ['D.jmp', 'D.jcc']:
            set_dead_reg(lines[0], d)
            d = lines[0].dead
            set_dead_reg(lines[1], d)
            lines[0:2] = []
    for idx, l in enumerate(lines):
        set_dead_reg(l, d)
        set_dead_PIC(lines, idx)
        d = l.dead
コード例 #18
0
def propagate_cfg(symbols, analysis):
    # Per object, propagatation by applying 'analysis' once to each basic
    # bloc, following the CFG.
    def follow_cfg(label, done):
        todo = [ (label, None) ]
        while len(todo):
            label, value = todo.pop(0)
            if label in done: continue
            done.add(label)
            value = analysis(label, value)
            if label.flow in ['sub', 'D.sub']:
                # Don't follow function calls
                todo.append((label.nxt, value))
            else:
                todo.extend([(_, value) for _ in label.cfg])
        return done
    done = set([None]) # Only once per basic bloc
    for o in symbols.object_list():
        follow_cfg(o[0], done)
    # Split in objects may be erroneous, local functions may be forgotten
    # cf. trees.s from pari 2.5.5 / clang 700 64-bit
    for label in symbols.blocs:
        if not label in done:
            follow_cfg(label, done)
コード例 #19
0
ファイル: SPARC.py プロジェクト: LRGH/plasmasm
# Copyright (C) 2011-2020 Airbus, [email protected]
containers = { 'ELF': 'SPARC' }
try:
    from plasmasm.python.compatibility import set
except ImportError:
    pass
opcodes = {
    'SPARC': set(['add', 'addcc', 'addx', 'and', 'andcc', 'b', 'ba', 'be', 'be,a', 'bg', 'bge', 'bgu', 'bl', 'ble', 'ble,a', 'blu', 'bne', 'bne,a', 'bset', 'call', 'clr', 'cmp', 'dec', 'inc', 'jmp', 'ld', 'ldd', 'ldsb', 'ldub', 'lduh', 'mov', 'nop', 'or', 'restore', 'retl', 'save', 'sdiv', 'sethi', 'sll', 'smul', 'sra', 'srl', 'st', 'stb', 'std', 'sub', 'subcc', 'udiv', 'wr', 'xor']),
}
コード例 #20
0
ファイル: expression.py プロジェクト: LRGH/miasmX
 def get_r(self, mem_read=False):
     r = set()
     for a in self.args:
         r = r.union(a[0].get_r(mem_read))
     return r
コード例 #21
0
 def labels(self):
     ''' labels that are referenced in the line '''
     return set([v for v in self.value if hasattr(v, 'name')])
コード例 #22
0
        'fpatan', 'fprem', 'fprem1', 'fptan',  'fwait', 'fxam', 'fxch',
        'fxrstor', 'fxsave',
        'in', 'jmp', 'lahf', 'ldmxcsr', 'leave', 'lfence', 'lock', 'lodsw',
        'mfence', 'nop', 'out', 
        'rep', 'ret', 'sahf', 'scasb', 'scasw', 'sfence', 'stc', 'std', 'sti',
        'stmxcsr', 'stosb', 'stosl', 'stosw', 'ud2', 'wait',
        'xrstor', 'xsave', 'xsaveopt',
    ]

opcodes = {
    'I386-intel': set(MMX + NOSUFFIX + TEST + ['.p2align',
        'adc', 'add', 'and', 'bsf', 'bsr', 'bswap', 'bt',
        'call', 'cbw', 'cdq', 'cmc', 'cmp', 'cmpsw', 'cwd', 'cwde',
        'dec', 'div',
        'fadd', 'faddp', 'fcmovb', 'fcmovbe', 'fcmove', 'fcmovnb', 'fcmovnbe', 'fcmovne', 'fcmovnp', 'fcmovnu', 'fcmovu', 'fdiv', 'fdivp', 'fdivr', 'fdivrp',
        'fiadd', 'fidiv', 'fidivr', 'fild', 'fimul', 'fist', 'fistp', 'fisttp', 'fisub', 'fisubr', 'fmul', 'fmulp',
        'fsqrt', 'fst', 'fstp', 'fsub', 'fsubp', 'fsubr', 'fsubrp', 'fucom', 'fucomi', 'fucomip', 'fucomp', 'fucompp',
        'idiv', 'imul', 'inc',
        'lea', 'mov', 'movsw', 'movsx', 'movzx', 'mul', 'neg', 'not', 'or',
        'pop', 'popfd', 'push', 'pushfd', 'repz', 'repnz', 'rol', 'ror',
        'sal', 'sar', 'sbb', 'shl', 'shld', 'shr', 'shrd', 'sub',
        'test', 'xadd', 'xchg', 'xor']),
    'I386-att': set(MMX + NOSUFFIX + TEST + TEST_att + ['cvtsi2sdl', 'cvtsi2ssl', '.p2align',
        'adcl', 'addb', 'addl', 'addw', 'andb', 'andl', 'andw', 'bsfl', 'bsrl', 'bswap', 'bswapl', 'btl', 'btsl',
        'call', 'calll', 'cbtw', 'cltd', 'cmpb', 'cmpl', 'cmpsb', 'cmpsw', 'cmpw', 'cwtd', 'cwtl',
        'decb', 'decl', 'decw', 'divb', 'divl', 'divw',
        'fadd', 'faddl', 'faddp', 'fadds', 'fcmovb', 'fcmovbe', 'fcmove', 'fcmovnb', 'fcmovnbe', 'fcmovne', 'fcmovnu', 'fcmovu', 'fcom', 'fcomi', 'fcomip', 'fcomp', 'fcompp', 'fdiv', 'fdivl', 'fdivp', 'fdivr', 'fdivrl', 'fdivrp', 'fdivrs', 'fdivs',
        'fiaddl', 'fidivl', 'fidivrl', 'fildl', 'fildll', 'fildq', 'filds', 'fimull', 'fistps', 'fistl', 'fistpl', 'fistpll', 'fistpq', 'fisttpl', 'fisttpll', 'fisttpq', 'fisubl', 'fisubrl', 'fldl', 'flds', 'fldt', 'fmul', 'fmull', 'fmulp', 'fmuls',
        'fsqrt', 'fstl', 'fstp', 'fstpl', 'fstps', 'fstpt', 'fsts', 'fsub', 'fsubl', 'fsubp', 'fsubr', 'fsubrl', 'fsubrp', 'fsubrs', 'fsubs', 'fucom', 'fucomi', 'fucomip', 'fucomp', 'fucompi', 'fucompp',
        'idivb', 'idivl', 'imull', 'imulw', 'incb', 'incl', 'incw', 'insb', 'insd', 'insw', 'jmpl',
        'leal', 'lgdtl', 'ljmp', 'movb', 'movl', 'movsb', 'movsbl', 'movsbw', 'movsl', 'movsw', 'movswl', 'movw', 'movzbl', 'movzbw', 'movzwl', 'mulb', 'mull', 'negb', 'negl', 'notb', 'notl', 'notw', 'orb', 'orl', 'orw', 'outsb', 'outsd', 'outsw',
        'popfl', 'popl', 'pushfl', 'pushl', 'pushw', 'repnz', 'repz', 'retl', 'rolb', 'roll', 'rolw', 'rorb', 'rorl', 'rorw',
コード例 #23
0
ファイル: expression.py プロジェクト: LRGH/miasmX
def get_expr_ids(e):
    ids = set()
    e.visit(lambda x: get_expr_ids_visit(x, ids))
    return ids
コード例 #24
0
def guess_asm_cpu(symbols):
    from plasmasm import arch
    cpu_opcodes = {}
    for cpu in arch.CPUs:
        cpu_opcodes.update(arch.import_cpu_meta(cpu).opcodes)
    opcodes = set()
    operands = set()
    for label in symbols.symbols:
        for line in getattr(label, 'lines', []):
            if not isinstance(line, Instruction):
                continue
            opcodes.add(line.opname)
            operands.update(line.operands)
    if len(operands) == 0:
        return None
    delta = []
    for cpu in cpu_opcodes:
        delta.append((len(opcodes.difference(cpu_opcodes[cpu])), cpu))
    delta.sort()
    cpu = delta[0][1]
    if delta[0][0] == 0 and delta[1][0] != 0:
        return cpu
    if delta[0][0] == delta[1][0]:
        val = delta[0][0]
        cpu = [x for n, x in delta if n == val]
        # Filter possible cpu by looking at operands
        # Necessary to make the difference between I386 and X64
        cpu_base = set([_ for _ in cpu if not '-' in _])
        cpu_base.update(set([_[:_.find('-')] for _ in cpu if '-' in _]))
        for op in operands:
            if op in ('%g0', '%g1', '%o0'):
                NON_REGRESSION_FOUND
                cpu_base.intersection_update(set(['SPARC']))
            for reg in [
                    'rax', 'rbx', 'rcx', 'rdx', 'rbp', 'rsp', 'rsi', 'rdi',
                    'rip'
            ] + ['r%d' % _ for _ in range(8, 16)]:
                if op in (reg, '%' + reg, '(%' + reg + ')'):
                    cpu_base.intersection_update(set(['X64']))
                if '%' + reg in op or '[' + reg in op:
                    cpu_base.intersection_update(set(['X64']))
            if op in ('eax', '%eax'):
                cpu_base.intersection_update(set(['X64', 'I386']))
            if len(cpu_base) <= 1: break
        if cpu_base == set(['I386', 'X64']):
            # Sometimes an assembly file generated for 64-bit architecture
            # is also a valid 32-bit assembly; but we need to know which
            # was the target architecture, e.g. obfuscation will be different
            if '.rodata.str1.8' in symbols.sections.asm_name:
                # 32-bit uses .rodata.str1.4
                NON_REGRESSION_FOUND
                cpu_base = set(['X64'])
            else:
                cpu_base = set(['I386'])
        # Get back to full CPU description (with AT&T/Intel syntax)
        def startswith(cpu, cpu_base):
            # str.startswith(tuple) is invalid for python 2.3
            for _ in cpu_base:
                if cpu.startswith(_): return True
            return False

        cpu = [_ for _ in cpu if startswith(_, cpu_base)]
        if len(cpu) == 1:
            return cpu[0]
        if set(cpu) == set(['I386-att', 'I386-intel']):
            if not 'format' in symbols.get_meta():
                return 'I386-att'
            else:
                NON_REGRESSION_FOUND
                return 'I386-intel'
        log.warning("Guessing cpu: %s are matching", cpu)
        return cpu[0]
    diff = opcodes.difference(cpu_opcodes[cpu])
    if len(diff) * 2 > len(opcodes):
        log.warning(
            "Guessing cpu: best guess is %s but too many opcodes are missing",
            cpu)
        return None
    log.warning("Guessing cpu %s; additional opcodes are %s", cpu,
                sorted(list(diff)))
    return cpu
コード例 #25
0
ファイル: symbols.py プロジェクト: LRGH/plasmasm
 def compute_dst(self):
     if not hasattr(self, 'lines') or not None in self.cfg:
         return None
     if not section_type(self.section) in ['text', 'plt']:
         return None
     if len(self.lines) == 0:
         return None
     idx = -1
     if len(self.lines) > 1 and self.lines[-2].flow is not None:
         idx = -2
     instr = self.lines[idx]
     if instr.flow == False:
         return None
     if instr.flow.endswith('ret'):
         return None
     log.debug("dst of '%s' at (%s)", self, instr)
     if hasattr(instr, 'dst') and \
    len(instr.dst) >= 1 and \
        isinstance(instr.dst[0], list):
         # Non-resolved switch table
         table = instr.dst[0][0]
         if not hasattr(table, 'lines'):
             log.debug("SWITCH TABLE AT LABEL %s, empty", table)
             return None
         if not hasattr(table, 'switch_table'):
             log.debug("SWITCH TABLE AT LABEL %s, %d lines, no base", table,
                       len(table.lines))
             instr.dst = []
             for line in table.lines:
                 if not hasattr(line, 'value'):
                     assert line.__class__.__name__ == 'ConstantZero'
                     break
                 if not isinstance(line.value[0], Symbol):
                     break
                 instr.dst.append(line.value[0])
             return instr
         switch_base, ptr_size, tbl_size = table.switch_table
         if hasattr(table, 'size'):
             log.debug("SWITCH TABLE AT LABEL %s, %d lines, complete",
                       table, len(table.lines))
             instr.dst = []
             base = "-%s" % switch_base
             for line in table.lines:
                 label = line.value[0]
                 assert label.name.endswith(base)
                 label = label.name[:-len(base)]
                 label = self.symbols.find_symbol(name=label)
                 instr.dst.append(label)
             return instr
         log.debug("SWITCH TABLE AT LABEL %s, %d lines, incomplete", table,
                   len(table.lines))
         if tbl_size is not None:
             log.debug("    tbl_size=%s", tbl_size)
         return None
     in_str, _ = self.symbols.streams[self.section]
     # Note that the performance impact is HUGE
     # e.g. parsing examples/x64_linux/k9-fPIC.o takes 39s instead of 3s
     # TODO: recompute only if the ancestors of 'self' have changed
     # or if the target switch table has changed
     # This should gain a lot of time
     lines = self.lines  # May be extended with previous blocs
     msg, val = instr.evaluate_lines(lines, in_str)
     cur_bloc = self
     while val == [None]:
         # If the analysis has not been conclusive, and if there is
         # only one ancestor bloc, then we emulate it too
         ancestors = cur_bloc.get_ancestors()
         log.debug("Ancestors %s", [str(_) for _ in ancestors])
         if len(ancestors) != 1:
             break
         cur_bloc = ancestors[0]
         if not hasattr(cur_bloc, 'lines'):
             break
         lines = cur_bloc.lines + lines
         msg, val = instr.evaluate_lines(lines, in_str)
     self.del_data('cfg_warn')  # Warning displayed only at the end
     if val == [None]:
         msg, retval, machine = msg
         self.set_data('cfg_warn', (instr, msg, retval))
         log.debug("Failed to compute dst of '%s' at (%s)", self, instr)
         log.debug("... %s (TODO) '%s'", msg, retval)
         log.debug("    MEMORY is")
         for mem in machine:
             log.debug("    - %s", mem)
     elif val == 'TABLE':
         # Table found, but data section not parsed yet
         log.debug("... %s %s", msg, val)
         val = [None]
     elif len(val) == 1:
         log.debug("... %s '%s'", msg, val[0])
     else:
         log.debug("... %s %s", msg, [str(v) for v in val])
     if val == instr.dst:
         # Nothing changed
         return None
     if len(val) >= len(instr.dst):
         # New destinations found
         # Note that 'None' in the destination list means that the
         # analysis is incomplete
         instr.dst = val
         return instr
     if set(val + [None]) == set(instr.dst):
         # Destination list completed
         # e.g. when the end of a switch table has been found
         # Recompute CFG to delete None
         instr.dst = val
         return instr
     if set(val) < set(instr.dst):
         # In some rare cases, compute_dst generated an element in a
         # switch table, which changes the CFG before this instruction,
         # and makes our backward analysis fail because we go backwards
         # only if a basic has a unique ancestor.
         return None
     # Should not happen, it means that the new destination list
     # is different from the old one in a strange way
     log.error("Bloc %r", self)
     log.error(" OLD DST %s", instr.dst)
     log.error(" NEW DST %s", val)
     TODO
コード例 #26
0
ファイル: expression.py プロジェクト: LRGH/miasmX
 def get_w(self):
     return set([self])  #[memreg]
コード例 #27
0
def update_value(line, value, str_copy):
    if isinstance(line, P2Align):
        return value
    if line.api_nb_arg() == 2:
        src = line.api_arg_txt(1, asm_format='att_syntax')
        dst = line.api_arg_txt(0, asm_format='att_syntax')
    # Top
    if   value == (False, set()):
        return value
    # Analysis not possible
    if '(%rsp,' in str(line):
        return False, set()
    # When the stack moves...
    imm = line_shifts_stack(line)
    if imm != 0:
        if imm is not None: imm = -imm
        return stack_shift(value, imm)
    # Sometimes %rsp is copied in another register
    if 'mov' == line.opname \
            and src == '%rsp':
        reg, val = value
        reg = dict(reg)
        reg[dst] = set([0])
        return reg, val
    # Sometimes %rsp is copied in another register, with an offset
    if 'lea' == line.opname \
            and src.endswith('(%rsp)'):
        imm = src[:-6]
        if imm == '': imm = 0
        else:         imm = int(imm)
        reg, val = value
        reg = dict(reg)
        reg[dst] = set([imm])
        return reg, val
    # Sometimes the other register is shifted
    if 'add' == line.opname \
            and dst in value[0]:
        imm = line.api_get_cst(1)
        if imm is None:
            return value
        else:
            registers = dict(value[0])
            registers[dst] = set([_ + imm for _ in registers[dst]])
            return registers, value[1]
    # String copy into the red zone
    if 'mov' == line.opname \
            and src.startswith('$') \
            and dst in ('%ecx', '%cl'):
        imm = line.api_get_cst(1)
        if imm is not None:
            str_copy['ecx'] = imm
        return value
    if line.opname in ('movsq', 'stosq', 'scasq') \
            and line.prefix == [243]: # rep
        if 'ecx' in str_copy and '%rdi' in value[0]:
            imm = value[0]['%rdi']
            assert len(imm) == 1
            imm = list(imm)[0]
            positions = value[1].union(set(
                [imm+8*idx for idx in range(str_copy['ecx'])]))
            return value[0], positions
        else:
            return value
    # Use of the red zone starting from %rsp
    if line.opname in   ('mov', 'movss', 'movsd',
                         'movaps', 'movups', 'movlps',
                         'movdqa', 'movdqu', ) \
            and dst.endswith('(%rsp)'):
        imm = dst[:-6]
        if imm == '': imm = 0
        else:         imm = int(imm)
        positions = value[1].union(set([imm]))
        if line.opname in ('movaps', 'movups', 'movlps',
                           'movdqa', 'movdqu', ):
            # input is 128-bit long
            # note that movss %xmmN, MEM only moves 32 bits
            positions.update([imm+8])
        return value[0], positions
    # Use of the red zone starting from another register
    if line.opname in ('mov', 'movsxd') \
            and dst.endswith(')'):
        reg = dst[-5:-1]
        if reg in value[0]: # registers
            imm = dst[:-6]
            if imm == '': imm = 0
            else:         imm = int(imm)
            positions = value[1].union(set([imm+_ for _ in value[0][reg]]))
            return value[0], positions
        else:
            return value
    # Sometimes the other register is overwritten
    if set(value[0].keys()).intersection(set(['%%%s'%_ for _ in line.rw[1]])):
        registers = dict(value[0])
        written = set(['%%%s'%_ for _ in line.rw[1]])
        for _ in value[0]:
            if _ in written:
                del registers[_]
        return registers, value[1]
    return value
コード例 #28
0
ファイル: symbols.py プロジェクト: LRGH/plasmasm
 def labels(self):
     ''' labels that are referenced in the line '''
     return set()
コード例 #29
0
x64_att_opcodes = set([
    'jmpq',
    'callq',
    'retq',
    'popq',
    'pushq',
    'movq',
    'cmpq',
    'testq',
    'leaq',
    'btq',
    'bswapq',
    'notq',
    'orq',
    'xorq',
    'andq',
    'bsfq',
    'bslq',
    'bsrq',
    'rolq',
    'rorq',
    'sarq',
    'salq',
    'shrq',
    'shlq',
    'sbbq',
    'negq',
    'decq',
    'incq',
    'adcq',
    'addq',
    'subq',
    'mulq',
    'divq',
    'imulq',
    'idivq',
    'shldq',
    'shrdq',
    'cltq',
    'cqto',
    'movabsq',
    'movsbq',
    'movslq',
    'movswq',
    'insq',
    'movsq',
    'outsq',
    'lodsq',
    'stosq',
    'cmpsq',
    'scasq',
    'pextrq',
    'pinsrq',
    'cvtsi2sdq',
    'cvtsi2ssq',
    'cvttsd2siq',
    'cvttss2siq',
])
コード例 #30
0
ファイル: expression.py プロジェクト: LRGH/miasmX
 def get_r(self, mem_read=False):
     if mem_read:
         return set(self.arg.get_r(mem_read).union(set([self])))
     else:
         return set([self])