Ejemplo n.º 1
0
    def flatten_cfg(self, cfg):
        fname, _ = cfg
        bbl = self.fb_tbl[fname]
        name_eloc_dict = {}
        for b in bbl:
            name_eloc_dict[b.bblock_name] = b.bblock_end_loc

        f = None
        for _f in self.funcs:
            if _f.func_name == fname:
                f = _f
                break
        assert f is not None
        func_instrs = self.func_instrs(f)
        for i in func_instrs:
            op = get_op(i)
            if op in JumpOp:
                des = get_cf_des(i)
                if isinstance(des, Label):
                    i0_loc = get_loc(i)
                    i1_loc = self._get_loc(i)
                    i1_loc.loc_label = ''
                    i0 = TripleInstr((self._ops['mov'], Label('global_des'),
                                      Label('$' + des), i0_loc, None))
                    junk = get_junk_codes(i1_loc)
                    i1 = DoubleInstr((op, Label('switch_bb'), i1_loc, None))
                    self.replace_instrs(i0, get_loc(i), i)
                    for _i in junk:
                        self.append_instrs(_i, get_loc(i))
                    self.append_instrs(i1, get_loc(i))
        self.update_process()
Ejemplo n.º 2
0
    def split_bb(self, b_name, b_instrs, split_pos):
        instr = b_instrs[split_pos]
        split_symbol = b_name + '_split'

        loc = get_loc(instr)
        loc_without_label = self._get_loc(instr)
        loc_without_label.loc_label = ''

        loc_with_label = self._get_loc(instr)
        loc_with_label.loc_label = split_symbol + ':'

        i1 = DoubleInstr((self._ops['jmp'], Label(split_symbol), loc_without_label, None))
        # i2 should be replaced with a list of garbage code
        # i2 = SingleInstr((self._ops['nop'], loc_with_label, None))

        self.insert_instrs(i1, loc)
        # self.insert_instrs(i2, loc)
        # we insert some codes after the jmp, which will never execute
        useless = []
        useless.append(DoubleInstr((self._ops['push'], self._regs[1], loc_without_label, None)))
        useless.append(TripleInstr((self._ops['mov'], self._regs[0], self._regs[1], loc_without_label, None)))
        useless.append(TripleInstr(('xor', self._regs[0], self._regs[0], loc_without_label, None)))
        useless.append(DoubleInstr((self._ops['jmp'], Label('printf'), loc_without_label, None)))
        for u in useless:
            self.insert_instrs(u, loc)

        junk = get_junk_codes(loc_with_label)
        if len(junk) == 0:
            junk.append(SingleInstr((self._ops['nop'], loc_with_label, None)))
        junk[0][-2].loc_label = loc_with_label.loc_label
        for j in junk:
            self.insert_instrs(j, loc)
Ejemplo n.º 3
0
    def get_opaque_header2(self, b, spt_pos=0):
        opaque_symbol = b.bblock_name + '_opaque_next'
        bil = self.bb_instrs(b)
        i = bil[spt_pos]

        # print 'basic block opaque transformation: ' + b.bblock_name + ' ' + dec_hex(b.bblock_begin_loc.loc_addr) \
        #       + '->' + dec_hex(b.bblock_end_loc.loc_addr)
        # print 'instruction be added opaque block is: %s' % pp_print_instr(i)

        iloc = self._get_loc(i)
        tmp_iloc = copy.deepcopy(iloc)
        tmp_iloc.loc_label = ''
        tmp_iloc2 = copy.deepcopy(iloc)
        tmp_iloc2.loc_label = opaque_symbol + ': '

        # store the %eax to stack
        i1 = DoubleInstr(('push', self._regs[0], iloc, None))
        save_flag = SingleInstr((self._ops['pushf'], tmp_iloc, None))
        junk1 = get_junk_codes(tmp_iloc)
        i2 = DoubleInstr(('call', Types.Label('opaque_func'), tmp_iloc, None))
        # in attach_opaque_routines, we set the value of %eax=0x0
        # cmp is supposed to be true, and the code will always jump to opaque_symbol
        i3 = TripleInstr(('cmp', self._regs[0], Types.Normal(self.routine_constant), tmp_iloc, None))
        i4 = DoubleInstr(('je', Types.Label(opaque_symbol), tmp_iloc, None))
        # this junk should never be executed
        junk2 = get_junk_codes(tmp_iloc)
        i5 = DoubleInstr(('call', Types.Label('halt_func'), tmp_iloc, None))
        # recover the value of %eax, and here is the start of opaque_symbol
        recover_flag = SingleInstr((self._ops['popf'], tmp_iloc2, None))
        i6 = DoubleInstr(('pop', self._regs[0], tmp_iloc, None))
        i0 = set_loc(i, tmp_iloc)

        res = list()
        res.append((instr_update.INSERT, i1, iloc))
        res.append((instr_update.INSERT, save_flag, iloc))
        res.extend([(instr_update.INSERT, j, iloc) for j in junk1])
        res.append((instr_update.INSERT, i2, iloc))
        res.append((instr_update.INSERT, i3, iloc))
        res.append((instr_update.INSERT, i4, iloc))
        res.extend([(instr_update.INSERT, j, iloc) for j in junk2])
        res.append((instr_update.INSERT, i5, iloc))
        res.append((instr_update.INSERT, recover_flag, iloc))
        res.append((instr_update.INSERT, i6, iloc))
        res.append((instr_update.REPLACE, i0, iloc, i))
        return res
