예제 #1
0
    def read(self, file_name):

        fin = open(file_name, 'rb')

        magic_word = self.read_long(fin)

        if magic_word != SolutionWriter.MAGIC_WORD:
            raise RuntimeError('The file is not a binary solution file')

        program = {}
        original = {}

        try:
            addr_count = self.read_int(fin)
            for i in range(0, addr_count):
                addr = self.read_int(fin)
                count = self.read_int(fin)
                if count > 0:
                    program[addr] = [
                        CAPSInstruction(self.read_int(fin), addr)
                        for j in range(0, count)
                    ]
                    original[addr] = [
                        CAPSInstruction(program[addr][count - 1].encoding,
                                        addr)
                    ]
        finally:
            fin.close()

        return original, program
예제 #2
0
    def test_opcode_field(self):
        caps = CAPSInstruction(0xe52de004, 0x10550)  # str;lr, [sp, #-4]!
        self.assertEqual(caps.opcode_field, ARM_INS_STR)

        caps = CAPSInstruction(0xe28cca10, 0x10550)  # add ip, ip, #0x10000
        self.assertEqual(caps.opcode_field, ARM_INS_ADD)

        caps = CAPSInstruction(0x18bd8010, 0x10550)  # popne;{r4, pc}
        self.assertEqual(caps.opcode_field, ARM_INS_POP)
예제 #3
0
    def test_conditional_field(self):
        caps = CAPSInstruction(0xe52de004, 0x10550)  # str;lr, [sp, #-4]!
        self.assertEqual(caps.conditional_field, ARM_CC_AL - 1)

        caps = CAPSInstruction(0x106f4, 0x10550)  # strdeq r0, r1, [r1], -r4
        self.assertEqual(caps.conditional_field, ARM_CC_EQ - 1)

        caps = CAPSInstruction(0x18bd8010, 0x10550)  # popne;{r4, pc}
        self.assertEqual(caps.conditional_field, ARM_CC_NE - 1)
예제 #4
0
 def test_is_a(self):
     self.assertTrue(CAPSInstruction(0x18bd8010,
                                     0x10550).is_a('pop'))  # popne {r4, pc}
     self.assertTrue(CAPSInstruction(0xe92d4010,
                                     0x10550).is_a('push'))  # push {r4, lr}
     self.assertTrue(CAPSInstruction(
         0x106f4, 0x10550).is_a('str'))  # strdeq r0, r1, [r1], -r4
     self.assertTrue(CAPSInstruction(
         0xe28cca10, 0x10550).is_a('add'))  # add ip, ip, #0x10000
 def test_modify_rn(self):
     inst = CAPSInstruction('000209b4', 8)  # strheq;r0, [r2], -r4
     mod = InstructionModifier()
     self.assertEqual(
         'strheq\tr0, [r0], -r4',
         str(CAPSInstruction(mod.modify_rn(inst.encoding, 0), 8)))
     self.assertEqual(
         'strheq\tr0, [r4], -r4',
         str(CAPSInstruction(mod.modify_rn(inst.encoding, 4), 8)))
     self.assertEqual(
         'strheq\tr0, [sl], -r4',
         str(CAPSInstruction(mod.modify_rn(inst.encoding, 10), 8)))
 def test_modify_rm(self):
     inst = CAPSInstruction('000209b4', 8)  # strheq;r0, [r2], -r4
     mod = InstructionModifier()
     self.assertEqual(
         'strheq\tr0, [r2], -r0',
         str(CAPSInstruction(mod.modify_rm(inst.encoding, 0), 8)))
     self.assertEqual(
         'strheq\tr0, [r2], -r6',
         str(CAPSInstruction(mod.modify_rm(inst.encoding, 6), 8)))
     self.assertEqual(
         'strheq\tr0, [r2], -sl',
         str(CAPSInstruction(mod.modify_rm(inst.encoding, 10), 8)))
 def create_program(self):
     program = []
     program.append(CAPSInstruction('e1a03000', 0))  # mov;r3, r0
     program.append(CAPSInstruction('e59f1018', 1))  # ldr;r1, [pc, #0x18]
     program.append(CAPSInstruction('e1a00003', 2))  # mov;r0, r3
     program.append(CAPSInstruction('ebffff9e', 3))  # bl;#0x10594
     program.append(CAPSInstruction('e3a03000', 4))  # mov;r3, #0
     program.append(CAPSInstruction('e1a00003', 5))  # mov;r0, r3
     program.append(CAPSInstruction('e8bd8800', 6))  # pop;{fp, pc}
     program.append(CAPSInstruction('00010830', 7))  # andeq;r0, r1, r0, lsr r8
     program.append(CAPSInstruction('000209b4', 8))  # strheq;r0, [r2], -r4
     program.append(CAPSInstruction('00010570', 9))  # andeq;r0, r1, r0, ror r5
     return program
 def test_modify_rd(self):
     '0xe59f1018'
     inst = CAPSInstruction('e59f1018', 8)  # ldr	r1, [pc, #0x18]
     mod = InstructionModifier()
     self.assertEqual(
         'ldr\tr0, [pc, #0x18]',
         str(CAPSInstruction(mod.modify_rd(inst.encoding, 0), 8)))
     self.assertEqual(
         'ldr\tr4, [pc, #0x18]',
         str(CAPSInstruction(mod.modify_rd(inst.encoding, 4), 8)))
     self.assertEqual(
         'ldr\tsl, [pc, #0x18]',
         str(CAPSInstruction(mod.modify_rd(inst.encoding, 10), 8)))
