Example #1
0
def do_equiv_instrs(instrs, gen_patched, all_diffs=None):
  """Check each instruction if it has an equivalent one and computes the
  changed bytes set. Optionally, it can generate a changed file with the
  equivalent instructions. Returns the list of changed bytes."""

  changed_bytes = set()
  changed = []

  for ins in instrs: 
    if check_equiv(ins):
      changed.append(ins)

  diff = inp.get_diff(changed)

  if gen_patched:
    inp.patch(diff, "equiv")

  changed_bytes.update((ea for ea, orig, new in diff))

  for ins in changed:
    if all_diffs != None:
      all_diffs.append(inp.get_diff([ins]))
    ins.reset_changed()

  return changed_bytes
Example #2
0
def randomize(input_file):
    # get the changed byte sets
    functions = inp.get_functions(input_file)
    levels = func.classify_functions(functions)
    func.analyze_functions(functions, levels)

    global_diffs = []
    changeable = 0

    for f in filter(lambda x: x.level != -1, functions.itervalues()):
        # skip the SEH prolog and epilog functions .. they cause trouble
        if "_SEH_" in f.name:    
            continue

        diffs = []

        # swap (register reassignment with CFG): RUNTIME ERROR
        # This application has requested the Runtime to terminate it in an unsusal way.
        # Please Contact the application's support team for more information
        swap.liveness_analysis(f.code)
        live_regs = swap.get_reg_live_subsets(f.instrs, f.code, f.igraph)
        swaps = swap.get_reg_swaps(live_regs)
        swap.do_single_swaps(swaps, False, diffs)

        # preserv (reordering of register preservation): ERROR
        preservs, avail_regs = preserv.get_reg_preservations(f)
        preserv.do_reg_preservs(f.instrs, f.blocks, preservs, avail_regs, False, diffs)

        # equiv (automic instruction substitution): GOOD
        equiv.do_equiv_instrs(f.instrs, False, diffs)

        # reorder (intra basic block reordering): GOOD
        reorder.do_reordering(f.blocks, False, diffs)

        if diffs:
            changeable += len(list(itertools.chain(*diffs)))
            global_diffs.extend(random.choice(diffs))

    inp.patch(global_diffs, "rand", False)

    print "changed %d bytes of at least %d changeable" % (len(global_diffs), changeable)
    print "(not counting all possible reorderings and preservations)"
Example #3
0
def do_single_swaps(swaps, gen_patched, all_diffs=None):
    """Applies one swap at a time and optionally generates the patched .dll.
    Returns a set of the linear addresses of the changed bytes."""

    changed_bytes = set()

    for i, swap in enumerate(swaps):
        success, changed = apply_swap_comb([swap])

        if success:
            diff = inp.get_diff(changed)
            if gen_patched:
                inp.patch(diff, "swap-%06d" % i)
            if all_diffs != None:
                all_diffs.append(diff)
            changed_bytes.update((ea for ea, orig, curr in diff))

        for ins in changed:
            ins.reset_changed()

    return changed_bytes
Example #4
0
def do_single_swaps(swaps, gen_patched, all_diffs=None):
    """Applies one swap at a time and optionally generates the patched .dll.
    Returns a set of the linear addresses of the changed bytes."""

    changed_bytes = set()

    for i, swap in enumerate(swaps):
        success, changed = apply_swap_comb([swap])

        if success:
            diff = inp.get_diff(changed)
            if gen_patched:
                inp.patch(diff, "swap-%06d" % i)
            if all_diffs != None:
                all_diffs.append(diff)
            changed_bytes.update((ea for ea, orig, curr in diff))

        for ins in changed:
            ins.reset_changed()

    return changed_bytes
