示例#1
0
 def testAddSubSimple(self):
     for opcode in equiv.equiv_addsub8:
         imm, neg = '\x66', '\x9A'
         i = insn.Instruction(0, bytes(chr(opcode) + imm), 0)
         self.assertTrue(equiv.check_equiv(i))
         nbytes = bytearray(chr(equiv.equiv_addsub8[opcode]) + neg)
         self.assertEqual(i.cbytes, nbytes)
     for opcode in equiv.equiv_addsub32:
         imm, neg = '\x66\x66\x66\x66', '\x9A\x99\x99\x99'
         i = insn.Instruction(0, bytes(chr(opcode) + imm), 0)
         self.assertTrue(equiv.check_equiv(i))
         nbytes = bytearray(chr(equiv.equiv_addsub32[opcode]) + neg)
         self.assertEqual(i.cbytes, nbytes)
示例#2
0
 def testSameRegisters(self):
     for opcode in equiv.same_regs:
         for modrm in equiv.same_reg_modrms:
             i = insn.Instruction(0, bytes(chr(opcode) + chr(modrm)), 0)
             self.assertTrue(equiv.check_equiv(i))
             nbytes = bytearray(
                 chr(equiv.same_regs[opcode][0]) + chr(modrm))
             self.assertEqual(i.cbytes, nbytes)
示例#3
0
 def testAddSubOpcodeExtension(self):
     ext_mask = 0b00101000  # modrm = mod 2b | reg 3b | rm 3b
     modrm_mod = 0xC0  # 11000000 src operand is a reg (test only this case)
     for opcode in (0x80, 0x81, 0x83):
         for modrm_rm, reg in enumerate(self.rm_regs):
             for ext in (0b101000, 0b000000):
                 if opcode == 0x81:
                     imm, neg = '\x66\x66\x66\x66', '\x9A\x99\x99\x99'
                 else:
                     imm, neg = '\x66', '\x9A'
                 modrm = modrm_mod | ext | modrm_rm
                 i = insn.Instruction(0,
                                      bytes(chr(opcode) + chr(modrm) + imm),
                                      0)
                 self.assertTrue(equiv.check_equiv(i))
                 nbytes = bytearray(
                     chr(opcode) + chr(modrm ^ ext_mask) + neg)
                 self.assertEqual(i.cbytes, nbytes)
示例#4
0
 def testBothRegisters(self):
     modrm_mod = 0xC0  # 11000000  src operand is a reg (test only this case)
     modrm_regs = [0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x38]
     dir_bit = 0b00000010
     for modrm_rm, reg in enumerate(self.rm_regs):
         for modrm_reg in modrm_regs:
             for opcode in equiv.both_regs + tuple(
                 (op ^ dir_bit for op in equiv.both_regs)):
                 if opcode in equiv.same_regs:
                     continue
                 modrm_byte = modrm_mod | modrm_rm | modrm_reg
                 i = insn.Instruction(0,
                                      bytes(chr(opcode) + chr(modrm_byte)),
                                      0)
                 self.assertTrue(equiv.check_equiv(i))
                 # swapped reg, rm!
                 modrm_byte = modrm_mod | modrm_rm << 3 | modrm_reg >> 3
                 nbytes = bytearray(chr(opcode ^ dir_bit) + chr(modrm_byte))
                 self.assertEqual(i.cbytes, nbytes)
示例#5
0
 def test_XCHG_XORSUB(self):
     i = insn.Instruction(0, '\x87\xD8', 0)  # xchg eax, ebx
     self.assertEqual(equiv.check_equiv(i), True)
     i = insn.Instruction(0, str(i.cbytes), 0)  # xchg ebx, eax
     self.assertEqual(i.disas, "xchg ebx,eax")
