绝大部分tweak正常工做的基础, 它由MobileHooker MobileLoader Safe mode 组成.ios
替换系统函数. 也就是所谓的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
做用是加载第三方dylib. iOS 启动时, 会由launchd将MobileLoader载入内存, 而后MobileLoader会根据dylib的同名plist文件指定的做用范围, 有选择地在不一样进程里经过dlopen函数打开目录/Library/MobileSubstrate/DynamicLibraries/ 下的全部dylib.ssh
因为tweak本质是dylib, 寄生在别的进程里, 一旦出错可能会致使进程崩溃, 而若是是SpringBoard等系统进程, 则会形成iOS 系统瘫痪, 因此CydiaSubstrate引入Safe mode, 他会捕获SIGTRAP SIGABRT SIGILL SIGBUS SIGSEGV SIGSYS这六种信号, 而后进入安全模式. 安全模式里全部基于CydiaSubstrate的第三方均会被禁用. 并且这个插件要本身去安装, 越狱以后是不会自动安装的, 因此本人以前的手机就白苹果了, 若是有这个插件能够避免一些问题的出现, 不过白苹果也是能够解决的, 经过iTunes刷机就行了, 仍是能够恢复正常的, 但系统就是最新的了.iphone
首先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命令, 能够获取类对象的地址.
全称 Low Level Debugger 苹果出品, 内置Xcode中的动态调试工具, 运行在Mac中. LLDB功能能够归纳如下四点:
(1) 在指定的条件下启动程序
(2) 在指定的条件下中止程序
(3) 在程序中止的时候对程序进行改动, 观察程序的执行过程有什么变化.
(4) 在程序中止的时候检查程序内部发生的事.
运行在iOS 上, 它做为服务端, 实际执行LLDB(客户端)传过来的命令, 再把执行结果反馈给LLDB显示给用户. 所谓的远程调试. 默认iOS 上没有安装debugserver, 只有设备链接过Xcode, 并运行调试过才会把debugserver安装到iOS 的 /Developer/usr/bin/ 目录. 由于缺乏task_for_pid权限,因此只能调试本身的App.
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. 如图:
而后执行:
process connect connect://iOSIP:1234
复制代码
记得把iOSIP换成本身手机的IP.
成功后如图:
在这以前debugserver启动过进程或者附加了进程才能够.
因此电脑终端最好开倆个窗口好操做些, 用手机终端则麻烦不少.
这个时候咱们就能够开始调试了, 下面看一下经常使用的LLDB命令.
用于列举当前进程中的全部模块, 由于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看就能够了.
和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.
这个命令通常用于自动观察某个断点触发时的上下文变化, 后面会用到.
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
复制代码