Example #5
0
def do_reordering(blocks, gen_patched, all_diffs=None):
    """Reorders the instructions within the given blocks and optionally generates
    instances of the input file with these instructions reordered. Returns the
    changed bytes set (coverage evaluation)."""

    reordered = []
    changed_bytes = set()
    diff = []

    for block in blocks:

        dag = BuildBBDependenceDAG(block)
        block.rinstrs = ReorderGraph(dag)

        # update the address of reordered instrs
        for i, rins in enumerate(block.rinstrs):

            if i == 0:
                rins.raddr = block.begin
            else:
                rins.raddr = block.rinstrs[i - 1].raddr + len(block.rinstrs[i - 1].bytes)

            if rins.raddr != rins.addr and rins.inst_len > 4:
                reordered.append(rins)

        diff.extend(inp.get_block_diff(block))

    reloc_diff = inp.get_reloc_diff(reordered)

    if gen_patched:
        inp.patch(diff + reloc_diff, "reorder")

    if all_diffs != None and len(reloc_diff) == 0:
        all_diffs.append(diff + reloc_diff)

    changed_bytes.update((ea for ea, orig, curr in diff))

    return changed_bytes
Example #6
0
def do_reg_preservs(instrs,
                    blocks,
                    preservs,
                    avail_regs,
                    gen_patched,
                    all_diffs=None):
    """Changes the preserved registers within the given instructions and optionally 
  generates instances of the input file with these permuted register preservations.
  Returns the changed bytes set."""

    changed_bytes = set()

    #f_exit instructions (ret) implicitly use the preserved registers.. exclude them!
    implicit = reduce(lambda x, y: x | y,
                      [i.implicit for i in instrs if not i.f_exit], set())

    regs = [reg for reg, pushes, pops in preservs if reg not in implicit]

    if not preservs or (len(regs) == 1 and not avail_regs):
        return changed_bytes

    # preserved registers that are implicitly used should not be touched
    # hmm .. rotation should still happen even when all regs are implicitly used..
    #if not regs:
    #  return changed_bytes
    if len(regs) == 1:  #we know we have available
        regs.append(avail_regs.pop())

    if len(regs) >= 2:
        # we do need the combinations here, because we want to change as much
        # as possible in case a register cannot be swapped (e.g. weird modrm/sib)
        for r1, r2 in itertools.combinations(regs, 2):
            for ins in instrs:
                if not ins.swap_registers(r1, r2):
                    #print "MAYBEBUG: broke for", ins.disas, "in register preservations!", r1, r2, ins.regs
                    break
            else:  #no break!
                diff = inp.get_diff(instrs)
                if gen_patched:
                    inp.patch(diff, "preserv-%s-%s" % (r1, r2))
                if all_diffs != None:
                    all_diffs.append(diff)
                changed_bytes.update((ea for ea, orig, curr in diff))
            for ins in instrs:
                ins.reset_changed()

    # the second part bellow can be useful in cases where global swap
    # cannot  be applied due to implicit uses

    # group preservs in the same block and reorder them
    # augment each ins in the preservs with blocks
    for reg, pushes, pops in preservs:
        for ins in itertools.chain(pushes, pops):
            ins.block = next((b for b in blocks if ins in b.instrs), None)

    preservs_groups = []

    for reg, pushes, pops in preservs:
        if len(preservs_groups) == 0:
            preservs_groups.append([[reg, pushes, pops]])
            continue
        for group in preservs_groups:
            if (all(p1.block == p2.block
                    for p1, p2 in zip(group[0][1], pushes))
                    and all(p1.block == p2.block
                            for p1, p2 in zip(group[0][2], pops))):
                group.append([reg, pushes, pops])
                break
            else:
                preservs_groups.append([[reg, pushes, pops]])
    #print "grouping!:", '\n'.join((str(g) for g in preservs_groups))

    # reorder (rotate) the pushes/pops by placing the last one in the
    # first's position and shifting all the other instrs down
    # TODO: breaks if esp is used within the reordered block! (BIB @ 070012F1)
    for group in (g for g in preservs_groups if len(g) > 1):
        # group them by block
        #pushes_by_block = {}
        ins_by_block = {}
        for reg, pushes, pops in group:
            for ins in itertools.chain(pushes, pops):
                if (ins.block, ins.mnem) not in ins_by_block:
                    ins_by_block[(ins.block, ins.mnem)] = []
                ins_by_block[(ins.block, ins.mnem)].append(ins)
        # in each block, move the latest ins to the ealiest's position
        for (block, mnem), instrs in ins_by_block.iteritems():
            instrs.sort(key=lambda x: x.addr)
            first = block.instrs.index(instrs[0])
            last = block.instrs.index(instrs[-1])
            block.rinstrs = block.instrs[:first]
            block.rinstrs.append(block.instrs[last])
            block.rinstrs.extend(block.instrs[first:last])
            block.rinstrs.extend(block.instrs[last + 1:])
            diff = inp.get_block_diff(block)
            changed_bytes.update((ea for ea, orig, curr in diff))
            #XXX should also generate patched files ...

    return changed_bytes