예제 #9
0
    def read_functions(self):
        # Function header in our assembly
        p = re.compile("^\.\w+\:[0-9a-f]+\s*\<[\$|\w+]")

        if self._instruction_set != DisassembleReader.ARM_SET:
            raise RuntimeError("Instruction encoding not supported yet")

        result = []

        k, i = "no_method", 0
        result.append(ElfFunction(k))
        for line in open(self._filename):
            line = line.rstrip('\n')
            if p.match(line):
                k = line
                if k in result:
                    i += 1
                    k = line + i
                result.append(ElfFunction(k))
            elif len(line) > 0 and line[0] == ' ':
                e = line.split(":", 1)[1].split("  ", 1)[0].split(" ", 1)
                f = result[len(result) - 1]
                encoding = Instruction.reverse_endianess(e[1])
                f.instructions.append(CAPSInstruction(encoding, position=int(e[0], 16)))

        return result
예제 #10
0
def corrupt_program(program, err_percent, max_amount):
    """
    Corrupts a program.
    :param program: Program to corrupt
    :param err_percent: Percentage of instructions to be corrupted from 0 - 100.
                        The routine will always corrupt at least one instruction with one bit of error
    :param max_amount: Maximal amount of bit errors per instructions, meaning that each corrupted instructions can
                       have up to this amount of errors
    """
    if 0 > err_percent > 100:
        raise RuntimeError("Percent cannot be larger than 100 or lower than 0")

    max_amount = max(1, max_amount)
    err_percent /= 100

    len_program = len(program)

    corrupted_amount = math.ceil(max(1, len_program * err_percent))

    # Find the min and max address in the program
    min_addr = sys.maxsize
    max_addr = -sys.maxsize
    for k in program:
        min_addr = k if min_addr > k else min_addr
        max_addr = k if max_addr < k else max_addr

    while corrupted_amount > 0:
        p = random.randint(0, len_program) * 4 + min_addr
        if p in program and len(program[p]) == 1:
            a = random.randint(1, max_amount)
            for r in corrupt_bits(31, 0, a, program[p][0].encoding):
                if _encoding_not_in_list(r, program[p]):
                    program[p].append(CAPSInstruction(r,
                                                      program[p][0].address))
            corrupted_amount -= 1
