iOS逆向学习之八(动态调试)

什么是动态调试?

动态调试就是在咱们的程序运行之时,经过下断点、打印等一系列方式查看参数、返回值、函数调用流程等等。不只是在iOS开放中须要动态调试,在任何语言的开发过程当中都须要用到动态调试python

Xcode如何进行动态调试?

Xcode编译器和调试器

  • Xcode最先使用的是GUN开发的GCC编译器,可是从xcode5以后开始使用自研的LLVM编译器,能够点击查看GCCLLVM的介绍
  • Xcode调试器早期也是使用的GUN开发的GDB调试器,以后也替换成了自研的LLDB调试器,能够点击查看GDBLLDB的介绍。

Xcode调试App的流程

  • 首先在Xcode中会自带一个叫作==debugserver==的工具,存放在/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/De viceSupport/9.1/DeveloperDiskImage.dmg/usr/bin/debugserver目录下,当咱们使用Xcode在iPhone上运行咱们的程序时,Xcode会将==debugserver==安装到咱们的iPhone上,具体安装路径为/Developer/usr/bin/debugserver
  • Xcode链接上手机后,经过自带的==LLDB==编译器向iPhone上的==debugserver==传输指令,==debugserver==接收到指令以后将指令运行到App中,App执行指令以后将结果返回为==debugserver==,而后==debugserver==会将信息反馈给==LLDB==,最后==LLDB==会将信息打印到Xcode上。
  • 可是Xcode这种调试方式有很大局限性,由于只能调试经过Xcod安装的App

如何不经过Xcode动态调试任意App?

可使用终端取代Xcode来对App进行动态调试正则表达式

debugserver环境搭建

方法1、经过ldid进行签名

  • 获取到iPhone下/Developer/usr/bin/debugserver目录中的debugserver工具,复制到Mac上
  • 因为经过Xcode安装的==debugserver==权限不足,只能调试Xocde安装的App,因此咱们要给==debugserver==增长更多的权限。
  • 经过ldid -e指令导出==debugserver==的权限信息
ldid -e debugserver > debugserver.entitlements
复制代码
  • 在debugserver.entitlements中增长如下两个权限
    • get-task-allow
    • task_for_pid-allow

  • 经过ldid对==debugserver==进行从新签名
ldid -Sdebugserver.entitlements debugserver
复制代码
  • 因为/Developer/usr/bin/目录是只读的,因此咱们将从新签名过的==debugserver==放在/usr/bin/下,而后对==debugserver==增长运行权限,就能够在终端使用==debugserver==了
chmod +x /usr/bin/debugserver
复制代码

方法2、经过codesign对debugserver进行签名

#查看权限基本信息
codesign -d --entitlements - debugserver

#签名权限
codesign -f -s - --entitlements debugserver.entitlements debugserver

#也能够简写为
codesign -fs - --entitlements debugserver.entitlements debugserver
复制代码

让debugserver附加到某个进程

debugserver *:端口号 -a 进程
复制代码

*:端口号:表示使用iPhone上的某个端口启动debugserver服务(注意:不能使用保留端口号)
-a 进程:指定进程id或者进程名称express

使用debugserver启动App

debugserver -x auto *:端口号 App可执行文件路径
复制代码

在Mac上启动LLDB,远程链接iPhone上的debugserver

在以前的学习中,咱们知道可使用iPhone的ip地址来链接手机,可是这样须要保证手机和电脑在同一个wifi下,而且使用这种方式传输数据十分缓慢。因此,一般的作法是经过usb链接iPhone,将iPhone上的某个端口映射到Mac上的某个端口,而后然LLDB和Mac上的端口通讯便可xcode

debugserver attaching

  • 经过如下指令对iPhone的10089进行映射
python ./usbmuxd/tcprelay.py -t 22:10088 9999:10089
复制代码

此处的10089端口能够任意定义,只要不使用保留端口号便可。使用10088端口映射22端口,是为了和iPhone进行SSH通讯bash

  • 映射成功以后,使用9999端口启动==debugserver==服务。让==debugserver==附加到腾讯视频App进程,以下:
debugserver *:9999 -a live4iphone
复制代码
  • 若是出现如下效果,代表==debugserver==已经成功attach到了腾讯视频App上

在Mac上启动LLDB,远程链接iPhone上的debugserver服务

  • 首先在Mac上启动LLDB
➜  ~ lldb
(lldb)
复制代码
  • 经过Mac的10089端口链接==debugserver==服务
process connect connect://localhost:10089
复制代码

  • 因为链接上==debugserver==服务以后,程序是默认在断点状态,使用LLDB的c命令让程序继续运行
(lldb) c
Process 635 resuming
复制代码

经常使用的LLDB指令

LLDB指令的基本格式

<command> [<subcommand> [<subcommand>...]] <action> [-options [option- value]] [argument [argument...]]
复制代码

对应着app

命令 子命令 命令操做 命令选项 命令参数
复制代码

例如给test这个函数设置断点:iphone

breakpoint set -n test
复制代码

help指令

