iOS逆向之动态调试
有时候想更了解别人App的调用流程,就需要在App运行的时候进行动态调试。动态调试指的是将程序运行起来,通过下断点、打印等方式,查看参数、返回值、函数调用流程等。
Xcode的动态调试原理
首先了解一下 Xcode
编译和调试器的发展。Xcode
中的编译器发展历程:GCC
-> LLVM
,调试器的发展历程:GDB
-> LLDB
。
Xcode
调试安装到手机上的应用的原理:Xcode
通过 LLDB
调试器把调试指令发送到手机上的 debugserver
, debugserver
再与相应的 APP
进行交互,达到调试的效果。
debugserver
一开始是存放在Mac的Xcode里面,路径:
1 | /Applications/Xcode.app/Contents/Developer/Platforms |
当 Xcode
识别到手机设备时,Xcode
会自动将 debugserver
安装到手机上。
Xcode
调试的局限性:一般情况下,只能调试通过 Xcode
安装的APP,无法调试其它APP。
给debugserver赋予权限
默认情况下 /Developer/usr/bin/debugserver
缺少一定的权限,只能调试通过Xcode安装的App,如果希望调试其它App,需要对 debugserver
重新签名,签上可以调试其它App的权限。
需要的两个权限为:get-task-allow
和 task_for_pid-allow
iPhone上的 /Developer
目录是只读的,无法直接对 /Developer/usr/bin/debugserver
文件签名,需要先把 debugserver
复制到Mac。
通过 ldid
命令导出文件以前的签名权限:
1 | $ ldid -e debugserver > debugserver.entitlements |
debugserver.entitlements
这个文件其实是个 plist
文件,在这个文件中加上上面提到的两个权限后,再通过 ldid
命令对文件重新签名。
1 | $ ldid -Sdebugserver.entitlements debugserver |
然后将已经签好权限的 debugserver
放到 /usr/bin
目录,便于找到 debugserver
指令。
debugserver附加到某个APP进程
1 | $ debugserver *:端口号 -a 进程 |
- *:端口号:使用iPhone的某个端口启动debugserver服务(不是保留端口)
- -a进程:输入APP的进程信息(进程ID或者进程名称)
Mac远程连接iPhone上的debugserver服务
启动LLDB:
1 | // 在终端输入 |
连接debugserver服务
1 | (lldb) process connect connect://手机IP地址:debugserver服务端口号 |
使用LLDB的c命令让程序先继续运行
1 | (lldb) c |
到此,就可以远程调试别人的App了。
常用的LLDB指令
- 给ViewController的test方法设置断点
1 | breakpoint set -n "-[ViewController test]" |
- 查看指令用户使用
help
指令:help breakpoint
等。 - 打印线程的堆栈信息:
thread backtrace
很多命令不在这里赘述,请参考:http://lldb.llvm.org/lldb-gdb.html
ASLR
获取 ASLR
的偏移量:
1 | image list -o -f |
打印结果的第二列前面的地址就是我们需要的 ASLR
的偏移量offset。
假如我们想给某个类中的test方法添加断点,那么通过 Hooper
工具找到该方法的第一个内存地址,假如为0x010101,然后地址加上我们得到的 ASLR
的偏移量就是该方法的实际地址。然后通过该地址给方法下断点。
1 | breakpoint set -o 0x010101+offset |
到此就给该方法添加了断点,之后当程序调用该方法的时候,会停在该断点出。
结语
练习 lldb
的各种指令时,推荐先在 Xcode
上练习各种用法,因为会有提示和直观的输出结果,更容易我们理解。