예제 #11
0
    def _change_parts(self, changer, get_parts, with_part, frequency):
        """
        Change some part of the instruction to increase its frequency
        :param changer: method to change the instruction part
        :param next:  Function that tells if more parts of that type remains
        :param with_part: Instruction containing that part
        :param frequency: Frequency dictionary
        :param qos: Quality of Service function
        """
        qos = self._qos

        freq_sorted = list(frequency.keys())
        freq_sorted.sort(key=lambda k: frequency[k])

        progress_bar = TextProgressBar(iteration=0,
                                       total=len(freq_sorted),
                                       prefix='Changing Frequence:',
                                       decimals=0,
                                       bar_length=50,
                                       print_dist=1)

        # Go through all registers, from least frequent to more frequent
        for i in range(0, len(freq_sorted)):
            part = freq_sorted[i]
            # For all instructions containing this register
            for j in range(0, len(with_part[part])):
                instruction = with_part[part][j]
                # Try to change the register with a more frequent one, starting with the most frequent
                index = len(freq_sorted) - 1
                # Flag to indicate that at least a register was correctly changed
                any_correct = False
                while not any_correct and index > part:
                    # New, most frequent part
                    new_part = freq_sorted[index]
                    # Now try to change any infrequent register from the instruction.
                    # There could be more than one use of the part
                    # So try them all
                    encoding = instruction.encoding
                    for register_part in get_parts(encoding, part):
                        # Change the address
                        # Using the instruction modifier
                        encoding = changer(encoding, part, new_part,
                                           register_part)
                        # Run the program and check if it works
                        correct_qos = qos.run(encoding, instruction.address)
                        any_correct = any_correct or correct_qos
                        # If it is correct, update the frequency dictionary
                        if correct_qos:
                            instruction = CAPSInstruction(
                                encoding, instruction.address)
                            with_part[part][j] = instruction
                            if part in frequency:
                                frequency[part] -= 1
                    # The most frequent register was no good, try next one
                    if not any_correct:
                        index -= 1

            progress_bar.suffix = 'Iterations: {})'.format(i)
            progress_bar.progress()
예제 #12
0
def load_corrupted_program_from_json(file_path):
    with open(file_path) as data_file:
        data = json.load(data_file)
    result = {}
    for k, v in data.items():
        addr = int(k)
        result[addr] = v
        for i in range(0, len(v)):
            v[i] = CAPSInstruction(v[i], addr)
    return result
예제 #13
0
    def test_registers_used(self):
        # TODO: Change from capstone registers numbers to my register numbers
        caps = CAPSInstruction(0xe52de004, 0x10550)  # str lr, [sp, #-4]!
        regs = caps.registers_used()
        self.assertEqual(2, len(regs))
        self.assertTrue(AReg.LR in regs and AReg.SP in regs)

        caps = CAPSInstruction(0x106f4, 0x10550)  # strdeq r0, r1, [r1], -r4
        regs = caps.registers_used()
        self.assertEqual(3, len(regs))
        self.assertTrue(AReg.R0 in regs and AReg.R1 in regs
                        and AReg.R4 in regs)

        caps = CAPSInstruction(0x18bd8010, 0x10550)  # popne {r4, pc}
        regs = caps.registers_used()
        self.assertEqual(3, len(regs))
        self.assertTrue(AReg.R4 in regs and AReg.PC in regs
                        and AReg.SP in regs)
예제 #14
0
    def read_instructions(self):
        if self._instruction_set != DisassembleReader.ARM_SET:
            raise RuntimeError("Instruction encoding not supported yet")

        result = []

        for line in open(self._filename):
            if line[0] == ' ':
                e = line.rstrip('\n').split(":", 1)[1].split("  ", 1)[0].split(" ", 1)
                encoding = Instruction.reverse_endianess(e[1])
                instruction = CAPSInstruction(encoding, position=int(e[0], 16))
                result.append(instruction)

        return result
예제 #15
0
    def test_registers_written(self):
        caps = CAPSInstruction(0x18bd8010, 0x10550)  # popne {r4, pc}
        regs = caps.registers_written()
        self.assertEqual(3, len(regs))
        self.assertTrue(AReg.SP in regs and AReg.R4 in regs
                        and AReg.PC in regs)

        caps = CAPSInstruction(0xe92d4800, 0x10550)  # push {fp, lr}
        regs = caps.registers_written()
        self.assertEqual(0, len(regs))
예제 #16
0
def corrupt_instruction(program,
                        original_instruction,
                        address,
                        conditional=True,
                        registers=False,
                        opcode=False,
                        amount=2):
    # We corrupt an instruction
    bin_c = 1 if conditional else 0
    bin_c = bin_c + 1 if registers else bin_c
    bin_c = bin_c + 1 if opcode else bin_c
    amount = distribute_random_amount(amount, bin_c)
    corrupted = [original_instruction.encoding]
    if conditional:
        bin_c -= 1
        corrupted = corrupt_conditional(amount[bin_c],
                                        original_instruction.encoding)
    if registers:
        bin_c -= 1
        r = []
        for c in corrupted:
            r.extend([
                cc for cc in corrupt_registers(amount[bin_c], c) if cc not in r
            ])
        corrupted = r
    if opcode:
        bin_c -= 1
        r = []
        for c in corrupted:
            r.extend(
                [cc for cc in corrupt_opcode(amount[bin_c], c) if cc not in r])
        corrupted = r

    #program[address] = []
    for i in range(1, len(corrupted)):
        inst = CAPSInstruction(corrupted[i], original_instruction.address)
        if not inst.ignore:
            program[address].append(inst)

    return program[address]
