debugserver&lldb,配合hopper调试oc的应用

一、启动IOS上的server和Mac上的client

IOS

debugserver 172.16.4.70:12345 -a ProductName

Mac

zeno@zeno-macbook ~ % lldb
(lldb) process connect connect://172.16.4.75:12345
(lldb) 
error: Process 1036 is currently being debugged, kill the process before connecting.
Process 1036 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
Process 2994 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
    frame #0: 0x00000001b88672d0 libsystem_kernel.dylib`mach_msg_trap + 8
libsystem_kernel.dylib`mach_msg_trap:
->  0x1b88672d0 <+8>: ret    

libsystem_kernel.dylib`mach_msg_overwrite_trap:
    0x1b88672d4 <+0>: mov    x16, #-0x20
    0x1b88672d8 <+4>: svc    #0x80
    0x1b88672dc <+8>: ret    
Target 0: (ProductName) stopped.

二、计算应用的 page0偏移量大小

(lldb) image list -o -f | grep ProductName
[ 0] 0x0000000000ce0000 /private/var/containers/Bundle/Application/C2FFA931-CA3D-4BE9-BCEC-8CF086F57AF4/ProductName.app/ProductName(0x0000000100ce0000)
(lldb) c
Process 2994 resuming

得到ProductName的page0段落大小是:0x0000000000ce0000

三、使用hopper给要调试函数找到函数地址

找到自己要下断点的函数地址,如下图:0000000100007d20

四、lldb设置断点

用上面的app偏移量+函数地址,就是函数运行在内存中的地址,注意,加号两边不要有空格,并且数字前面加上0x表示16进制,hopper的地址没有自动加上0x

(lldb) br set -a 0x0000000000ce0000+0x0000000100007d20
Breakpoint 1: where = ProductName`___lldb_unnamed_symbol1$$ProductName + 164, address = 0x0000000100ce7d20

设置完断点以后,例如现在下断点的函数是点击屏幕以后出发的,那么点击屏幕后会停在这个断点处
通过lldb 可以读取寄存器的值
例如输入re read查看寄存器的值

(lldb) re read
General Purpose Registers:
x0 = 0x000000011b276800
x1 = 0x0000000112e2f360 “touchesBegan_TableView:withEvent:”
x2 = 0x0000000280301560
x3 = 0x0000000283202b80
x4 = 0x000000016bbdc5c8

因为普通的oc方法会编译成c++方法,例如下面的test1::会改成objc_msgSend,

[vc test1:arg1 :arg2];
objc_msgSend(vc,@selector(test1::),arg1,arg2)

objc_msgSend的参数:

  • 参数1是调用的控制器
  • 参数2是方法名
  • 参数3是test1函数参数1
  • 参数4是test1函数参数2

参数1.2.3.4分别存在寄存器x0,x1,x2,x3里
所以在lldb调试方法的时候,寄存器内容如下:

po $x0.  //打印是调用的控制器
x/s $x1  //打印方法名
po $x2   //打印参数1
po $x3   //打印参数2..

x0寄存器是调用这个方法的对象

(lldb) re read x0
      x0 = 0x000000011b276800
(lldb) po $x0
<BaseMsgContentViewController: 0x11b276800>

x1寄存器是方法名

(lldb) re read x1
      x1 = 0x0000000112e2f360  "touchesBegan_TableView:withEvent:"
(lldb) x/s 0x0000000112e2f360
0x112e2f360: "touchesBegan_TableView:withEvent:"

x2 是参数1

(lldb) re read x2
x2 = 0x0000000280301560
(lldb) po $x2
{(
phase: Began tap count: 1 force: 0.133 window: ; layer = > view: > location in window: {237, 189.5} previous location in window: {237, 189.5} location in view: {177, 40.5} previous location in view: {177, 40.5}
)}

x3是参数2

(lldb) re read x3
x3 = 0x0000000283202b80
(lldb) po $x3
timestamp: 465.034 touches: {(
phase: Began tap count: 1 force: 0.133 window: ; layer = > view: > location in window: {237, 189.5} previous location in window: {237, 189.5} location in view: {177, 40.5} previous location in view: {177, 40.5}
)}

通过lr寄存器查看调用函数的地址

(lldb) re read lr
lr = 0x000000011e12e3b0  tweek_wechat.dylib`___lldb_unnamed_symbol381$$tweek_wechat.dylib + 104

通过bt指令查看函数调用栈

下面frame #1刚好就是上面 lr的地址,就是调用本函数的函数地址

(lldb) bt
* frame #0: 0x00000001076ece18 WeChat`___lldb_unnamed_symbol242619$$WeChat
    frame #1: 0x000000011e12e3b0 tweek_wechat.dylib`___lldb_unnamed_symbol381$$tweek_wechat.dylib + 104
    frame #2: 0x0000000110590b2c WeChat`___lldb_unnamed_symbol1610700$$WeChat + 244
    frame #3: 0x00000001ad369420 UIKitCore`forwardTouchMethod + 316
    frame #4: 0x00000001ad3692d0 UIKitCore`-[UIResponder touchesBegan:withEvent:] + 60
    frame #5: 0x00000001ad4cd0cc UIKitCore`-[UITableViewCell touchesBegan:withEvent:] + 136
    frame #6: 0x00000001ad369420 UIKitCore`forwardTouchMethod + 316
    frame #7: 0x00000001ad3692d0 UIKitCore`-[UIResponder touchesBegan:withEvent:] + 60
    frame #8: 0x00000001ad369420 UIKitCore`forwardTouchMethod + 316
    frame #9: 0x00000001ad3692d0 UIKitCore`-[UIResponder touchesBegan:withEvent:] + 60
    frame #10: 0x0000000107acb060 WeChat`___lldb_unnamed_symbol259286$$WeChat + 96

计算函数调用栈里面函数的地址

tweek_wechat.dylib 的函数是自己用tweek里面添加的hook方法的打印函数参数的方法
第1个函数 0x00000001076ece18 地址,就是咱们下断点的函数地址.
第2个函数 0x000000011e12e3b0 不是代码段的函数
第3个函数0x0000000110590b2c 是代码段的函数

frame #10: 0x0000000107acb060 WeChat`___lldb_unnamed_symbol259286$$WeChat + 96
这里计算frame #10的地址
是带偏移量的,减去app偏移量,用计算器算:
 0x0000000107acb060-0x0000000004220000=0x1038AB060

在hopper中找到地址对应的函数

快捷键g,把地址输入进去,跳转到汇编指令
也可以点击 上面Navigate->Go To Address or Symbol…

有的函数找不到,就多换几个
00000001038ab05c         bl         sub_107bfedbc+21112
00000001038ab060         adrp       x8, #0x111753000                            ; 0x111753314@PAGE
00000001038ab064         ldrsw      x8, [x8, #0x314]                            ; 0x111753314@PAGEOFF, objc_ivar_offset_BaseMessageCellView_m_bDisableAllOperation
在cydia中删掉自己写的tweek方法

删掉自己写的tweek打印方法可以在bt的时候可以直接查看原始的函数调用栈

app从启动开始就用lldb调试

debugserver -x auto localhost:20001 app包地址

关于Zeno Chen

本人涉及的领域较多,杂而不精 程序设计语言: Perl, Java, PHP, Python; 数据库系统: MySQL,Oracle; 偶尔做做电路板的开发,主攻STM32单片机
此条目发表在Objective-C分类目录。将固定链接加入收藏夹。