Ejemplo n.º 4
0
    def update_preceding_func(self, pre, f):
        pre_f_instrs = self.func_instrs(pre)
        last_loc = self._get_loc(pre_f_instrs[-1])
        last_loc.loc_label = ''

        junk = get_junk_codes(last_loc, 0)
        for j in junk:
            self.append_instrs(j, last_loc)
        i = DoubleInstr((self._ops['jmp'], Label(f.func_name), last_loc, None))
        self.append_instrs(i, last_loc)
Ejemplo n.º 5
0
 def get_switch_routine(self, loc):
     loc_without_label = copy.deepcopy(loc)
     loc_without_label.loc_label = ''
     junk = get_junk_codes(loc)
     i0 = DoubleInstr(
         (self._ops['jmp'], Label('*global_des'), loc_without_label, None))
     junk.append(i0)
     # note junk can be length 0, the label modification must locate after the appending
     junk[0][-2].loc_label = ".globl switch_bb\nswitch_bb:"
     return junk
Ejemplo n.º 6
0
    def update_succeeding_func(self, f, suc):
        f_instrs = self.func_instrs(f)
        last_loc = self._get_loc(f_instrs[-1])
        last_loc.loc_label = ''

        junk = get_junk_codes(last_loc, 0)
        for j in junk:
            self.append_instrs(j, last_loc)
        i = DoubleInstr(
            (self._ops['jmp'], Label(suc.func_name), last_loc, None))
        self.append_instrs(i, last_loc)
Ejemplo n.º 7
0
 def _get_garbage(self, loc, mode=1):
     if mode == 1:
         nops = self._nop_garbage_instrs(loc)
         num_instrs = len(nops)  # random.randint(1, len(nops) - 4)
         res = []
         for i in range(num_instrs):
             res.append(random.choice(nops))
         return res
     elif mode == 2:
         return get_junk_codes(loc, None)
     else:
         return []
Ejemplo n.º 8
0
 def get_branch_routine(self, iloc):
     """
     return the list of routine instructions for branch functions
     :param iloc: the location of instruction that routine being inserted
     :return: the list of routine instructions
     """
     loc_with_branch_label = copy.deepcopy(iloc)
     loc_with_branch_label.loc_label = 'branch_routine: '
     loc = copy.deepcopy(iloc)
     loc.loc_label = ''
     i0 = DoubleInstr((self._ops['pop'], Label('global_des'),
                       loc_with_branch_label, None))
     junk = get_junk_codes(loc)
     i1 = DoubleInstr((self._ops['jmp'], Label('*branch_des'), loc, None))
     res = [i0]
     res.extend(junk)
     res.append(i1)
     return res
Ejemplo n.º 9
0
 def update_current_bb(self, fb, last_loc, sb):
     fb_l = self.bb_instrs(fb)
     sb_l = self.bb_instrs(sb)
     fl = len(fb_l)
     sl = len(sb_l)
     if fl >= sl:
         for idx in range(fl):
             if sl <= idx:
                 floc = self._get_loc(fb_l[idx])
                 floc.loc_label = ''
                 # i = SingleInstr(('nop', floc, False))
                 # self.replace_instrs(i, floc, fb_l[idx])
                 junk = get_junk_codes(floc)
                 if len(junk) == 0:
                     junk.append(SingleInstr(('nop', floc, False)))
                 self.replace_instrs(junk[0], floc, fb_l[idx])
                 for j in junk[1:]:
                     self.append_instrs(j, floc)
             elif idx < sl:
                 # Note: the get_loc return the reference of loc, which may cause side effect
                 floc = self._get_loc(fb_l[idx])
                 sloc = self._get_loc(sb_l[idx])
                 floc.loc_label = sloc.loc_label
                 sh_ = set_loc(sb_l[idx], floc)
                 self.replace_instrs(sh_, floc, fb_l[idx])
     else:
         for idx in range(sl):
             if idx >= fl:
                 sloc = self._get_loc(sb_l[idx])
                 last_loc.loc_label = sloc.loc_label
                 sh_ = set_loc(sb_l[idx], last_loc)
                 self.insert_instrs(sh_, last_loc)
             elif idx == fl - 1:
                 loc = self._get_loc(fb_l[idx])
                 sloc = self._get_loc(sb_l[idx])
                 loc.loc_label = sloc.loc_label
                 sh_ = set_loc(sb_l[idx], loc)
                 self.replace_instrs(sh_, loc, fb_l[idx])
             else:
                 floc = self._get_loc(fb_l[idx])
                 sloc = self._get_loc(sb_l[idx])
                 floc.loc_label = sloc.loc_label
                 sh_ = set_loc(sb_l[idx], floc)
                 self.replace_instrs(sh_, floc, fb_l[idx])
