Debug iOS apps without symbols

Source: Internet
Author: User

Note:

Debugging here refers to using lldb to remotely debug iOS applications

Setting a breakpoint refers to setting a breakpoint on the ObjC method.

Use Cases:

1. debug the iOS app that has been strip

2. debug dylib of the iOS system that has been strip

When debugging iOS apps without symbols, it is inconvenient to set breakpoints:

1. App: When ASLR is not enabled, you must first find the method address and set a breakpoint for the address.

2. Dylib: When ASLR is not enabled, find the base address of dylib and calculate the offset.

If ASLR is enabled, it is more troublesome to set breakpoints.

I have been trying to solve this problem. I have thought about the following methods:

First, the ObjC language is a relatively dynamic language, so you can dump the class information and function address by using a tool such as class-dump.

In addition, the DWARF format is open standard,

Therefore, you can convert the output information of class-dump to DWARF to dynamically load symbols during debugging.

This method I am not the first thought of, this post has a detailed description: http://stackoverflow.com/questions/17554070/import-class-dump-info-into-gdb

However, after performing operations based on this method, it is found that the iOS application is ineffective and the process is cumbersome.

Later I thought that ObjC was formed by encapsulating a thin layer (Message characteristics) on the C language,

All ObjC method calls are eventually converted to C method calls,

Therefore, you can set breakpoints on the corresponding C function to solve the breakpoint setting problem,

How to obtain the address of the C function depends on the runtime method of ObjC, mainly involving:

1. object_getClass

2. NSSelectorFromString

3. class_respondsToSelector

4. class_getMethodImplementation

After resolving the problem of where to set the breakpoint,

Next, we need to solve the problem of easily setting breakpoints in lldb.

Lldb integrates the Python script engine, see: http://lldb.llvm.org/python-reference.html

Therefore, we can use the Python script to extend the lldb debugging command, mainly using the following functions:

1. lldb. debugger

2. lldb. debugger. GetSelectedTarget ()

3. lldb. debugger. GetSelectedTarget (). GetProcess ()

4. lldb. debugger. GetSelectedTarget (). GetProcess (). GetSelectedThread ()

5. lldb. debugger. GetSelectedTarget (). GetProcess (). GetSelectedThread (). GetSelectedFrame ()

6. lldb. frame. EvaluateExpression

7. lldb. debugger. HandleCommand

Script configuration method:

Method 1: Run command script import bt_objc.py In the debugging console.

Method 2: add the above command ~ /. Lldbinit. If the file does not exist, you can create it by yourself.

Script content:

  1 #!/usr/bin/python  2   3 '''  4 Author:   5     Proteas  6 Date:  7     2014-03-05  8 Purpose:  9     set breakpoint without symbols, for examle: stripped macho 10 Usage: 11     add the following line to ~/.lldbinit 12     command script import ~/.lldb/bt_objc.py 13 ''' 14  15 import lldb 16 import commands 17 import shlex 18 import optparse 19 import re 20  21 def __lldb_init_module (debugger, dict): 22     debugger.HandleCommand('command script add -f bt_objc.bt_objc bt_objc') 23     print 'The "bt_objc" command has been installed' 24  25 def create_command_arguments(command): 26     return shlex.split(command) 27      28 def is_command_valid(args): 29     "" 30     if len(args) == 0: 31         return False 32  33     arg = args[0] 34     if len(arg) == 0: 35         return False 36  37     ret = re.match('^[+-]\[.+ .+\]$', arg) # TODO: more strict 38     if not ret: 39         return False 40  41     return True 42  43 def get_class_name(arg): 44     match = re.search('(?<=\[)[^\[].*[^ ](?= +)', arg) # TODO: more strict 45     if match: 46         return match.group(0) 47     else: 48         return None 49  50 def get_method_name(arg): 51     match = re.search('(?<= )[^ ].*[^\]](?=\]+)', arg) # TODO: more strict 52     if match: 53         return match.group(0) 54     else: 55         return None 56  57 def is_class_method(arg): 58     if len(arg) == 0: 59         return False 60  61     if arg[0] == '+': 62         return True 63     else: 64         return False 65  66 def get_selected_frame(): 67     debugger = lldb.debugger 68     target = debugger.GetSelectedTarget() 69     process = target.GetProcess() 70     thread = process.GetSelectedThread() 71     frame = thread.GetSelectedFrame() 72  73     return frame 74  75 def get_class_method_address(class_name, method_name): 76     frame = get_selected_frame(); 77     class_addr = frame.EvaluateExpression("(Class)object_getClass((Class)NSClassFromString(@\"%s\"))" % "FigPluginView").GetValueAsUnsigned() 78     if class_addr == 0: 79         return 0 80  81     sel_addr = frame.EvaluateExpression("(SEL)NSSelectorFromString(@\"%s\")" % method_name).GetValueAsUnsigned() 82     has_method = frame.EvaluateExpression("(BOOL)class_respondsToSelector(%d, %d)" % (class_addr, sel_addr)).GetValueAsUnsigned() 83     if not has_method: 84         return 0 85  86     method_addr = frame.EvaluateExpression('(void *)class_getMethodImplementation(%d, %d)' % (class_addr, sel_addr)) 87  88     return method_addr.GetValueAsUnsigned() 89  90 def get_instance_method_address(class_name, method_name): 91     frame = get_selected_frame(); 92     class_addr = frame.EvaluateExpression("(Class)NSClassFromString(@\"%s\")" % class_name).GetValueAsUnsigned() 93     if class_addr == 0: 94         return 0 95  96     sel_addr = frame.EvaluateExpression("(SEL)NSSelectorFromString(@\"%s\")" % method_name).GetValueAsUnsigned() 97     has_method = frame.EvaluateExpression("(BOOL)class_respondsToSelector(%d, %d)" % (class_addr, sel_addr)).GetValueAsUnsigned() 98     if not has_method: 99         return 0100 101     method_addr = frame.EvaluateExpression('(void *)class_getMethodImplementation(%d, %d)' % (class_addr, sel_addr))102 103     return method_addr.GetValueAsUnsigned()104 105 def bt_objc(debugger, command, result, dict):106     args = create_command_arguments(command)107 108     if not is_command_valid(args):109         print 'please specify the param, for example: "-[UIView initWithFrame:]"'110         return111 112     arg = args[0]113     class_name = get_class_name(arg)114     method_name = get_method_name(arg)115 116     address = 0117     if is_class_method(arg):118         address = get_class_method_address(class_name, method_name)119     else:120         address = get_instance_method_address(class_name, method_name)121 122     if address:123         lldb.debugger.HandleCommand ('breakpoint set --address %x' % address)124     else:125         print "fail, please check the arguments"

The above script can also be downloaded from this link: https://raw.github.com/Proteas/lldb-scripts/master/bt_objc.py

After the script is configured, run the following command to set the breakpoint:

Bt_objc "-[UIView initWithFrame:]"

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.