示例#6
0
文件: eval.py 项目: terry2012/ropf
def get_entropy(f, g, live_regs, swaps, preservs, avail_regs):
    """Given a gadget, it returns the number of different ways that it can be
    broken. A second return value indicates whether this gadget can be
    eliminated (entropy)."""
    def _add_if_hit(g, diff, diffs):
        gdiff = tuple(d for d in diff if g.start <= d[0] < g.end)  # d[0] is ea
        old_diffs_len = len(diffs)
        if len(gdiff) > 0:
            diffs.add(gdiff)
        return old_diffs_len != len(diffs)

    entropy = 1
    eliminated = False

    # 1. swaps
    swap_diffs = set()
    gswaps = []  # filter swaps that actually hit the gadget
    gbytes = range(g.start, g.end)

    for s in swaps:
        # sbytes = [xrange(i.addr, i.addr+i.inst_len) for i in swap.get_instrs()]
        # if set(itertools.chain(*sbytes)) & set(xrange(g.start, g.end)):
        #  gswaps.append(swap)
        for ins in s.get_instrs():
            if any(ins.addr <= b < ins.addr + len(ins.bytes) for b in gbytes):
                gswaps.append(s)
                break

    # XXX use only at most 10 swaps here .. otherwise it takes forever
    for i, swap_comb in enumerate(swap.gen_swap_combinations(gswaps[:10])):
        success, changed = swap.apply_swap_comb(swap_comb)
        if not success:
            continue
        diff = inp.get_diff(changed)
        _add_if_hit(g, diff, swap_diffs)
        for ins in changed:
            ins.reset_changed()
        if i > 1000:
            print "killing after 1000 swap combinations"
            break

    entropy *= len(swap_diffs) + 1
    eliminated = any(g.addrs[-1] == d[1] for d in itertools.chain(*swap_diffs))

    print "\tswaps:", len(swap_diffs)

    # 2. preservs
    preserv_diffs = set()

    # 2.1 global substitution
    implicit = reduce(lambda x, y: x | y,
                      [i.implicit for i in f.instrs if not i.f_exit], set())
    preserv_regs = [
        reg for reg, pushes, pops in preservs if reg not in implicit
    ]
    preserv_combs = []

    if len(preserv_regs) >= 2:
        preserv_combs.extend(itertools.combinations(preserv_regs, 2))

    preserv_combs.extend(itertools.product(preserv_regs, avail_regs))

    for r1, r2 in preserv_combs:
        for ins in f.instrs:
            if not ins.swap_registers(r1, r2):
                break
        else:
            diff = inp.get_diff(f.instrs)
            _add_if_hit(g, diff, preserv_diffs)
        for ins in f.instrs:
            ins.reset_changed()

    # 2.2 reorder pushes/pops
    # XXX: a preserved register is used only after it's pushed!
    #      and only before it's poped!
    # augment each ins in the preservs with blocks and find first/last
    preserv_blocks = set()

    for reg, pushes, pops in preservs:
        for ins in itertools.chain(pushes, pops):
            ins.block = next((b for b in f.blocks if ins in b.instrs), None)
            if not hasattr(ins.block, 'first'):
                ins.block.first = ins.block.instrs.index(ins)
                ins.block.last = ins.block.instrs.index(ins)
            else:
                ins.block.first = min(ins.block.first,
                                      ins.block.instrs.index(ins))
                ins.block.last = max(ins.block.last,
                                     ins.block.instrs.index(ins))
            preserv_blocks.add(ins.block)

    # group preservs in the same block and reorder them
    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)])

    # do reorder of pushes/pops
    for group in (g for g in preservs_groups if len(g) > 1):
        for group_perm in itertools.permutations(group):
            for block in preserv_blocks:
                block.rinstrs = block.instrs[:]
                block.curr_first = block.first
                block.curr_last = block.last
            for reg, pushes, pops in group:
                for push in pushes:
                    push.block.rinstrs.remove(push)
                    push.block.rinstrs.insert(push.block.curr_first, push)
                    push.block.curr_first += 1
                for pop in reversed(pops):
                    pop.block.rinstrs.remove(pop)
                    pop.block.rinstrs.insert(pop.block.curr_last - 1, pop)
                    pop.block.curr_last -= 1
            diff = set()
            for block in preserv_blocks:
                diff.update(inp.get_block_diff(block))
            _add_if_hit(g, diff, preserv_diffs)

    entropy *= len(preserv_diffs) + 1
    eliminated = eliminated or any(g.addrs[-1] == d[1]
                                   for d in itertools.chain(*preserv_diffs))

    print "\tpreservs:", len(preserv_diffs)

    # overlaping gadgets!
    if g.overlap:

        # 3. equiv
        equiv_instrs = []

        for ins in f.instrs:
            if equiv.check_equiv(ins):
                diff = inp.get_diff([ins])
                if any(g.start <= ea < g.end for ea, orig, curr in diff):
                    equiv_instrs.append(ins)
                eliminated = eliminated or any(g.addrs[-1] == d[1]
                                               for d in diff)
                ins.reset_changed()

        sr_equiv = [
            i for i in equiv_instrs if i.bytes[i.opc_off] in objs.same_regs
        ]
        entropy *= 2**(len(equiv_instrs) - len(sr_equiv))
        entropy *= 5**len(sr_equiv)

        print "\tequiv (instrs):", len(
            equiv_instrs), "(%d sr_equiv)" % len(sr_equiv)

        # 4. reorder
        reorder_diffs = set()

        # find the block(s) of the gadget
        for block in f.blocks:
            if block.begin <= g.start < block.end or block.begin <= g.end < block.end or (
                    g.start <= block.begin and g.end >= block.end):
                # dag = reorder.BuildBBDependenceDAG(block)
                # for order in itertools.permutations(block.instrs):
                #  # all should be forward edges, from left to right
                #  if any(order.index(u) < order.index(v) for u, v in dag.edges()):
                #    continue
                for order in reorder.gen_topological_sortings(block):
                    block.rinstrs = order
                    diff = inp.get_block_diff(block)
                    _add_if_hit(g, diff, reorder_diffs)

        eliminated = any(g.addrs[-1] == d[1]
                         for d in itertools.chain(*reorder_diffs))
        entropy *= len(reorder_diffs) + 1

        print "\treorder:", len(reorder_diffs)

    if not g.overlap:
        # 4. reorder in non-overlapping
        reorder_breakes = 0

        # find the block(s) of the gadget
        for block in f.blocks:
            if block.begin <= g.start < block.end or block.begin <= g.end < block.end or (
                    g.start <= block.begin and g.end >= block.end):
                # print "will work on block:", block
                for order in reorder.gen_topological_sortings(block):
                    # print "test this order:", order
                    block.rinstrs = order
                    # 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)
                    for ins in (f.code[a] for a in g.addrs if a in f.code):
                        if ins.addr != ins.raddr and ins.raddr < g.start or ins.raddr >= g.end:
                            reorder_breakes += 1
                            break

        entropy *= reorder_breakes + 1

        print "\treorder (non-overlapping):", reorder_breakes

    print "\tgadget entropy:", entropy, "eliminated:", eliminated

    return entropy, eliminated
