iOS攻防 - (十二)LLDB和DebugServer配合使用
1.介绍
debugserver是运行在iOS上。从它的名字你就能看出,debugserver扮演着一个服务器的角色,可以执行在MAC OS X客户端执行LLDB命令,并把结果反映到终端界面上,通常也成为”remote debugging”远程调试。debugserver默认在iOS系统里是没有的,但是,只要我们用Xcode在iPhone上调试过程序,它就会自动安装到iOS的目录 /Developer/usr/bin/
。但是此种情况下,debugserver只能调试自己开发的程序。debug自己的程序多没意思,我们有源码了,什么都是一目了然,只要调试别人开发的程序,才有意思。所以,别担心,以下有一些小技巧教你如此调试别人的程序。
2.配置debugserver
2.1 首选从以下这张表中找出你的iOS设备对应的ARM类型
我的iOS设备是iPhone 5,所以对应的ARM类型是armv7s。
首先从iOS设备中把debugserver拷贝到OS X中,iOS路径是 /Developer/usr/bin/debugserver
,可以通过iFunBox拷贝,也可以通过scp命令,取决于你自己。这里我举栗子拷贝到OS X的Documents目录,然后执行如下瘦身命令
lipo -thin armv7s debugserver -output debugserver
armv7s,取决于你的iOS设备
2.2 给debugserver添加task_for_pid权限
下载 http://iosre.com/ent.xml 到 “/Users/victor/Documents” 的OSX目录下,然后运行以下命令:
/opt/theos/bin/ldid -Sent.xml debugserver
注意:-S和ent.xml中间没有空格
如果不知道theos和ldid,请
如果一切顺利,几秒钟内,这个命令就能执行完。倘若几分钟了,或者程序卡死在这条命令,那就取消吧,换一个方案。
下载 http://iosre.com/ent.plist 到 “/Users/victor/Documents/” 的OSX目录下,然后运行如下命令:
codesign -s - –entitlements ent.plist -f debugserver
2.3 拷贝修改好debugserver到iOS设备的 /usr/bin
目录下
VictorZhang@VictorZhang:~/Documents$ scp debugserver root@10.18.138.168:/usr/bin/debugserver
然后SSH登录到iOS设备,赋予debugserver执行权限
chmod +x /usr/bin/debugserver
有一件事需要声明,就是我们把debugserver拷贝到了 /usr/bin/
目录下,而不是覆盖原始的debugserver,主要是因为,一:原始的debugserver是不可写的;二:我们在使用debugserver时,可以直接使用命令 debugserver
不用带一长串路径。到此为止debugserver已经准备好了
2.4 使用debugserver对进程的启动和附加
拿微信举栗子,SSH连接到iOS设备上运行如下命令,表示开启WeChat应用的远程调试,任意IP可以连接,端口指定1234
debugserver *:1234 -a “WeChat”
此时,在MAC OS X端再打开一个终端,进行LLDB操作
lldb
(lldb) process connect connect://10.18.136.168:1234
具体的lldb命令详解,请看这里 http://lldb.llvm.org/lldb-gdb.html
这里的意思是,远程进程连接,连接到IP=10.18.136.168,端口=1234的设备上,也就是我的iPhone 5手机
但是我在连接时发生了错误,如图所示
Process 440 stopped
* thread #1, stop reason = signal SIGSTOP
frame #0: 0x00000001987c7570
error: memory read failed for 0x1987c7400
在官方书籍里说,这是LLDB的一个巨大bug,自从Xcode 6就开始了 把ARM和THUMB指令全部打乱混乱,专门针对armv7和armv7s的设备。我猜,Apple公司对外宣称这是一个bug,但是其实内部决定这是防止各位iOS逆向程序员对任意应用进行debug的一种行为表现
在官方书籍还说,上有政策,下有对策。我们有一个临时解决方案,就是下载Xcode 5.0.x 安装到Mac OS X,在安装时,要注意:因为Mac OS X本身有一个最新的Xcode 8.3.2 ,所以在安装Xcode 5.0.2时,在弹出的提示时要保留两者,keep both.
下载地址: http://adcdownload.apple.com/Developer_Tools/xcode_5.0.2/xcode_5.0.2.dmg
安装完后,在MAC OS X端再打开一个终端,进行LLDB操作
/Applications/Xcode5.app/Contents/Developer/usr/bin/lldb
(lldb) process connect connect://10.18.136.168:1234
发现还是报错,只是换了错误提示,无语。。。
已经在StackOverflow 提交一个问题,正等待回答。。。
https://stackoverflow.com/questions/44342680/failed-to-remote-debugging-on-using-command-line-process-connect-connect-iosi
也在iOSRE上提了,等着回答。。。
http://bbs.iosre.com/t/failed-to-remote-debugging-on-using-command-line-process-connect-connect-iosip-port/8259
终于在iOSRE上找到答案了,是debugserver瘦身时选择的架构的问题,对debugserver重新瘦身用arm64
lipo -thin arm64 debugserver -output debugserver
codesign -s - –entitlements ent.plist -f debugserver
然后,把debugserver在scp到iOS设备里,赋予执行权限chmod
当成功链接后,你会看到如下图所示
2.5 当debugserver连接上后,准备调试
2.5.1 image list
image list在lldb里,info shared在GDB里,作用都是列出main executable和所有依赖的库。
(lldb) process connect connect://10.18.136.168:1234
Process 68463 stopped
* thread #1: tid = 0x10b6f, 0x00000001987ace0c libsystem_kernel.dylib`mach_msg_trap + 8, queue = 'com.apple.main-thread, stop reason = signal SIGSTOP
frame #0: 0x00000001987ace0c libsystem_kernel.dylib`mach_msg_trap + 8
libsystem_kernel.dylib`mach_msg_trap + 8:
-> 0x1987ace0c: ret lr
libsystem_kernel.dylib`mach_msg_overwrite_trap:
0x1987ace10: movn x16, #31
0x1987ace14: svc #128
0x1987ace18: ret lr
(lldb) image list -o -f
[ 0] 0x00000000000a8000 /private/var/mobile/Containers/Bundle/Application/62733E8A-0E12-4F06-9F6B-A5C3ACAB0AF8/weixin.app/Lanxin(0x00000001000a8000)
[ 1] 0x0000000101acc000 /Library/MobileSubstrate/MobileSubstrate.dylib(0x0000000101acc000)
[ 2] 0x00000000053e4000 /Users/VictorZhang/Library/Developer/Xcode/iOS DeviceSupport/8.2 (12D508)/Symbols/usr/lib/libiconv.2.dylib
[ 3] 0x00000000053e4000 /Users/VictorZhang/Library/Developer/Xcode/iOS DeviceSupport/8.2 (12D508)/Symbols/usr/lib/libstdc++.6.dylib
[ 4] 0x00000000053e4000 /Users/VictorZhang/Library/Developer/Xcode/iOS DeviceSupport/8.2 (12D508)/Symbols/usr/lib/libxml2.2.dylib
[ 5] 0x00000000053e4000 /Users/VictorZhang/Library/Developer/Xcode/iOS DeviceSupport/8.2 (12D508)/Symbols/usr/lib/libz.1.dylib
[ 6] 0x00000000053e4000 /Users/VictorZhang/Library/Developer/Xcode/iOS DeviceSupport/8.2 (12D508)/Symbols/System/Library/Frameworks/AVFoundation.framework/AVFoun
......
上面输出的三列解释如下:
第一列,序号
第二列,由ASLR随机生成的image地址
第三列,image的全路径,括号里是(原始起始地址 + ASLR偏移地址)
重点:
1.最终运行的基地址 = 不包含偏移地址的基地址 + ASLR 偏移地址
2.不包含偏移地址的基地址可以在IDA中查看
3.ASLR 偏移地址可以在LLDB上查看
拿微信举例,如何断点
(1).假如我们现在已经连接上了debugserver,并且拿 -[WloginProtocol loginWithPasswd:retData:]:
举例
(2).那么该方法的基地址是多少?
答:e979e + f0000 = 1d979e
br s -a 0x1d979e
f0000地址如下图显示
其他参数和命令 http://lldb.llvm.org/lldb-gdb.html
>br l //查看所有断点
>br s -a 0xCC730 //设置断点
>br dis //禁用断点
>br en //启用断点
>br del //删除断点
>c //继续运行
//设置一组断点,通过以下命令
(lldb) br com add 1
Enter your debugger command(s). Type 'DONE' to end.
> po [$r0 class]
> p (char *)$r1
> c
> DONE