iOS逆向工程 iOS工具篇

CydiaSubstrate

绝大部分tweak正常工做的基础, 它由MobileHooker MobileLoader Safe mode 组成.ios

MobileHooker

替换系统函数. 也就是所谓的hook, 它主要包含如下两个函数:安全

(1) 其中MSHookMessageEx做用于OC函数, 经过调用method_setImplementation函数将[class selector] 的实现改成replacement, 达到hook的目的. 如 向一个NSString对象发送hasSuffix消息, 而作出hasPrefix的操做, 至关于把函数实现换了.bash

(2) MSHookFunction : 做用于C和C++函数, 经过编写汇编指令, 在进程执行到function时转而执行replacement, 同时保持function的指令及其返回地址, 使得用户能够选择性地执行function, 并保证进程可以在执行完replacement后继续正常运行. 并且MSHookFunction对function的指令总长度是有要求的, function全部指令加起来长度不能过短.(8字节)架构

MSHookFunction三个参数做用分别是: 替换的原函数 替换函数 被MobileHooker保存的原函数.这个体系写法以下:app

MobileLoader

做用是加载第三方dylib. iOS 启动时, 会由launchd将MobileLoader载入内存, 而后MobileLoader会根据dylib的同名plist文件指定的做用范围, 有选择地在不一样进程里经过dlopen函数打开目录/Library/MobileSubstrate/DynamicLibraries/ 下的全部dylib.ssh

Safe mode

因为tweak本质是dylib, 寄生在别的进程里, 一旦出错可能会致使进程崩溃, 而若是是SpringBoard等系统进程, 则会形成iOS 系统瘫痪, 因此CydiaSubstrate引入Safe mode, 他会捕获SIGTRAP SIGABRT SIGILL SIGBUS SIGSEGV SIGSYS这六种信号, 而后进入安全模式. 安全模式里全部基于CydiaSubstrate的第三方均会被禁用. 并且这个插件要本身去安装, 越狱以后是不会自动安装的, 因此本人以前的手机就白苹果了, 若是有这个插件能够避免一些问题的出现, 不过白苹果也是能够解决的, 经过iTunes刷机就行了, 仍是能够恢复正常的, 但系统就是最新的了.iphone

Cycript

是由saurik推出的一款脚本语言, 能够看做是Objective-JavaScript .

首先ssh到手机的进程, 而后 cycript, 出现cy# 的提示符就说明已成功启动cycript.函数

按下control + D , 先退出 Cycript. 若是要测试NSStrign类的 length函数功能, 则可注入任意链接了Foundation库的进程.工具

经过进程注入方式调用Cycript测试函数的步骤很简单, 以SpringBoard为例, 首先找到进程名或PID以下:测试

SpringBoard的进程PID是4634, 接下来输入 cycript-p 4634 或者 cycript-p SpringBoard, 把Cycript注入到SpringBoard, 这时Cycript已经运行到SpringBoard进程里了.

若是知道对象的内存地址, 还能够经过# 操做符来获取这个对象.

若是知道对象的内存地址, 还能够经过# 操做符来获取这个对象.

经过choose命令, 能够获取类对象的地址.

LLDB和debugserver

LLDB

全称 Low Level Debugger 苹果出品, 内置Xcode中的动态调试工具, 运行在Mac中. LLDB功能能够归纳如下四点:

(1) 在指定的条件下启动程序

(2) 在指定的条件下中止程序

(3) 在程序中止的时候对程序进行改动, 观察程序的执行过程有什么变化.

(4) 在程序中止的时候检查程序内部发生的事.


debugserver

运行在iOS 上, 它做为服务端, 实际执行LLDB(客户端)传过来的命令, 再把执行结果反馈给LLDB显示给用户. 所谓的远程调试. 默认iOS 上没有安装debugserver, 只有设备链接过Xcode, 并运行调试过才会把debugserver安装到iOS 的 /Developer/usr/bin/ 目录. 由于缺乏task_for_pid权限,因此只能调试本身的App.

配置debugserver

1.给debugserver减肥

因为本人用的是iPhone5s因此选择arm64的架构.

首先将未处理过的debugserver拷贝到电脑中(~/debugserver)这里能够直接用pp助手.

而后帮助debugserver减肥.

lipo -thin armv7s ~/debugserver -output ~/debugserver
复制代码

2.给debugserver添加task_for_pid权限

下载xml格式文件配置信息 iosre.com/ent.xml 到debugserver同级目录.

而后执行以下命令:

codesign -s - --entitlements ent.xml -f debugserver
复制代码

执行前确保xml文件和debugserver在同一个文件夹内, 并且执行当前命令时要在当前文件的文件夹中.

如图:

出现这样的提示就是成功了.


3.而后将处理过的debugserver拷贝到手机中(/usr/bin/)

这里没有覆盖以前的文件, 一是由于原版文件是不可写的, 没法覆盖, 二是由于/usr/bin/下的命令无须输入全路径就能够执行, 即在任何路径下运行debugserver均可以启动处理过的debugserver.

最后还要给debugserver赋予执行权限命令以下:

chmod +x /usr/bin/debugserver
复制代码

若是在电脑终端执行必需要ssh到当前手机才能够.


