def replace_main_with_bkpt(binary):
    # Get the VMA and offset of the .text section
    for line in subprocess.check_output(['objdump', '-h', binary],
                                        universal_newlines=True).splitlines():
        tokens = line.split()
        if len(tokens) == 7 and tokens[1] == '.text':
            text_vma = hex_int(tokens[3])
            text_offset = hex_int(tokens[5])
            break

    # Get the VMA of the 'main' symbol
    for line in subprocess.check_output(['objdump', '-t', binary],
                                        universal_newlines=True).splitlines():
        tokens = line.split()
        if tokens and tokens[-1] == 'main':
            main_vma = hex_int(tokens[0])
            break

    # Calculate the offset of the main symbol within the binary
    main_offset = text_offset + (main_vma - text_vma)

    # Write a bkpt on this offset
    with open(binary, 'r+b') as f_bin:
        f_bin.seek(main_offset)
        f_bin.write(bytes.fromhex('700020e1'))
Exemple #2
0
    def __init__(self, f_map, line, alignment_info=None):
        tokens = line.split()

        self.name = tokens[0]
        if len(tokens) == 1:
            # Grab the next line and decode it
            line2 = next(f_map)
            tokens = line2.split()
            assert len(
                tokens) == 3, 'Can only handle entries of 3 tokens here!'
            self.address = hex_int(tokens[0])
            self.size = hex_int(tokens[1])
            self.obj = tokens[2]
        else:
            # Get the information from this line
            assert len(
                tokens) == 4, 'Can only handle entries of 4 tokens here!'
            self.address = hex_int(tokens[1])
            self.size = hex_int(tokens[2])
            self.obj = tokens[3]

        # If we can find the alignment, try to do so
        if alignment_info:
            obj_name = self.obj[self.obj.rfind('/') + 1:]
            obj = alignment_info.objects.get(obj_name, None)
            if obj:
                self.alignment = obj.sections.get(self.name, None)
                assert self.alignment, 'Could not find alignment information for this section!'
Exemple #3
0
    def read(cls, offset, header, lines):
        if header.startswith('L'):
            # Decode the line, if a string is empty the diff is 0
            tokens = header[1:].split(':')
            address_diff = hex_int(tokens[0]) if tokens[0] else 0
            size_diff = hex_int(tokens[1]) if tokens[1] else 0

            return (0, cls(offset, address_diff, size_diff))
        else:
            return (0, None)
Exemple #4
0
    def __init__(self, line):
        self.lines = []
        tokens = line.split()
        self.address = hex_int(tokens[1])
        self.size = hex_int(tokens[2])
        self.parameter_size = hex_int(tokens[3])
        self.name = tokens[4:]

        # Data will be added onto these later on
        self.publics = []
        self.stacks = []
Exemple #5
0
 def __init__(self, line):
     tokens = line.split()
     # Decode INIT records and other records differently
     if tokens[2] == 'INIT':
         self.address = hex_int(tokens[3])
         self.size = hex_int(tokens[4])
         self.entries = tokens[5:]
     else:
         self.address = hex_int(tokens[2])
         self.size = 0
         self.entries = tokens[3:]
Exemple #6
0
    def read(cls, header):
        if not header:
            return None

        tokens = header.split(':')
        if len(tokens) == 2:
            size_diff = hex_int(tokens[0]) * 8 if tokens[0] else 0
            address_diff = hex_int(tokens[1])
        else:
            size_diff = hex_int(tokens[0]) * 8
            address_diff = 0
        return cls(size_diff, address_diff)
Exemple #7
0
    def read(cls, offset, header, lines):
        if header.startswith('S'):
            tokens = header[1:].split(':')
            deleted_size = hex_int(tokens[0])
            added_size = hex_int(tokens[1])
            added_lines = []
            for line in lines[:added_size]:
                added_lines.append(Line(line))

            return (added_size, cls(offset, added_lines, deleted_size))
        else:
            return (0, None)
Exemple #8
0
    def read(cls, path):
        self = cls()
        with open(path, 'r') as f:
            # Find all the function patches and determine how many empty patches there are between them
            patch_lines = []
            for line in f:
                if 'F' in line:
                    # If we were gathering lines for a patch (we won't be in the beginning), create it
                    if patch_lines:
                        self.func_patches.append(FuncPatch.read(patch_lines))

                    # Add this line (the patch header) to the lines
                    patch_lines = [line]

                    # Find out the offset. If none is encoded it was 0. With the offset we also know
                    # how many empty function patches there are and can create them
                    token_pos = line.find('F')
                    offset = hex_int(
                        line[:token_pos]) if (token_pos != 0) else 0
                    for _ in range(offset):
                        self.func_patches.append(FuncPatch(''))

                else:
                    # Add this line for the patch we are preparing
                    patch_lines.append(line)

            # Finish last patch
            if patch_lines:
                self.func_patches.append(FuncPatch.read(patch_lines))

        return self
