iOS逆向

iOS 逆向开发20:LLDB 动态调试

2021-08-30  本文已影响0人  differ_iOSER

iOS 逆向开发 文章汇总

目录

需要补充一个连接

一、LLDB(Low Lever Debug)

默认内置于Xcode中的动态调试工具。标准的 LLDB 提供了一组广泛的命令,旨在与老版本的 GDB 命令兼容。 除了使用标准配置外,还可以很容易地自定义 LLDB 以满足实际需要。LLDB 的官方API文档。

1.1 断点设置

breakpoint set --selector touchesBegan:withEvent::根据selector设置断点
breakpoint set --file ViewController.m --selector touchesBegan:withEvent:

1.2 流程控制

执行代码expression
expression 指令,简写p:打印变量的值
po:打印对象信息, expression命令选项:-O 表示调用对象的discraption方法

image list :镜像列表
b -[xxx xxx] :为实例方法添加断点
x :根据内存地址读取内存中的数据。
register read :读取寄存器中的值
register write 写入寄存器
memory read 读取内存值
help breakpoint :查看命令的帮助文档
bt:打印当前堆栈信息
updownframe 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

链接

  1. 下载LLDB到/opt目录
  2. Open up (or create) ~/.lldbinit
  3. Add the following command to your ~/.lldbinit file: command script import /opt/LLDB/lldb_commands/dslldb.py
  4. 重启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 高级用法

4.1 封装.cy文件

cd LCJShell
vi cyConnect.sh
cycript -r 192.168.6.30:6666

4.2 修改界面上的数据

cy# choose(UILabel)
cy# #0x15adcbd60.text = @"¥999999.99"

使用Debug View Hierarchy查看界面上的控件指针最方便

4.2 封装.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);
上一篇 下一篇

猜你喜欢

热点阅读