def vinst2ARM(self, iv): """ Analize instruction (ARM) :param iv: instruction tuple """ instr = iv[1] if instr[0].upper().startswith('MOVW'): self.ARMmovs.append(iv[0]) if isinstance(instr, Types.DoubleInstr): if isinstance(instr[1], Types.TBExp): self.insert_text(instr[1].base, int(instr[1].base.split('x')[1], 16)) self.insert_text(instr[1].dest, int(instr[1].dest.split('x')[1], 16)) return instr return Types.DoubleInstr( (instr[0], self.v_exp2(instr[1], instr, None, False), instr[2], instr[3])) if isinstance(instr, Types.TripleInstr): if instr[0].startswith('vldr') and isinstance( instr[2], Types.Const): self.ARMvldrtargets.append(instr[2]) return Types.TripleInstr( (instr[0], instr[1], self.v_exp2(instr[2], instr, None, True), instr[3], instr[4])) return instr
def vinst2(self, f, instr): """ Analize instruction (x86) :param f: unsused :param instr: instruction tuple """ if isinstance(instr, Types.SingleInstr): return instr elif isinstance(instr, Types.DoubleInstr): return Types.DoubleInstr( (instr[0], self.v_exp2(instr[1], instr, f, False), instr[2], instr[3])) elif isinstance(instr, Types.TripleInstr): is_test = instr[0].upper() in ['TEST', 'TESTL', 'TESTW', 'TESTB'] return Types.TripleInstr( (instr[0], self.v_exp2(instr[1], instr, f, is_test), self.v_exp2(instr[2], instr, f, is_test), instr[3], instr[4])) elif isinstance(instr, Types.FourInstr): return Types.FourInstr( (instr[0], instr[1], self.v_exp2(instr[2], instr, f, False), self.v_exp2(instr[3], instr, f, False) if instr[0][0].upper() == 'V' else instr[3], instr[4], instr[5])) elif isinstance(instr, Types.FiveInstr): return Types.FiveInstr( (instr[0], instr[1], instr[2], self.v_exp2(instr[3], instr, f, False), instr[4], instr[5], instr[6])) return instr
def scan(self): """ Scan instruction list and modify PC relative code with labels """ i = 0 inlen = len(self.instrs) - 1 while i < inlen: h1 = self.instrs[i] if get_loc(h1).loc_addr >= self.funcs[self.curr_func][1]: # It can be assumed that the base register is set only inside a single function self.curr_func += 1 self.curr_regs.clear() if isinstance(h1, Types.TripleInstr) and (self.match_get_pc_thunk(h1) \ or (h1[0].upper() == 'MOV' and isinstance(h1[2], Types.RegClass) \ and h1[2].upper() in self.curr_regs and isinstance(h1[1], Types.RegClass))): # .got.plt address can also be copied to more than one register self.curr_regs.add(h1[1].upper()) elif len(self.curr_regs) > 0: if isinstance(h1, Types.DoubleInstr): self.instrs[i] = Types.DoubleInstr((h1[0], self.v_exp(h1[1]), h1[2], h1[3])) elif not isinstance(h1, Types.SingleInstr): if isinstance(h1, Types.TripleInstr): self.instrs[i] = Types.TripleInstr((h1[0], self.v_exp(h1[1]), self.v_exp(h1[2]), h1[3], h1[4])) elif isinstance(h1, Types.FourInstr): self.instrs[i] = Types.FourInstr((h1[0], h1[1], self.v_exp(h1[2]), h1[3], h1[4], h1[5])) if isinstance(h1[1], Types.RegClass) and h1[1].upper() in self.curr_regs: # Remove if overridden self.curr_regs.remove(h1[1].upper()) i += 1
def translate_it_block(block): """ Translate IT block using normal branches :param block: instruction list of IT block :return: instruction list with normal branches """ itloc = get_loc(block[0]) res = [ Types.DoubleInstr( ('b' + block[0][1], Types.Label('.LIT_%X.T' % itloc.loc_addr), itloc, False)) ] branches = {'t': [], 'e': []} for i in xrange(1, len(block[0][0])): op = block[i][0].split('.') op[0] = op[0][:-2] instr = type(block[i])(('.'.join(op), ) + block[i][1:]) branches[block[0][0][i]].append(instr) endloc = get_loc(block[-1]) branches['e'].append( Types.DoubleInstr(('b', Types.Label( ('.LIT_%X.E' % itloc.loc_addr)), endloc, False))) branches['t'][0][-2].loc_label += '.LIT_%X.T: ' % itloc.loc_addr res += branches['e'] + branches['t'] res.append( set_loc( block[-1], Types.Loc('.LIT_%X.E: ' % itloc.loc_addr, endloc.loc_addr, True))) return res
def perform(instrs, funcs): # Do stuff to the instruction list if not ELF_utils.elf_arm(): instrs.append( Types.TripleInstr(('mov', Types.RegClass('eax'), Types.RegClass('eax'), Types.Loc('', 0, True), False))) return instrs
def __init__(self): self.looking_for_cfd = False self.text_secs = [] self.locs = [] self.up_bound = Types.Loc('', 0, True) self.low_bound = Types.Loc('', 0, True) self.trim_tbl = {} self.five_q = simple_queue()
def __init__(self): self.cfg_table = {} self.cfg_bdiv_table = {} self.found_entry = False self.skip_entry = False self.entry_loc = Types.Loc('', 0, True) self.last_loc = Types.Loc('', 0, True) self.entry_instr = Types.SingleInstr(('NOP', Types.Loc('', 0, True), None)) self.bb_list = [] self.bl = [] self.bl_sort = []
def get_framecookiecheck(curr_instr, funcID): """ Get code block for frame cookie check :param curr_instr: indirect branch instruction :param funcID: generated function ID :return: frame cookie check instruction list """ loc = get_loc(curr_instr) tmp = list(framecookiecheck) tmp[3][2] = Types.Normal(funcID) tmp[3] = Types.TripleInstr(tmp[3]) return set_inlineblocklocation(loc, tmp) + \ [set_loc(curr_instr, Types.Loc('', loc.loc_addr, loc.loc_visible))]
def get_framecookiehead(curr_instr, funcID): """ Get function header code block for frame cookie insertion :param curr_instr: function entry instruction :param funcID: generated function ID :return: frame cookie insertion instruction list """ loc = get_loc(curr_instr) tmp = list(framecookiehead) tmp[5][2] = Types.Normal(funcID) tmp[5] = Types.TripleInstr(tmp[5]) return set_inlineblocklocation(loc, returnenc + tmp) + \ [set_loc(curr_instr, Types.Loc('', loc.loc_addr, loc.loc_visible))]
def doublemovARM(self, instrs): """ insert labels for double mov operations movw r0, #0x102c -> movw r0, #:lower16:S_0x2102c movt r0, #0x2 -> movt r0, #:upper16:S_0x2102c :param instrs: instruction list """ for i in self.ARMmovs: mw = list(instrs[i]) destreg = mw[1] tindex = 1 while tindex < config.ARM_maxDoublemovDist: # GCC optimizations causes movw and movt not to be close to each other currinstr = instrs[i + tindex] if currinstr[0].upper() == 'MOV' and currinstr[2] == destreg: # Sometimes GCC changes idea and picks another register to load the address destreg = instrs[i + tindex][1] elif currinstr[1] == destreg: if currinstr[0].upper().split('.')[0] == 'STR': # Some other times GCC wants to have even more fun and changes register using the stack tindex += 1 while tindex < config.ARM_maxDoublemovDist: if instrs[i + tindex][2] == currinstr[2]: destreg = instrs[tindex + i][1] break tindex += 1 else: break tindex += 1 if tindex >= config.ARM_maxDoublemovDist: continue tindex = i + tindex mt = list(instrs[tindex]) if mt[0].upper().startswith('MOVT') and mt[1] == destreg: val = (mt[2] << 16) + (mw[2] & 0xffff) s = self.check_sec(val) if s is not None: s_label = 'S_' + dec_hex(val) self.insert_data(s.sec_name, val) mw[2] = Types.Label('#:lower16:' + s_label) mt[2] = Types.Label('#:upper16:' + s_label) instrs[i] = type(instrs[i])(mw) instrs[tindex] = type(instrs[tindex])(mt) if self.check_text(val): val = val & (-2) s_label = 'S_' + dec_hex(val) self.insert_text(s_label, val) mw[2] = Types.Label('#:lower16:' + s_label) mt[2] = Types.Label('#:upper16:' + s_label) instrs[i] = type(instrs[i])(mw) instrs[tindex] = type(instrs[tindex])(mt) self.ARMmovs = []
def get_returnenc(curr_instr, popcookie=False): """ Get code block for return address encryption :param curr_instr: return instruction :param popcookie: True if also frame cookie must be removed :return: return encryption instruction list """ pre = list(framecookietail) if popcookie else [] loc = get_loc(curr_instr) if curr_instr[0].upper().startswith('POP'): # pop {...,pc} i = map(str.upper, curr_instr[1]).index('PC') rlist = curr_instr[1][:i] + ('lr', ) + curr_instr[1][i + 1:] pre.insert( 0, Types.DoubleInstr( (curr_instr[0], Types.RegList(rlist), None, False))) curr_instr = Types.DoubleInstr( ('bx', Types.RegClass('lr'), None, False)) elif curr_instr[0].upper().startswith( 'LDR') and curr_instr[1].upper() == 'PC': # ldr pc, [sp], #4 pre.insert( 0, type(curr_instr)((curr_instr[0], Types.RegClass('lr')) + curr_instr[2:])) curr_instr = Types.DoubleInstr( ('bx', Types.RegClass('lr'), None, False)) return set_inlineblocklocation(loc, pre + returnenc) + \ [set_loc(curr_instr, Types.Loc('', loc.loc_addr, loc.loc_visible))]
def vinst(self, i): loc = get_loc(i) if self.skip_entry: if loc.loc_addr == self.end_loc.loc_addr: bn = 'BB_' + str(cfg.counter) cfg.counter += 1 b = Types.Bblock('', bn, loc, loc, i) self.bb_list.insert(0, b) else: self.entry_loc = loc self.entry_instr = i self.found_entry = True self.skip_entry = False self.last_loc = loc return self.help_exit( i) if Opcode_utils.is_control_transfer_op(i[0], i[1]) else i elif loc.loc_addr == self.end_loc.loc_addr: return self.help_exit(i) elif self.bb_entry(i): self.help_entry(i) return self.help_exit(i) if Opcode_utils.is_control_transfer_op( i[0], i[1]) else i elif isinstance(i, (Types.DoubleInstr, Types.SingleInstr)) and self.bb_exit(i[0], i[1]): return self.help_exit(i) self.last_loc = loc return i
def set_inlineblocklocation(loc, block): """ Set location for code block :param loc: location object :param block: list of instructions """ return [set_loc(block[0], loc)] + \ map(lambda i: set_loc(i, Types.Loc('', loc.loc_addr, loc.loc_visible)), block[1:])
def get_returnenc(curr_instr, popcookie=False): """ Get code block for return address encryption :param curr_instr: return instruction :param popcookie: True if also frame cookie must be removed :return: return encryption instruction list """ loc = get_loc(curr_instr) return set_inlineblocklocation(loc, framecookietail + returnenc if popcookie else returnenc) + \ [set_loc(curr_instr, Types.Loc('', loc.loc_addr, loc.loc_visible))]
def unify_loc(self, instrs): last_label = '' for i in xrange(len(instrs)): lo = get_loc(instrs[i]) if lo.loc_label != '' and lo.loc_label == last_label: instrs[i] = set_loc(instrs[i], Types.Loc('', lo.loc_addr, True)) else: last_label = lo.loc_label return instrs
def help_exit(self, i): loc = get_loc(i) if self.found_entry: self.last_loc = loc bn = 'BB_' + str(cfg.counter) cfg.counter += 1 b = Types.Bblock('', bn, self.entry_loc, self.last_loc, self.entry_instr) self.bb_list.insert(0, b) self.found_entry = False self.skip_entry = True elif loc.loc_addr == self.end_loc.loc_addr: bn = 'BB_' + str(cfg.counter) cfg.counter += 1 b = Types.Bblock('', bn, loc, loc, i) self.bb_list.insert(0, b) else: self.last_loc = loc return i
def pcreloffARM(self, instrs): """ Trying to handle this mess ldr r7, label -> ldr r7, label ... -> ... add r7,pc -> add r7, #0 ... -> ... ldr r1, [r7] -> ldr r1, [r7] ... -> ... label: .word 0xoffset -> label: .word (0xoffset + pc) :param instrs: instruction list """ i = 0 offsets = {} inlen = len(instrs) while i < inlen: hi = instrs[i] if isinstance(hi, Types.TripleInstr) \ and hi[0].lower().startswith('ldr') \ and isinstance(hi[2], Types.Point): j = i + 1 while j - i < config.ARM_maxAddPcDist and j < inlen: hj = instrs[j] if isinstance(hj, Types.TripleInstr) \ and hj[0].lower().startswith('add') \ and hj[1] == hi[1] \ and isinstance(hj[2], Types.RegClass) \ and hj[2].lower() == 'pc': offsets[hi[2]] = get_loc(hj).loc_addr + 4 instrs[j] = Types.TripleInstr( (hj[0], hj[1], Types.Normal(0), hj[3], hj[4])) break j += 1 elif isinstance(hi, Types.DoubleInstr) and isinstance( hi[0], Types.InlineData): off = offsets.pop(get_loc(hi).loc_addr, None) if off: instrs[i] = Types.DoubleInstr( (hi[0], Types.Point((hi[1] + off) & 0xFFFFFFFF), hi[2], hi[3])) i += 1
def help_entry(self, i): if self.found_entry: bn = 'BB_' + str(cfg.counter) cfg.counter += 1 b = Types.Bblock('', bn, self.entry_loc, self.last_loc, self.entry_instr) self.bb_list.insert(0, b) self.found_entry = True self.entry_instr = i self.entry_loc = get_loc(i) self.last_loc = self.entry_loc return i
def v_exp(self, e): """ Check if PC relative expression and transform using labels :param e: expression :return: transformed expression if matching, original one otherwise """ if isinstance(e, (Types.BinOP_PLUS, Types.BinOP_MINUS)): r1, addr = e if r1.upper() in self.curr_regs: addr = -addr if isinstance(e, Types.BinOP_MINUS) else addr des = self.gotaddr + addr s = self.check_sec(des) if s is not None: self.label.append(des) return Types.Label('S_' + dec_hex(des)) return e
def bswapsub(reg, loc): """ Replace target register in bswap containing ret encoding bytes :param reg: bswapped register :param loc: instuction location :return: instruction list with replaced bswap """ sub = Types.RegClass('edi' if reg[0].lower() == 'e' else 'rdi') substack = Types.RegClass('edi' if ELF_utils.elf_32() else 'rdi') return set_inlineblocklocation(loc, [ Types.DoubleInstr(('push', substack, None, False)), Types.TripleInstr(('mov', sub, reg, None, False)), Types.DoubleInstr(('bswap', sub, None, False)), Types.TripleInstr(('mov', reg, sub, None, False)), Types.DoubleInstr(('pop', substack, None, False)), ])
def aux(bnl, acc, i): if isinstance(i, Types.SingleInstr) and Opcode_utils.is_ret( (i[0], i[1])): bn = self.bbn_byloc(get_loc(i).loc_addr) acc.insert(0, (bn, (Types.J(), 'RET'))) elif isinstance(i, Types.DoubleInstr): if Opcode_utils.is_indirect(i[1]): bn = self.bbn_byloc(get_loc(i).loc_addr) acc.insert(0, (bn, (Types.J(), 'T'))) elif Opcode_utils.is_call(i[0]): bn = self.bbn_byloc(get_loc(i).loc_addr) bn1 = self.next_bb(bnl, bn) acc.insert(0, (bn, (Types.J(), bn1))) acc.insert(0, (bn, (Types.J(), 'INTER'))) elif Opcode_utils.is_jmp(i[0]): bn = self.bbn_byloc(get_loc(i).loc_addr) if Opcode_utils.is_func(i[1]): acc.insert(0, (bn, (Types.J(), 'INTER'))) else: en = recover_addr_from_label(p_exp(i[1])) if en == -1: acc.insert(0, (bn, (Types.J(), 'T'))) else: dn = self.bbn_byloc(en) acc.insert(0, (bn, (Types.J(), dn))) elif Opcode_utils.is_cond_jmp(i[0]): if not Opcode_utils.is_func(i[1]): bn = self.bbn_byloc(get_loc(i).loc_addr) sn = self.next_bb(bnl, bn) acc.insert(0, (bn, (Types.F(), sn))) else: assert (False) else: bn = self.bbn_byloc(get_loc(i).loc_addr) dn = self.next_bb(bnl, bn) acc.insert(0, (bn, (Types.F(), dn))) return acc
def add_bblock_label(self, bbl, instrs): bbl1 = sorted( bbl, lambda b1, b2: b1.bblock_begin_loc.loc_addr - b2. bblock_begin_loc.loc_addr) i = 0 j = 0 while True: if i == len(instrs) and j < len(bbl1): raise Exception('failed to add block label') if j == len(bbl1): break hi = instrs[i] hb = bbl1[j] iloc = get_loc(hi) bloc = hb.bblock_begin_loc if bloc.loc_addr == iloc.loc_addr: iloc = Types.Loc(hb.bblock_name + ': ' + iloc.loc_label, iloc.loc_addr, iloc.loc_visible) instrs[i] = set_loc(instrs[i], iloc) j += 1 i += 1 return instrs
""" Templates for gfree return address encryption and frame cookie """ import config from disasm import Types from utils.ail_utils import ELF_utils, set_loc, get_loc if ELF_utils.elf_64(): # x86_64 cslab = Types.Label(config.gfree_cookiestackvar + '@tpoff') returnenc = [ Types.DoubleInstr(('pushq', Types.RegClass('rax'), None, False)), Types.TripleInstr(('movq', Types.RegClass('rax'), Types.Label(config.gfree_xorkeyvar), None, False)), Types.TripleInstr(('xorq', Types.BinOP_PLUS( (Types.RegClass('rsp'), 8)), Types.RegClass('rax'), None, False)), Types.DoubleInstr(('popq', Types.RegClass('rax'), None, False)), ] framecookiehead = [ Types.DoubleInstr(('pushq', Types.RegClass('rax'), None, False)), Types.DoubleInstr(('pushq', Types.RegClass('rbx'), None, False)), Types.TripleInstr(('addq', Types.SegRef( ('fs', cslab)), Types.Normal(1), None, False)), Types.TripleInstr( ('movq', Types.RegClass('rbx'), Types.SegRef( ('fs', cslab)), None, False)), Types.TripleInstr(
def secmapper(l): items = l.split() return Types.Section(items[0], int(items[1], 16), int(items[3], 16))
def v_exp2(self, exp, instr, f, chk): """ Analyze expression and determine if it represent an address. If so substitute if with a corresponding symbolic expression using labels :param exp: expression :param instr: instruction tuple to which the expression belongs to :param f: unused :param chk: True if instruction is TEST (x86) :return: modified expression if matching, original one otherwise """ if isinstance(exp, Types.Const): if isinstance(exp, Types.Normal) and chk: return exp s = self.check_sec(exp) if s is not None: self.insert_data(s.sec_name, exp) return Types.Label(self.build_symbol(exp)) if self.check_text(exp): if ELF_utils.elf_arm(): exp = type(exp)(exp & (-2)) s_label = self.build_symbol(exp) self.insert_text(s_label, exp) return Types.Label(s_label) if self.check_plt(exp): return Types.Label(self.build_plt_symbol(exp)) elif isinstance(exp, Types.Symbol): if isinstance(exp, Types.JumpDes): if self.check_text(exp): s_label = 'S_' + dec_hex(exp) self.insert_text(s_label, exp) return Types.Label(s_label) elif self.check_plt(exp) and exp in self.plt_hash: return Types.Label(self.plt_hash[exp]) elif isinstance(exp, Types.StarDes): return Types.StarDes(self.v_exp2(exp.content, instr, f, chk)) elif isinstance(exp, Types.CallDes): if exp.func_name.startswith('S_0'): addr = int(exp.func_name[2:], 16) if self.check_text(addr): s_label = 'S_' + dec_hex(addr) self.insert_text(s_label, addr) return Types.Label(s_label) elif self.check_plt(addr): off = 0 while not self.plt_hash.get(addr - off, None): off += 2 return Types.Label(self.plt_hash[addr - off]) else: self.symbol_list.insert(0, exp.func_begin_addr) elif isinstance(exp, Types.Ptr): if isinstance(exp, (Types.BinOP_PLUS, Types.BinOP_MINUS)): r, addr = exp s = self.check_sec(addr) if s is not None: s_label = 'S_' + dec_hex(addr) self.insert_data(s.sec_name, addr) return Types.BinOP_PLUS_S((r, s_label)) \ if isinstance(exp, Types.BinOP_PLUS) \ else Types.BinOP_MINUS_S((r, s_label)) elif isinstance(exp, (Types.FourOP_PLUS, Types.FourOP_MINUS)): r1, r2, off, addr = exp s = self.check_sec(addr) if s is not None: s_label = 'S_' + dec_hex(addr) self.insert_data(s.sec_name, addr) return Types.FourOP_PLUS_S((r1,r2,off,s_label)) \ if isinstance(exp, Types.FourOP_PLUS) \ else Types.FourOP_MINUS_S((r1,r2,off,s_label)) elif isinstance(exp, Types.JmpTable_PLUS): addr, r, off = exp s = self.check_sec(addr) if s is not None: s_label = 'S_' + dec_hex(addr) self.insert_data(s.sec_name, addr) return Types.JmpTable_PLUS_S((s_label, r, off)) if self.check_text(addr): s_label = 'S_' + dec_hex(addr) self.insert_text(s_label, addr) return Types.JmpTable_PLUS_S((s_label, r, off)) elif isinstance(exp, Types.JmpTable_MINUS): addr, r, off = exp s = self.check_sec(addr) if s is not None: s_label = '-S_' + dec_hex(addr) self.insert_data(s.sec_name, addr) return Types.JmpTable_MINUS_S((s_label, r, off)) if self.check_text(addr): s_label = '-S_' + dec_hex(addr) self.insert_text(s_label, addr) return Types.JmpTable_MINUS_S((s_label, r, off)) return exp