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 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 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 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 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 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
""" 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(