Exemple #9
0
    def __init__(self, map_path, align_path=None):
        # Load all section alignment information if it is present
        if align_path is not None:
            alignment_info = AlignmentInformation(align_path)
        else:
            alignment_info = None

        with open(map_path, 'r') as f_map:
            self.discarded_sections = []
            self.pre_sections = []
            self.main_sections = []
            self.post_sections = []

            # The map consists of several parts which we process differently
            target_sections = None
            for line in f_map:
                # Determine where in the map we are
                if 'Discarded input sections' in line:
                    target_sections = self.discarded_sections
                    continue

                if 'Memory Configuration' in line:
                    target_sections = None
                    continue

                if '*(.text.unlikely' in line:
                    target_sections = self.pre_sections
                    continue

                if '*(.text.[a-zA-Z0-9]*' in line:
                    target_sections = self.main_sections
                    continue

                if '*(.text.*' in line:
                    target_sections = self.post_sections
                    continue

                # This is the farthest we go, anything behind this is not useful for us
                if '*(.gnu.warning)' in line:
                    break

                # We haven't arrived to the good part yet
                if target_sections is None:
                    # Look for the start address of the text segment
                    m = re.search(
                        '(?<=PROVIDE \(__executable_start = SEGMENT_START)\s*(\("text-segment",)\s+(?P<base>\w+)(?=\))',
                        line)
                    if m:
                        self.text_start_address = hex_int(m.group('base'))

                    continue

                # Look at all lines containing .text., but ignore some
                if '.text' in line and not ('*' in line or '.ARM.extab.text.'
                                            in line or '.ARM.exidx.text.'
                                            in line or '.text.__stub' in line):
                    # Handle the line depending on where we are in the map
                    # Decode the entry into an object
                    target_sections.append(Section(f_map, line,
                                                   alignment_info))
Exemple #10
0
 def run_replay_tool(seed, sections, build_prefix, opportunity_log):
     for line in subprocess.check_output(
         [
             os.path.join(config.replay_dir, 'nop'),
             str(seed),
             str(config.nopinsertion_chance), build_prefix, opportunity_log
         ],
             universal_newlines=True).splitlines():
         # If the line is the start of a new section, add it as an entry to the dictionary with a new list onto which insertions will be added.
         if ':' in line:
             assert line not in sections, 'Duplicate section!'
             insertions = []
             sections[line] = insertions
         else:
             # For any insertion, the get offset at which it happens, and the size change it induces
             tokens = line.split()
             insertions.append(
                 (support.hex_int(tokens[0]), support.hex_int(tokens[1])))
Exemple #11
0
    def read(cls, offset, header, lines):
        if header.startswith('A'):
            size = hex_int(header[1:])
            added_lines = []
            for line in lines[:size]:
                added_lines.append(Line(line))

            return (size, cls(offset, added_lines))
        else:
            return (0, None)
Exemple #12
0
    def read(cls, lines):
        self = cls('')

        # Decode the header and remove it from the lines
        tokens = lines[0].rstrip().split('F')
        if len(tokens) == 2 and tokens[1]:
            self.stack_patch = StackPatch.read(tokens[1])
        del lines[0]

        # These lines consist of different patches, each with a header. We will iterate over the headers and
        # read in the lines associated with them.
        offset = -1
        idx = 0
        while idx < len(lines):
            # Get the header, strip the line, removing newline and such
            header = lines[idx].rstrip()

            # Get the location of the identifying uppercase, and the relative offset
            # If there relative offset is encoded, it was 0.
            up_idx = support.find_first_uppercase(header)
            offset += hex_int(header[:up_idx]) + 1 if (up_idx != 0) else 1

            # Handle the right type of patch
            idx += 1  # Move to the line after the header, easier indexing after this
            for patch_type in (AdditionPatch, DeletionPatch, LinePatch,
                               SubstitutionPatch):
                (size, patch) = patch_type.read(offset, header[up_idx:],
                                                lines[idx:])
                if patch:
                    self.patches.append(patch)
                    break

            # Go to the next header. This header has already been skipped, so skip the extra lines (size)
            idx += size

        return self
Exemple #13
0
 def read(cls, offset, header, lines):
     if header.startswith('D'):
         size = hex_int(header[1:])
         return (0, cls(offset, size))
     else:
         return (0, None)
Exemple #14
0
def get_binary_text_size(binary):
    for line in subprocess.check_output(['objdump', '-h', binary],
                                        universal_newlines=True).splitlines():
        tokens = line.split()
        if len(tokens) >= 3 and tokens[1] == '.text':
            return hex_int(tokens[2])
Exemple #15
0
 def __init__(self, line):
     tokens = line.split()
     self.address = hex_int(tokens[0])
     self.size = hex_int(tokens[1])
     self.location = Location(int(tokens[2]), int(tokens[3]))
Exemple #16
0
 def __init__(self, line):
     tokens = line.split()
     self.address = hex_int(tokens[1])
     self.parameter_size = hex_int(tokens[2])
     self.name = tokens[3:]