4.用debugserver启动或附加进程

  • 启动进程

    debugserver -x backboard *:1234 /Applications/MobileSMS.app/MobileSMS
    复制代码

    debugserver会启动MobileSMS, 并开启1234端口, 等待来自任何IP的LLDB接入.

    若是中途出现错误, 那么就有多是task_for_pid权限没加上.

  • 附加进程

    debugserver *:1234 -a "MobileSMS"
    复制代码

    其实附加进程和启动进程区别就是须要手动打开指定的App.

  • 错误

    若是出现如图:

    说明iOS上的/Developer/目录下缺乏必要的调试数据.由于没有在Xcode的Window->Devices菜单中添加此设备, 从新添加便可.


LLDB使用说明

在终端中输入lldb便可启动lldb. 如图:

而后执行:

process connect connect://iOSIP:1234
复制代码

记得把iOSIP换成本身手机的IP.

成功后如图:

在这以前debugserver启动过进程或者附加了进程才能够.

因此电脑终端最好开倆个窗口好操做些, 用手机终端则麻烦不少.

这个时候咱们就能够开始调试了, 下面看一下经常使用的LLDB命令.

1. image list

用于列举当前进程中的全部模块, 由于ASLR的关系, 每次进程启动时(就是当你打开一个应用时), 同一进程的全部模块在虚拟内存中的起始地址都会产生随机偏移. 我的理解其实就是App启动时在手机内存中是有一个起始的内存地址的, 而ASLR其实就是让App每次打开时的起始地址随机.

那么怎么获取模块的起始地址呢? 待LLDB连接debugserver后, 先输入以下口令:

image list -o -f
复制代码

  • 模块基地址

上图的输出中 第一列 [x] 是模块的序号. 第二列是ASLR产生随机偏移大小. 第三列是模块的全路径, 括号里是偏移以后的起始地址. 模块的起始地址术语叫模块基地址.

偏移后模块基地址 = 偏移前模块基地址 + ASLR偏移
复制代码

如上图MobileSubstrate.dylib的偏移前模块基地址 = 0x0000000104910000 - 0x0000000104910000 = 0

那这个0哪里来的呢? 咱们把MobileSubstrate.dylib放到IDA中.

把View-A拉到最上面看到的第一行, 其中0就是咱们计算后的偏移前基地址.

  • 符号基地址

    偏移后符号的基地址 = 模块ASLR偏移 + 符号基地址

    若是是偏移前只要减去ASLR偏移便可.

    符号偏移前基地址能够在IDA中根据符号来获取

    只要知道偏移前基地址从IDA看, ASLR偏移从LLDB看就能够了.

2. breakpoint

和Xcode中的断点同样, 只不过这里不是图形工具而已. 通常逆向工程中用到的:

b function 

在函数的起始位置设置断点

br s –a address

br s –a 'ASLROffset+address'

在地址处设置断点
复制代码

以我本身新建Xocde工程项目设置函数[ViewController buttonAction:]断点为例:

(1) 用IDA查看这个项目偏移前的基地址, 把项目二进制文件放入IDA中, 定位到buttonAction:方法能够看到:

第一条指令   SUB    SP, SP, #0x30 偏移前的基地址是0x100006728.  
复制代码

(2) 经过LLDB查看ASLR偏移 0xa8000

(3) 设置并触发断点:

指令的偏移后基地址 = 0x100006728 + 0xa8000 = 0x1000ae728

在LLDB中设置断点

br s -a 0x1000ae728
复制代码

其中Breakpoint后面的1是断点的序号, 之后会用到.

而后咱们点击屏幕上的按钮触发断点.

打印的是一些方法的信息, 当进程停下来后咱们能够用c命令继续运行.

还能够经过br dis 和 br en 和 br del 来禁用 启用 删除断点.

若是是禁用全部断点则执行

br dis
复制代码

禁用某个断点在后面加上断点的序号

br dis 1
复制代码

同理启用和删除断点也是同样.

br en  
br del
复制代码

另一个颇有用的命令就是在断点触发前执行预先设置的指令, 它的用法以下:

br com add 1
复制代码

而后出现如图:

其中po i 是要执行的指令, 而DONE是退出设置指令. 数字4是断点的序号.

这里设置了一条指令, 而后咱们点击按钮触发方法如图:

这个时候i的值是1.

这个命令通常用于自动观察某个断点触发时的上下文变化, 后面会用到.

3. print

LLDB主要功能之一是在程序中止的时候检查程序内部发生的事, 而这个功能是经过print命令完成的, 他能够打印某处的值. 以我本人最近开发的程序 -[HomePageController tableView:didSelectRowAtIndexPath:] 方法为例演示一系列用法.

po   $r0    输出r0对应的值
p    $r0    输出r0值的类型以及命令结果
p/x  $r0    输出r0的十六进制值
x/10 $r0    输出指针r0指向的连续10个字的数据


nexti(ni)   执行下一条机器指令  不会进入函数体
stepi(si)   执行下一条机器指令  会进入函数体
** 进不进入函数体的意思就是你再方法中调用其余方法, 而当断点到这个方法的时候, 若是是上面的指令会跳转的这个调用的方法里面, 而下面的指令不会进入. ** 


register write  r0  1   给寄存器r0赋值为1


复制代码
相关文章
相关标签/搜索