目录
需要补充一个连接
一、LLDB(Low Lever Debug)
默认内置于Xcode中的动态调试工具。标准的 LLDB 提供了一组广泛的命令,旨在与老版本的 GDB 命令兼容。 除了使用标准配置外,还可以很容易地自定义 LLDB 以满足实际需要。LLDB 的官方API文档。
1.1 断点设置
- 设置断点
breakpoint set -n testFun
set 是子命令
-n 是选项 是--name 的缩写!
breakpoint set --selector touchesBegan:withEvent:
:根据selector设置断点
breakpoint set --file ViewController.m --selector touchesBegan:withEvent:
添加内存地址断点
b 0x104C55FA4
查看断点列表
breakpoint list
删除
breakpoint delete 组号
禁用/启用
breakpoint disable 1
禁用组1断点
breakpoint enable 1
启用遍历整个项目中满足Game这个字符的所有方法
breakpoint set -r Game
:
1.2 流程控制
- 继续执行
continue c
- 单步运行,将子函数当做整体一步执行
n next
ni
单步运行汇编级别 - 单步运行,遇到子函数会进去
s
si
单步运行可跳转指令内部,汇编级别
stop-hook
让你在每次stop的时候去执行一些命令,只对breadpoint,watchpoint其他命令
执行代码expression
expression 指令,简写p
:打印变量的值
po
:打印对象信息, expression命令选项:-O 表示调用对象的discraption方法
image list
:镜像列表
b -[xxx xxx]
:为实例方法添加断点
x
:根据内存地址读取内存中的数据。
register read
:读取寄存器中的值
register write
写入寄存器
memory read
读取内存值
help breakpoint
:查看命令的帮助文档
bt
:打印当前堆栈信息
up
、down
、frame select 1
:上一个、下一个、选择堆栈的frame
frame variable
:查看当前方法中的self、_cmd、参数、局部变量
watchpoint set variable p1->_name
:观察属性的值变化(相当于KVO)
1.3 Debug时更改一个变量的值
p [params setObject:@"970407" forKey:@"bankCardNo"]
p [self func];//调用方法
1.4 为一组断点添加命令
break command add 1
:为第一组断点添加命令,当触发断点时会执行命令
(lldb) break command add 1
Enter your debugger command(s). Type 'DONE' to end.
> frame variable
> DONE
(lldb) c
Process 8310 resuming
frame variable
(ViewController *) self = 0x000000013f0085d0
(SEL) _cmd = "save:"
(UIButton *) sender = 0x000000013f009ff0
(lldb)
1.5 为所有断点添加一行命令命令
写法一:
target stop-hook add -o "frame variable"
写法二:
(lldb) target stop-hook add
Enter your stop hook command(s). Type 'DONE' to end.
> frame variable
> DONE
Stop hook #2 added.
(lldb)
target stop-hook list
:列出stop-hook列表
target stop-hook delete 2
:删除指定编号stop-hook
这种方式添加的stop-hook在下次执行后就会清空
1.6 通过文件添加 stop-hook
在Home目录中添加.lldbinit文件,并加入相关的命令即可
这样所有项目中进入断点就会执行.lldbinit文件中的stop-hook命令
二、LLDB动态调试工具
2.1 Chisel
chisel 安装链接,安装后重启Xcode即可使用
pviews
查看视图层级:
pvc
:查看控制器层级
pclass 类指针
:查看当前类的继承关系
pmethods 类指针
:查看类中方法
pmethods 类指针
:查看当前类的成员属性
fvc -v 控件指针
:查找控件属于哪个控制器
fv 控件类名
:查找指定控件类的所有实例
flicker 控件指针
:让控件在界面上闪两下
vs 控件指针
:在指定父控件/子控件/同级控件之间选择。q
退出调试状态
2.2 LLDB
- 下载LLDB到/opt目录
- Open up (or create) ~/.lldbinit
- Add the following command to your ~/.lldbinit file:
command script import /opt/LLDB/lldb_commands/dslldb.py
- 重启Xcode即可使用
search ViewController
: 查找指定类的所有实例
methods 类指针
:查看类中方法
sbt
:查看恢复了方法符号的堆栈信息
三、 Cycript
Cycript是由Cydia创始人Saurik推出的一款脚本语言,Cycript混合了OC、JavaScript语法的解释器,这意味着我们能够在一个命令中使用OC或者JavaScript,甚至两者并用。它能够挂钩正在运行的进程,能够在运行时修改很多东西。(Cycript 也是一款LLDB动态调试工具)
3.1 Cycript安装
官网: http://www.cycript.org/
下载后使用Cycript这个可执行文件,将cycript文件夹放在 /opt/cycript
如果出现dyld: Library not loaded: /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/libruby.2.0.0.dylib
解决方法:将/opt/MonkeyDev/bin/cycript
拷贝到/opt/cycript/cycript
为了方便使用,可以在~/.zshrc中配置环境变量(如果配置了MonkeyDev/bin/
就不用配置cycript
了)。
参照[iOS 逆向开发17:HOOK原理下(HOOK OC方法)]( 文章中五、使用MonkeyDev进行重新签名和代码注入
内容创建MonkeyApp:CycriptDemo,并重签名一个APP。
可以看到IPA包内容中的
FrameWorks
中注入了libcycript.dylib
。运行App后进程就可以调用这个库中的一些方法,来开启相应的端口让别人监听。别人就可以通过这个端口链接这个进程进入cy#环境HOOK当前进程中的数据。
3.2无线网络链接手机
真机运行CycriptDemo,Mac和手机链接同一个WIFi。终端执行以下命令
cycript -r 手机IP地址:6666
真机回到CycriptDemo界面终端就会输出cy#
表示链接成功
3.3 Cycript常用命令
进入Cycript环境
cycript
附加进程(连接手机调试)
cycript –r ip:port
退出Cycript环境
Ctrl + D
Cycript 调试命令
pviews()
:查看视图层级
pvcs()
:查看控制器层级(这两个命令是/Monkey项目/Config/MDConfig.plist中配置后网络加载的.cy文件,如果无法使用可以参照四、Cycript 高级用法下载.cy文件手动加载到项目中)
UIWindow.keyWindow()
:获取keyWindow
var keyWindow = UIWindow.keyWindow()
:定义变量
[UIApplication sharedApplication]
或UIApp
:获取Application单例对象
keyWindow.recursiveDescription()
:查看视图层级(循环打印子视图)
keyWindow.recursiveDescription().toString()
:格式化打印(遇到\n换行)
# 对象地址
:拿到该对象,可用于调用方法
* 对象地址
:可以取出对象的成员变量
choose(UIButton)
:查询当前进程中该类型的对象。
四、 Cycript 高级用法
Cy文件
Cycript是一门脚本语言,它可以加载封装好的.cy文件。
我们会将常见的Cycript常用功能封装到.cy文件中,便于调试。非越狱中导入.cy文件
利用MonkeyDev工具导入.cy文件,MonkeyDev本身集成了Cycript。我们只需要将.cy文件通过xcode导入Framworks目录即可。(操作如上面3.1)
4.1 封装.cy文件
- Home文件夹中创建常用的Shell文件夹
LCJShell
- 创建
cyConnect.sh
用于连接手机
cd LCJShell
vi cyConnect.sh
cycript -r 192.168.6.30:6666
- 在/.zshrc配置环境变量,让
cyConnect.sh
在任何目录环境都可以使用
-
source ~/.zshrc
重新加载即可使用 -
sh cyConnect.sh
执行连接手机
4.2 修改界面上的数据
cy# choose(UILabel)
cy# #0x15adcbd60.text = @"¥999999.99"
使用Debug View Hierarchy查看界面上的控件指针最方便
4.2 封装.cy文件并配置到项目中供调试时使用
- 创建
differ.cy
文件,添加如下代码
// IIFE 匿名函数自执行表达式
(function(exports){
APPID = [NSBundle mainBundle].bundleIdentifier,
APPPATH = [NSBundle mainBundle].bundlePath,
APPHOME = NSHomeDirectory(),
//如果有变化,就用function去定义!!
CJRootvc = function(){
return UIApp.keyWindow.rootViewController;
};
CJPviews = function(){
return UIApp.keyWindow.recursiveDescription().toString();
};
CJPvcs = function(){
return UIWindow.keyWindow().rootViewController._printHierarchy().toString();
};
CJKeyWindow = function(){
return UIApp.keyWindow;
};
CJGetCurrentVCFromRootVc = function(rootVC){
var currentVC;
if([rootVC presentedViewController]){
rootVC = [rootVC presentedViewController];
}
if([rootVC isKindOfClass:[UITabBarController class]]){
currentVC = CJGetCurrentVCFromRootVc(rootVC.selectedViewController);
}else if([rootVC isKindOfClass:[UINavigationController class]]){
currentVC = CJGetCurrentVCFromRootVc(rootVC.visibleViewController);
}else{
currentVC = rootVC;
}
return currentVC;
};
CJCurrentVC = function(){
return CJGetCurrentVCFromRootVc(CJRootvc());
};
})(exports);
- 将
differ.cy
拖到项目中
- 将
differ.cy
拷贝到APP包内Frameworks中
- 重新运行项目并连接手机:
@import differ
表示引入自定义的.cy文件