예제 #1
0
def parse_symbols(file_num_to_consider: List[str]) -> Set[str]:
    var.get(NL)
    current_line = var.get(CL)
    assert current_line == "# Address	Size    	File  Name"
    var.get(NL)
    symbol_line_pattern = re.compile(
        ".*?\[\s*(?P<file_num>\d+)\]\s*[\+-]\[(?P<obj_name>\S+)\s+(?P<method_name>\S+?)\]"
    )
    current_line = var.get(CL)
    objects_name = set()
    while current_line:
        if current_line.startswith("#"):
            break
        else:
            m = symbol_line_pattern.match(current_line)
            if m and m.group('file_num') in file_num_to_consider:
                objects_name.add(m.group('obj_name'))
        var.get(NL)
        current_line = var.get(CL)
    return objects_name
예제 #2
0
def _move_to_seg_and_sect(seg, sect):
    current_line = var.get(CL)
    while current_line:
        m = new_section_pattern.match(current_line)
        if m and m.group('segname') == seg and m.group('sectname') == sect:
            var.get(NL)
            return
        var.get(NL)
        current_line = var.get(CL)
    raise Exception(f'segment: {seg} section: {sect} not found')
예제 #3
0
def parse_link_map(lp, pod=None):
    var.set(CF, open(lp, 'r'))
    var.get(NL)
    current_line = var.get(CL)  #type:str
    file_num_to_consider = None
    object_names = None

    while current_line:
        if current_line.startswith("#"):
            if current_line.replace(" ", '') == object_file_start_line:
                file_num_to_consider = parse_object_files(pod=pod)
            elif current_line.replace(" ", '') == symbols_start_line:
                assert file_num_to_consider
                object_names = parse_symbols(file_num_to_consider)
            else:
                var.get(NL)
        else:
            var.get(NL)
        current_line = var.get(CL)

    assert object_names
    return object_names
예제 #4
0
def parse_object_files(pod=None) -> List:
    object_file_line_pattern = re.compile(
        "\[\s*(?P<file_num>\d+)\]\s+.+?\.a\((?P<file_name>\S+)\.o\)")
    var.get(NL)
    file_num_belongs_to_pod = []
    current_line = var.get(CL)  # type:str
    while current_line:
        if current_line.startswith("#"):
            break
        if pod and pod not in current_line:
            pass
        else:
            m = object_file_line_pattern.match(current_line)
            if m:
                file_num_belongs_to_pod.append(m.group('file_num'))
        var.get(NL)
        current_line = var.get(CL)
    return file_num_belongs_to_pod
예제 #5
0
def parse_class_list(ep) -> dict:
    current_file = subprocess.Popen(['otool', '-oV', ep],
                                    stdout=subprocess.PIPE).stdout
    var.set(CF, current_file)
    var.get(NL)
    _move_to_seg_and_sect('__DATA', '__objc_classlist')
    class_objects = {}
    current_line = var.get(CL)
    while current_line:
        if new_class_pattern.match(current_line):
            class_object = _parse_implemented_class()
            class_objects[class_object.name] = class_object
        elif new_section_pattern.match(current_line):
            break
        else:
            var.get(NL)
        current_line = var.get(CL)
    return class_objects
예제 #6
0
def parse_referenced_methods(ep) -> List:
    current_file = subprocess.Popen(
        ['otool', '-v', '-s', '__DATA', '__objc_selrefs', ep],
        stdout=subprocess.PIPE).stdout
    var.set(CF, current_file)
    var.get(NL)
    _move_to_seg_and_sect('__DATA', '__objc_selrefs')
    referenced_methods = []
    pattern = re.compile(
        "[0-9a-f]{16}\s*__TEXT:__objc_methname:(?P<method>\S+)")
    current_line = var.get(CL)
    while current_line:
        m = pattern.match(current_line)
        if m:
            referenced_methods.append(m.group("method"))
            # logger.info(f"method {referenced_methods[-1]} referenced")
        var.get(NL)
        current_line = var.get(CL)
    return referenced_methods
예제 #7
0
def _parse_method_list(class_name) -> list:
    current_line = var.get(CL)
    r = []
    if current_line.startswith("entsize"):
        var.get(NL)
        current_line = var.get(CL)
        assert current_line.startswith("count")
        count = int(current_line.split(" ")[-1])
        var.get(NL)
        while count > 0:
            current_line = var.get(CL)
            assert current_line.startswith(
                "name"), f"error with class {class_name}"
            method_name = current_line.split()[-1]
            r.append(method_name)
            var.get(NL)
            assert var.get(CL).startswith(
                "types"), f"error with class {class_name}"
            var.get(NL)
            assert var.get(CL).startswith(
                "imp"), f"error with class {class_name}"
            var.get(NL)
            count -= 1
    return r
예제 #8
0
def _parse_implemented_class() -> ObjectEntity:

    var.get(NL)
    name = None
    base_method_list = []
    base_properties = []
    base_protocols = []
    while True:
        current_line = var.get(CL)  #type:str
        if (not name) and current_line.startswith("name"):
            name = current_line.split(' ')[-1]
            var.get(NL)
        elif current_line.startswith("baseMethods"):
            assert name, f"error with line {current_line}"
            var.get(NL)
            base_method_list += _parse_method_list(name)
        elif current_line.startswith("baseProperties"):
            assert name, f"error with line {current_line}"
            var.get(NL)
            base_properties += _parse_property_list(name)
        elif current_line.startswith(data_baseProtocols):
            var.get(NL)
            base_protocols = _parse_protocol_list(name)
        elif new_class_pattern.match(
                current_line) or new_section_pattern.match(current_line):
            break
        else:
            var.get(NL)
    return ObjectEntity(name=name,
                        base_method_list=base_method_list,
                        base_property_list=base_properties,
                        base_protocol_list=base_protocols)
예제 #9
0
def _parse_protocol_list(class_name: object) -> object:
    current_line = var.get(CL)
    r = []
    if not current_line.startswith(data_baseProtocols_count):
        return r
    count = int(current_line.split(' ')[-1])
    var.get(NL)
    while count > 0:
        var.get(NL)
        var.get(NL)
        current_line = var.get(CL)
        assert current_line.startswith(data_baseProtocols_name)
        r.append(current_line.split(' ')[-1])
        while not current_line.startswith(
                data_baseProtocols_instanceProperties):
            var.get(NL)
            current_line = var.get(CL)
        var.get(NL)
        current_line = var.get(CL)
        count -= 1
    assert current_line.startswith(ivars)
    return r
예제 #10
0
def _parse_property_list(class_name) -> List:
    current_line = var.get(CL)
    r = []
    if current_line.startswith("entsize"):
        var.get(NL)
        current_line = var.get(CL)
        assert current_line.startswith("count")
        count = int(current_line.split(" ")[-1])
        var.get(NL)
        while count > 0:
            current_line = var.get(CL)
            assert current_line.startswith(
                "name"), f"error with class {class_name}"
            property_name = current_line.split(' ')[-1]
            r.append(property_name)
            var.get(NL)
            assert var.get(CL).startswith(
                "attributes"), f"error with class {class_name}"
            var.get(NL)
            count -= 1
    return r