Ejemplo n.º 10
0
    def get_opaque_routines(self, iloc):
        iloc1 = copy.deepcopy(iloc)
        iloc1.loc_label = 'opaque_func: '

        tmp_loc = copy.deepcopy(iloc)
        tmp_loc.loc_label = ''

        iloc6 = copy.deepcopy(iloc)
        iloc6.loc_label = 'halt_func: '

        i1 = DoubleInstr(('push', self._stack_regs['bp'], iloc1, None))
        i2 = TripleInstr(('mov', self._stack_regs['bp'], self._stack_regs['sp'], tmp_loc, None))
        junk = get_junk_codes(tmp_loc, 0)
        # set the value of %eax to be 0
        i3 = TripleInstr(('mov', self._regs[0], Types.Normal(self.routine_constant), tmp_loc, None))
        i4 = DoubleInstr(('pop', self._stack_regs['bp'], tmp_loc, None))
        i5 = SingleInstr(('ret', tmp_loc, None))
        i6 = SingleInstr(('hlt', iloc6, None))
        res = [i1, i2]
        res.extend(junk)
        res.extend([i3, i4, i5, i6])
        return res
Ejemplo n.º 11
0
    def _branch_a_func(self, f):
        fil = self.func_instrs(f)
        find_a_valid_func = False
        for instr in fil:
            op = get_op(instr)
            des = get_cf_des(instr)
            if des is not None and isinstance(des, Label):
                if op in JumpOp:
                    if random.random() > obfs_proportion:
                        continue
                    # here we modify the process of 2 situations, jmp and conditional jmp
                    if p_op(op) == 'jmp' or p_op(op) == self._ops['jmp']:
                        # this is a simple jump, we simply cache the des and call the routine
                        find_a_valid_func = True
                        loc = self._get_loc(instr)
                        i0 = TripleInstr(
                            (self._ops['mov'], Label('branch_des'),
                             Label('$' + str(des)), loc, None))
                        loc1 = copy.deepcopy(loc)
                        loc1.loc_label = ''
                        i1 = DoubleInstr((self._ops['call'],
                                          Label('branch_routine'), loc1, None))
                        junk1 = get_junk_codes(loc1)
                        junk2 = get_junk_codes(loc1)

                        self.insert_instrs(i0, loc)
                        for _i in junk1:
                            self.insert_instrs(_i, loc)
                        self.replace_instrs(i1, loc, instr)
                        for _i in junk2:
                            self.append_instrs(_i, loc)
                    elif p_op(op) in {'je', 'jne', 'jl', 'jle', 'jg', 'jge'}:
                        # we only handle with these conditional jmp
                        find_a_valid_func = True
                        loc = self._get_loc(instr)
                        postfix = p_op(op)[1:]
                        # we ues conditional move the modify a conditional jmp
                        self._new_des_id += 1
                        fall_through_label = 'fall_through_label_%d' % self._new_des_id
                        loc_no_label = copy.deepcopy(loc)
                        loc_no_label.loc_label = ''
                        loc_fall_through = copy.deepcopy(loc)
                        loc_fall_through.loc_label = fall_through_label + ':'
                        tmp = [
                            DoubleInstr((self._ops['push'], self._regs[0], loc,
                                         None)),  # 0  replace
                            DoubleInstr((self._ops['push'], self._regs[1],
                                         loc_no_label, None)),
                            TripleInstr((self._ops['mov'], self._regs[0],
                                         Label('$' + fall_through_label),
                                         loc_no_label, None)),
                            TripleInstr(
                                (self._ops['mov'], self._regs[1],
                                 Label('$' + str(des)), loc_no_label, None)),
                            TripleInstr(('cmov' + postfix, self._regs[0],
                                         self._regs[1], loc_no_label, None)),
                            TripleInstr((self._ops['mov'], Label('branch_des'),
                                         self._regs[0], loc_no_label, None)),
                            DoubleInstr((self._ops['pop'], self._regs[1],
                                         loc_no_label, None)),
                            DoubleInstr((self._ops['pop'], self._regs[0],
                                         loc_no_label, None)),
                            DoubleInstr(
                                (self._ops['call'], Label('branch_routine'),
                                 loc_no_label, None)),
                            SingleInstr(
                                (self._ops['nop'], loc_fall_through, None))
                        ]
                        self.replace_instrs(tmp[0], loc, instr)
                        for _i in tmp[1:]:
                            self.append_instrs(_i, loc)
        return find_a_valid_func