help指令能够帮助咱们快速查找LLDB指令的使用方法tcp

help breakpoint
help breakpoint set
复制代码

expression -- 指令

expression指令被用来执行一个表达式函数

expression self.view.backgroundColor = [UIColor redColor]
//或者
expression -- self.view.backgroundColor = [UIColor redColor]
复制代码
  • expression、expression --和指令print、p、call效果等同

  • expression -O -- 和指令po效果等同

expression后的 -- 表示命令选项结束符,表示全部的命令选项已经设置完毕,若是没有命令选项,--能够省略。若是expression以后有命令选项,则--不能省略。工具

thread backtrace

==thread backtrace==指令的做用是打印线程的堆栈信息,效果和 ==bt== 的效果相同。

(lldb) thread backtrace
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  * frame #0: 0x0000000102d4d61d TestFont`-[ViewController touchesBegan:withEvent:](self=0x00007fd2f86066d0, _cmd="touchesBegan:withEvent:", touches=1 element, event=0x00006000036d4ab0) at ViewController.m:26
    frame #1: 0x0000000106f6f8e8 UIKitCore`forwardTouchMethod + 353
    ......
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  * frame #0: 0x0000000102d4d61d TestFont`-[ViewController touchesBegan:withEvent:](self=0x00007fd2f86066d0, _cmd="touchesBegan:withEvent:", touches=1 element, event=0x00006000036d4ab0) at ViewController.m:26
    frame #1: 0x0000000106f6f8e8 UIKitCore`forwardTouchMethod + 353
    ......
复制代码

thread return []

让函数返回某个值,不会执行以后的代码。若是函数有返回值,在后面跟上返回值,若是函数没有返回值,就直接使用thread return便可

frame variable []

打印当前栈帧的变量

thread相关指令

如下指令从左到右依次表示:指令全称、指令简称、极简指令

  • thread continue、continue、c :让程序跳过断点继续运行
  • thread step-over、next、n :单步运行,将子函数当作总体一步执行
  • thread step-in、step、s :单步运行,遇到子函数会进入子函数
  • thread step-out、finish :直接执行完当前函数的全部代码,返回上一个函数
  • thread step-inst-over、nexti、ni
  • thread step-inst、stepi、si

si、ni和s、n指令相似,可是s、n是源码级别,si、ni是汇编指令级别。每一句OC代码会有一条或多条汇编指令构成,s、n指令表示一步一步执行每一句OC代码,而si、ni表示一步一步执行汇编指令。

breakpoint相关指令

breakpoint set

设置断点

  • breakpoint set -a 函数地址
  • breakpoint set -n 函数名
    • breakpoint set -n test
    • breakpoint set -n touchesBegan:withEvent:
    • breakpoint set -n "-[ViewController touchesBegan:withEvent:]"
  • breakpoint set -r 正则表达式

此处跟上正则表达式,会将全部匹配到的方法都加上断点

  • breakpoint set -s 动态库 -n 函数名
    将指定动态库的指定函数打上断点

breakpoint list

列出全部的断点,每一个断点都有单独的编号

breakpoint disable 断点编号

禁用断点

breakpoint enable 断点编号

启用断点

breakpoint delete 断点编号

删除断点

breakpoint command add 断点编号

给指定断点编号的断点预先设置须要执行的命令,到触发断点时,就会按顺序执行预先设置的命令

breakpoint command list 断点编号

查看某个编号的断点全部预先设置的命令

breakpoint command delete 断点编号

删除指定编号断点的全部预设命令

内存断点watchpoint

给指定的内存下断点,当内存中的数据发生改变时会触发

watchpoint set variable 变量

对指定的变量设置内存断点,当变量值改变的时候会触发

watchpoint set variable self->_age
复制代码

注意:此处不能使用self.age

watchpoint set expression 内存地址

对指定内存地址设置断点,做用和watchpoint set variable相同

watchpoint list

列出全部的内存断点

watchpoint disable 断点编号

禁用内存断点

watchpoint enable 断点编号

启用内存断点

watchpoint delete 断点编号

删除内存断点

watchpoint command add 断点编号

给指定断点编号的内存断点预先设置须要执行的命令,到触发内存断点时,就会按顺序执行预先设置的命令

watchpoint command list 断点编号

查看某个编号的内存断点全部预先设置的命令

watchpoint command delete 断点编号

删除指定编号内存断点的全部预设命令

image模块查询指令

image lookup

模块查询指令

  • image lookup -t 类型
    查找某个类型的信息

  • image lookup -a 内存地址
    根据内存地址查找在模块中的位置

  • image lookup -n 符号或函数名
    查找某个符号或者函数的位置

image list

列出全部所加载的模块信息

  • image list -o -f
    打印出模块的偏移地址、全路径

LLDB小技巧

  • 每次敲Enter键,都会自动执行上次的命令
  • 绝大部分的指令均可以使用缩写
(lldb) breakpoint list
(lldb) br li
(lldb) br l

(lldb) breakpoint set -n test
(lldb) br s -n test
复制代码
相关文章
相关标签/搜索