示例#7
0
文件: eval.py 项目: kevinkoo001/ropf
def get_entropy(f, g, live_regs, swaps, preservs, avail_regs):
    """Given a gadget, it returns the number of different ways that it can be
    broken. A second return value indicates whether this gadget can be
    eliminated (entropy)."""

    def _add_if_hit(g, diff, diffs):
        gdiff = tuple(d for d in diff if g.start <= d[0] < g.end)  # d[0] is ea
        old_diffs_len = len(diffs)
        if len(gdiff) > 0:
            diffs.add(gdiff)
        return old_diffs_len != len(diffs)

    entropy = 1
    eliminated = False

    # 1. swaps
    swap_diffs = set()
    gswaps = []  # filter swaps that actually hit the gadget
    gbytes = range(g.start, g.end)

    for s in swaps:
        # sbytes = [xrange(i.addr, i.addr+i.inst_len) for i in swap.get_instrs()]
        # if set(itertools.chain(*sbytes)) & set(xrange(g.start, g.end)):
        #  gswaps.append(swap)
        for ins in s.get_instrs():
            if any(ins.addr <= b < ins.addr + len(ins.bytes) for b in gbytes):
                gswaps.append(s)
                break

    # XXX use only at most 10 swaps here .. otherwise it takes forever
    for i, swap_comb in enumerate(swap.gen_swap_combinations(gswaps[:10])):
        success, changed = swap.apply_swap_comb(swap_comb)
        if not success:
            continue
        diff = inp.get_diff(changed)
        _add_if_hit(g, diff, swap_diffs)
        for ins in changed:
            ins.reset_changed()
        if i > 1000:
            print "killing after 1000 swap combinations"
            break

    entropy *= len(swap_diffs) + 1
    eliminated = any(g.addrs[-1] == d[1] for d in itertools.chain(*swap_diffs))

    print "\tswaps:", len(swap_diffs)

    # 2. preservs
    preserv_diffs = set()

    # 2.1 global substitution
    implicit = reduce(lambda x, y: x | y, [i.implicit for i in f.instrs if not i.f_exit], set())
    preserv_regs = [reg for reg, pushes, pops in preservs if reg not in implicit]
    preserv_combs = []

    if len(preserv_regs) >= 2:
        preserv_combs.extend(itertools.combinations(preserv_regs, 2))

    preserv_combs.extend(itertools.product(preserv_regs, avail_regs))

    for r1, r2 in preserv_combs:
        for ins in f.instrs:
            if not ins.swap_registers(r1, r2):
                break
        else:
            diff = inp.get_diff(f.instrs)
            _add_if_hit(g, diff, preserv_diffs)
        for ins in f.instrs:
            ins.reset_changed()

    # 2.2 reorder pushes/pops
    # XXX: a preserved register is used only after it's pushed!
    #      and only before it's poped!
    # augment each ins in the preservs with blocks and find first/last
    preserv_blocks = set()

    for reg, pushes, pops in preservs:
        for ins in itertools.chain(pushes, pops):
            ins.block = next((b for b in f.blocks if ins in b.instrs), None)
            if not hasattr(ins.block, 'first'):
                ins.block.first = ins.block.instrs.index(ins)
                ins.block.last = ins.block.instrs.index(ins)
            else:
                ins.block.first = min(ins.block.first, ins.block.instrs.index(ins))
                ins.block.last = max(ins.block.last, ins.block.instrs.index(ins))
            preserv_blocks.add(ins.block)

    # group preservs in the same block and reorder them
    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)])

    # do reorder of pushes/pops
    for group in (g for g in preservs_groups if len(g) > 1):
        for group_perm in itertools.permutations(group):
            for block in preserv_blocks:
                block.rinstrs = block.instrs[:]
                block.curr_first = block.first
                block.curr_last = block.last
            for reg, pushes, pops in group:
                for push in pushes:
                    push.block.rinstrs.remove(push)
                    push.block.rinstrs.insert(push.block.curr_first, push)
                    push.block.curr_first += 1
                for pop in reversed(pops):
                    pop.block.rinstrs.remove(pop)
                    pop.block.rinstrs.insert(pop.block.curr_last - 1, pop)
                    pop.block.curr_last -= 1
            diff = set()
            for block in preserv_blocks:
                diff.update(inp.get_block_diff(block))
            _add_if_hit(g, diff, preserv_diffs)

    entropy *= len(preserv_diffs) + 1
    eliminated = eliminated or any(g.addrs[-1] == d[1] for d in itertools.chain(*preserv_diffs))

    print "\tpreservs:", len(preserv_diffs)

    # overlaping gadgets!
    if g.overlap:

        # 3. equiv
        equiv_instrs = []

        for ins in f.instrs:
            if equiv.check_equiv(ins):
                diff = inp.get_diff([ins])
                if any(g.start <= ea < g.end for ea, orig, curr in diff):
                    equiv_instrs.append(ins)
                eliminated = eliminated or any(g.addrs[-1] == d[1] for d in diff)
                ins.reset_changed()

        sr_equiv = [i for i in equiv_instrs if i.bytes[i.opc_off] in objs.same_regs]
        entropy *= 2 ** (len(equiv_instrs) - len(sr_equiv))
        entropy *= 5 ** len(sr_equiv)

        print "\tequiv (instrs):", len(equiv_instrs), "(%d sr_equiv)" % len(sr_equiv)

        # 4. reorder
        reorder_diffs = set()

        # find the block(s) of the gadget
        for block in f.blocks:
            if block.begin <= g.start < block.end or block.begin <= g.end < block.end or (
                            g.start <= block.begin and g.end >= block.end):
                # dag = reorder.BuildBBDependenceDAG(block)
                # for order in itertools.permutations(block.instrs):
                #  # all should be forward edges, from left to right
                #  if any(order.index(u) < order.index(v) for u, v in dag.edges()):
                #    continue
                for order in reorder.gen_topological_sortings(block):
                    block.rinstrs = order
                    diff = inp.get_block_diff(block)
                    _add_if_hit(g, diff, reorder_diffs)

        eliminated = any(g.addrs[-1] == d[1] for d in itertools.chain(*reorder_diffs))
        entropy *= len(reorder_diffs) + 1

        print "\treorder:", len(reorder_diffs)

    if not g.overlap:
        # 4. reorder in non-overlapping
        reorder_breakes = 0

        # find the block(s) of the gadget
        for block in f.blocks:
            if block.begin <= g.start < block.end or block.begin <= g.end < block.end or (
                            g.start <= block.begin and g.end >= block.end):
                # print "will work on block:", block
                for order in reorder.gen_topological_sortings(block):
                    # print "test this order:", order
                    block.rinstrs = order
                    # 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)
                    for ins in (f.code[a] for a in g.addrs if a in f.code):
                        if ins.addr != ins.raddr and ins.raddr < g.start or ins.raddr >= g.end:
                            reorder_breakes += 1
                            break

        entropy *= reorder_breakes + 1

        print "\treorder (non-overlapping):", reorder_breakes

    print "\tgadget entropy:", entropy, "eliminated:", eliminated

    return entropy, eliminated