Ejemplo n.º 12
0
    def get_opaque_header1(self, b, spt_pos=0):
        """
        get the list of instructions which work as the opaque block
        the instructions works as 'if (y < 10 || x*(x-1) % 2 == 0)'
        It is clear the the statement is always true (if something wrong and it run into false branch, halt the program)
        :param b: the opaque block will be inserted before the block
        :param spt_pos: the opaque block will be inserted before the instruction(which is b[spt_pos])
        :return: the instructions list of the opaque_block
        """
        opaque_symbol = b.bblock_name + '_opaque_next'
        bil = self.bb_instrs(b)
        i = bil[spt_pos]
        iloc_with_block_label = self._get_loc(i)
        iloc_without_label = copy.deepcopy(iloc_with_block_label)
        iloc_without_label.loc_label = ''
        iloc_with_true_branch_label = copy.deepcopy(iloc_with_block_label)
        iloc_with_true_branch_label.loc_label = opaque_symbol + ': '
        # false branch will call halt_func directly

        res = []
        res.append((instr_update.INSERT, DoubleInstr(('push', self._regs[0], iloc_with_block_label, None)),
                    iloc_with_block_label))  # use this reg as x
        res.append((instr_update.INSERT, SingleInstr((self._ops['pushf'], iloc_without_label, None)),
                    iloc_with_block_label))  # save flag
        res.append((instr_update.INSERT, DoubleInstr(('push', self._regs[1], iloc_without_label, None)),
                    iloc_with_block_label))  # use this reg as y
        # y < 10
        res.append((
            instr_update.INSERT, TripleInstr(('cmp', self._regs[1], Types.Normal(10), iloc_without_label, None)),
            iloc_with_block_label))
        res.append((instr_update.INSERT, DoubleInstr(('jl', Types.Label(opaque_symbol), iloc_without_label, None)),
                    iloc_with_block_label))
        # x*(x-1) % 2 == 0, use y to store value of (x-1)
        res.append((instr_update.INSERT, TripleInstr(('mov', self._regs[0], self._regs[1], iloc_without_label, None)),
                    iloc_with_block_label))
        # junk code
        res.extend([(instr_update.INSERT, j, iloc_without_label) for j in get_junk_codes(iloc_without_label)])
        res.append((instr_update.INSERT, TripleInstr(('sub', self._regs[1], Types.Normal(1), iloc_without_label, None)),
                    iloc_with_block_label))
        res.append((instr_update.INSERT, TripleInstr(('imul', self._regs[0], self._regs[1], iloc_without_label, None)),
                    iloc_with_block_label))
        res.append((instr_update.INSERT, TripleInstr(('and', self._regs[0], Types.Normal(1), iloc_without_label, None)),
                    iloc_with_block_label))
        res.append((instr_update.INSERT, TripleInstr(('test', self._regs[0], self._regs[0], iloc_without_label, None)),
                    iloc_with_block_label))
        res.append((instr_update.INSERT, DoubleInstr(('je', Types.Label(opaque_symbol), iloc_without_label, None)),
                    iloc_with_block_label))
        # false branch
        res.append((instr_update.INSERT, DoubleInstr(('call', Types.Label('abort'), iloc_without_label, None)),
                    iloc_with_block_label))
        # true branch
        res.append((instr_update.INSERT, DoubleInstr(('pop', self._regs[1], iloc_with_true_branch_label, None)),
                    iloc_with_block_label))
        res.append(
            (instr_update.INSERT, SingleInstr((self._ops['popf'], iloc_without_label, None)), iloc_with_block_label))
        res.append(
            (instr_update.INSERT, DoubleInstr(('pop', self._regs[0], iloc_without_label, None)), iloc_with_block_label))
        # remove the label of original block
        new_line = set_loc(i, iloc_without_label)
        res.append((instr_update.REPLACE, new_line, iloc_with_block_label, i))
        return res