Example #7
0
def do_reg_preservs(instrs, blocks, preservs, avail_regs, gen_patched, all_diffs=None):
    """Changes the preserved registers within the given instructions and optionally
    generates instances of the input file with these permuted register preservations.
    Returns the changed bytes set."""

    changed_bytes = set()

    # f_exit instructions (ret) implicitly use the preserved registers.. exclude them!
    implicit = reduce(lambda x, y: x | y, [i.implicit for i in instrs if not i.f_exit], set())

    regs = [reg for reg, pushes, pops in preservs if reg not in implicit]

    if not preservs or (len(regs) == 1 and not avail_regs):
        return changed_bytes

    # preserved registers that are implicitly used should not be touched
    # hmm .. rotation should still happen even when all regs are implicitly used..
    # if not regs:
    #  return changed_bytes
    if len(regs) == 1:  # we know we have available
        regs.append(avail_regs.pop())

    if len(regs) >= 2:
        # we do need the combinations here, because we want to change as much
        # as possible in case a register cannot be swapped (e.g. weird modrm/sib)
        for r1, r2 in itertools.combinations(regs, 2):
            for ins in instrs:
                if not ins.swap_registers(r1, r2):
                    # print "MAYBEBUG: broke for", ins.disas, "in register preservations!", r1, r2, ins.regs
                    break
            else:  # no break!
                diff = inp.get_diff(instrs)
                if gen_patched:
                    inp.patch(diff, "preserv-%s-%s" % (r1, r2))
                if all_diffs != None:
                    all_diffs.append(diff)
                changed_bytes.update((ea for ea, orig, curr in diff))
            for ins in instrs:
                ins.reset_changed()

    # the second part bellow can be useful in cases where global swap
    # cannot  be applied due to implicit uses

    # group preservs in the same block and reorder them
    # augment each ins in the preservs with blocks
    for reg, pushes, pops in preservs:
        for ins in itertools.chain(pushes, pops):
            ins.block = next((b for b in blocks if ins in b.instrs), None)

    preservs_groups = []

    for reg, pushes, pops in preservs:
        if len(preservs_groups) == 0:
            preservs_groups.append([[reg, pushes, pops]])
            continue
        for group in preservs_groups:
            if (all(p1.block == p2.block for p1, p2 in zip(group[0][1], pushes)) and
                    all(p1.block == p2.block for p1, p2 in zip(group[0][2], pops))):
                group.append([reg, pushes, pops])
                break
            else:
                preservs_groups.append([[reg, pushes, pops]])
    # print "grouping!:", '\n'.join((str(g) for g in preservs_groups))

    # reorder (rotate) the pushes/pops by placing the last one in the
    # first's position and shifting all the other instrs down
    # TODO: breaks if esp is used within the reordered block! (BIB @ 070012F1)
    for group in (g for g in preservs_groups if len(g) > 1):
        # group them by block
        # pushes_by_block = {}
        ins_by_block = {}
        for reg, pushes, pops in group:
            for ins in itertools.chain(pushes, pops):
                if (ins.block, ins.mnem) not in ins_by_block:
                    ins_by_block[(ins.block, ins.mnem)] = []
                ins_by_block[(ins.block, ins.mnem)].append(ins)
        # in each block, move the latest ins to the ealiest's position
        for (block, mnem), instrs in ins_by_block.iteritems():
            instrs.sort(key=lambda x: x.addr)
            first = block.instrs.index(instrs[0])
            last = block.instrs.index(instrs[-1])
            block.rinstrs = block.instrs[:first]
            block.rinstrs.append(block.instrs[last])
            block.rinstrs.extend(block.instrs[first:last])
            block.rinstrs.extend(block.instrs[last + 1:])
            diff = inp.get_block_diff(block)
            changed_bytes.update((ea for ea, orig, curr in diff))
            # XXX should also generate patched files ...

    return changed_bytes