예제 #17
0
    def read(self):

        functions = {}

        current_fn = None

        self.instructions = []
        section = None
        for line in open(self._filename):
            if line.strip() == "":
                continue
            elif line.startswith('.'):
                section = line.split(".")[1]
            else:
                if section.startswith('function'):
                    address, name = line.split(';')
                    functions[int(address, 16)] = ElfFunction(name.rstrip())
                elif section.startswith('init') or section.startswith('text') or \
                        section.startswith('plt') or section.startswith('fini'):
                    line_split = line.split(';')
                    try:
                        address, encoding = line_split[0], line_split[1]
                    except:
                        print('[ERROR] Cannot parse line: {}'.format(line))
                        continue
                    encoding = int(encoding, 16)
                    address = int(address, 16)
                    inst = CAPSInstruction(encoding, position=address)
                    if address in functions:
                        current_fn = functions[address]
                    if current_fn:
                        current_fn.instructions.append(inst)
                    self.instructions.append(inst)

        self.functions = [x for x in functions.values()]

        return self.functions, self.instructions
    def test_modify_register(self):
        inst1 = CAPSInstruction('000209b4', 8)  # strheq;r0, [r2], -r4
        inst2 = CAPSInstruction('e59f1018', 8)  # ldr	r1, [pc, #0x18]
        mod = InstructionModifier()
        self.assertEqual(
            'strheq\tr0, [r2], -r0',
            str(CAPSInstruction(mod.modify_register(inst1.encoding, 4, 0), 8)))
        self.assertEqual(
            'strheq\tr0, [r6], -r4',
            str(CAPSInstruction(mod.modify_register(inst1.encoding, 2, 6), 8)))

        self.assertEqual(
            'ldr\tr6, [pc, #0x18]',
            str(CAPSInstruction(mod.modify_register(inst2.encoding, 1, 6), 8)))
        self.assertEqual(
            'ldr\tr1, [r6, #0x18]',
            str(CAPSInstruction(mod.modify_register(inst2.encoding, 15, 6),
                                8)))
예제 #19
0
 def test_modifies_flags(self):
     self.assertTrue(CAPSInstruction(
         0xe3530000, 0x10550).modifies_flags())  # cmp r3, #0
     self.assertFalse(
         CAPSInstruction(0xe28cca10,
                         0x10550).modifies_flags())  # add ip, ip, #0x10000
예제 #20
0
 def test_constructor(self):
     caps = CAPSInstruction(0xe52de004, 0x10550)
     self.assertEqual(0x10550, caps.address)
     self.assertEqual(str(caps), 'str\tlr, [sp, #-4]!')
     # This is optional, but I need to check
     self.assertEqual(0x10550, caps._cap.address)
예제 #21
0
 def test_encoding(self):
     from_str = CAPSInstruction('000209b4', 8)
     from_int = CAPSInstruction(0x000209b4, 8)
     self.assertEqual(str(from_str), 'strheq\tr0, [r2], -r4')
     self.assertEqual(str(from_int), 'strheq\tr0, [r2], -r4')
예제 #22
0
 def test_is_push_pop(self):
     self.assertTrue(CAPSInstruction(0x18bd8010,
                                     0x10550).is_push_pop)  # popne {r4, pc}
     self.assertTrue(CAPSInstruction(0xe92d4010,
                                     0x10550).is_push_pop)  # push {r4, lr}
예제 #23
0
 def test_is_branch(self):
     self.assertTrue(CAPSInstruction(
         0xe5bef008, 0x10550).is_branch)  # ldr pc, [lr, #8]!
     self.assertTrue(CAPSInstruction(0xebffffeb,
                                     0x10550).is_branch)  # bl #0x105ac