美文网首页iOS 逆向工程 app安全 网络安全
lldb调试和chisel、DerekSelander、cycr

lldb调试和chisel、DerekSelander、cycr

作者: 妖精的菩萨 | 来源:发表于2018-12-20 14:43 被阅读4次

    0x01 LLDB

    Xcode 5发布之后,LLDB调试器已经取代了GDB,成为了Xcode工程中默认的调试器。它与LLVM编译器一起,带给我们更丰富的流程控制和数据检测的调试功能。LLDB为Xcode提供了底层调试环境,其中包括内嵌在Xcode IDE中的位于调试区域的控制面板,在这里我们可以直接调用LLDB命令。

    基础语法

    <command> [<subcommand> [<subcommand>...]] <action> [-options [option-value]] [argument [argument...]]
    
    • commandsubcommand:LLDB调试命令的名称。
    • action:执行命令的操作。
    • options:命令的选项。
    • arguement:命令的参数。
    • []:表示命令是可选的。可有可无。

    例:

    breakpoint set -n test
    

    command: breakpoint 表示断点命令
    action: set 表示设置断点
    option: -n 表示根据方法name设置断点
    arguement: test 表示方法名为test

    基础命令

    • 通过help命令查看相关lldb指令描述
    (lldb) help
    Debugger commands:
      apropos           -- List debugger commands related to a word or subject.
      breakpoint        -- Commands for operating on breakpoints (see 'help b' for
                           shorthand.)
      bugreport         -- Commands for creating domain-specific bug reports.
      command           -- Commands for managing custom LLDB commands.
      disassemble       -- Disassemble specified instructions in the current
                           target.  Defaults to the current function for the
                           current thread and stack frame.
      expression        -- Evaluate an expression on the current thread.  Displays
                           any returned value with LLDB's default formatting.
      frame             -- Commands for selecting and examing the current thread's
                           stack frames.
    
    • 通过apropos命令获取具体命令的合法参数及含义
    (lldb) apropos bt
    The following commands may relate to 'bt':
      _regexp-bt -- Show the current thread's call stack.  Any numeric argument
                    displays at most that many frames.  The argument 'all' displays
                    all threads.
      bt         -- Show the current thread's call stack.  Any numeric argument
                    displays at most that many frames.  The argument 'all' displays
                    all threads.
    
    • 一些小指令
      c/continue: 继续执行
      po:expression命令选项:-O 表示调用对象的discraption方法
      up: 往上走。
      n:单步往下走。将子函数当做整体一步执行。
      s: 单步运行,遇到子函数会进去。
      ni: 单步执行会跳转到指令内部,汇编级别。
      finish:返回上层调用栈。
      bt: 查看当前调用的堆栈信息。
      thread return:回滚。会改变代码执行流程。
      frame select 3:查看某个堆栈信息。
      image list:查看某块列表。
      register read:读取寄存器。
      register write:写入寄存器。
      Memory read:读取内存值。
      frame variable:可以打印当前方法的所有参数变量。frame表示帧。
    (lldb) frame select 3
    frame #3: 0x000000010af838e8 UIKitCore`forwardTouchMethod + 353
    UIKitCore`forwardTouchMethod:
        0x10af838e8 <+353>: movq   -0x68(%rbp), %rdi
        0x10af838ec <+357>: movq   0x865bc5(%rip), %rbx      ; (void *)0x00000001076a0010: objc_release
        0x10af838f3 <+364>: callq  *%rbx
        0x10af838f5 <+366>: movq   -0x70(%rbp), %rdi
    

    断点相关

    • 通过函数名设置断点
    (lldb) breakpoint set -name action1
    Breakpoint 1: no locations (pending).
    WARNING:  Unable to resolve breakpoint to any actual locations.
    (lldb) br list
    Current breakpoints:
    1: name = 'action1', locations = 0 (pending)
    
    • 设置OC方法断点。
    breakpoint set -n "[ViewController action1:]"
    

    可同时设置多个。就可以同时启用或者禁用某一组。

    (lldb)breakpoint set -n "[ViewController action1:]" -n "[ViewController action2:]" -n "[ViewController action3:]
    
    (lldb) br list
     Current breakpoints:
     1: names = {'[ViewController action1]', '[ViewController action1]', '[ViewController action2]', '[ViewController action2]', '[ViewController action3]', '[ViewController action3]'}, locations = 3, resolved = 3, hit count = 0
     1.1: where = LLDB`-[ViewController action1] + 12 at ViewController.m:42, address = 0x000000010a48f60c, resolved, hit count = 0
     1.2: where = LLDB`-[ViewController action2] + 12 at ViewController.m:45, address = 0x000000010a48f61c, resolved, hit count = 0
     1.3: where = LLDB`-[ViewController action3] + 12 at ViewController.m:48, address = 0x000000010a48f62c, resolved, hit count = 0
    
    • 禁用或者启用某一组。(也可以禁用1.1)
    breakpoint disable 1
    
    breakpoint enable 1
    
    • 删除某一组。(只能以组为单位的删除)
    breakpoint delete 1
    

    下面这样只能达到禁用效果

    breakpoint delete 1.1
    
    • 给项目中所有某个方法设置断点,适合自定义方法。
    breakpoint set --selector viewDidLoad
    
    • 给某个文件或者某个方法设置断点
    br set --file ViewController.m --selector action1:
    
    • 给系统所有带有某个字符串的方法设置断点。
    br set -r xxx
    
    • 删除断点
    breakpoint delete
    br delete
    
    • 内存断点。类似于KVO,可以监听某块内存区域值的变化。
    //监听p1对象中的name字段的内存区域。
    watchpoint set variable p1->_name
    

    也可以直接表达为具体的地址。

    p &p1->_name
    watchpoint set expression 0x0000600002d21c68
    

    进阶用法

    • command指令。通过指令给断点处添加额外指令的实现。
    (lldb) breakpoint command add 1
    Enter your debugger command(s).  Type 'DONE' to end.
    > frame variable
    > DONE
    

    当截住断点时,便会打印相关的指令。


    • hook指令。同上,只是针对每个断点生效。每次截住断点,打印配置好的指令。这里指令一般是通用命令。
    target stop-hook add -o "frame variable"
    

    补充:

    lldb有一个初始化文件.lldbinit,通过在文件中配置相关指令,使用lldb截住的断点都可以执行相关指令。

    操作步骤:

    1、vim ~/.lldbinit,进入配置文件。
    2、进入编辑模式,将target stop-hook add -o "frame variable"命令输入其中。保存即可生效。
    3、在Xcode代码中设置断点,截住时便会打印frame variable的方法参数信息。

    0x02 chisel

    chiselfacebook利用llbd官方的api,用脚本实现了一些特定的功能。

    安装

    通过Homebrew进行安装

    brew update
    brew install chisel
    

    vim ~/.lldbinit修改lldb初始化文件,将chisel的脚本文件的替身地址加入其中

    command script import /usr/local/Cellar/chisel/1.8.0/libexec/fblldb.py
    

    重启Xcode,即可使用。

    常用命令概览

    • 打印视图层级
    (lldb) pviews 0x170391b90
    <UIView: 0x170391b90; frame = (0 20; 320 633); autoresize = W; layer = <CALayer: 0x170a23960>>
       | <UIImageView: 0x1701ffd00; frame = (0 -20; 320 568); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x170a235e0>>
    
    • 打印视图上级
     pviews -u 0x17438fe50
    
    • 打印整个界面的层级关系
    pviews
    
    • 查看响应者链
    presponder 0x150867780
    
    • 查看按钮绑定的事件
    (lldb) pactions 0x150867780
    <WCAccountLoginControlLogic: 0x174a915d0>: onFirstViewRegester
    
    • 查看按钮的继承关系
    (lldb) pclass 0x150867780
    FixTitleColorButton
       | UIButton
       |    | UIControl
       |    |    | UIView
       |    |    |    | UIResponder
       |    |    |    |    | NSObject
    
    • 列出某个对象的方法列表
    (lldb) pmethods 0x14f787f20
    Class Methods:
    No methods were found
    
    • 打印对象的所有属性及属性值。
     pinternals 0x136a11200
    
    • 根据控制器的名称找到这个名称当前所有的地址。
    (lldb) fvc WCAccountMainLoginViewController
    0x136a11200 WCAccountMainLoginViewController
    //根据地址显示控制器信息。
    (lldb) fvc -v 0x136a11200
    Found the owning view controller.
    <WCAccountMainLoginViewController: 0x136a11200>
    
    • 快速定位到某个组件。

    taplogcontinue,点击页面的某个控件,便会自动打印控件的相关信息。

    (lldb) taplog 
    Process 2388 resuming
    <WCUITextField: 0x136685ee0; baseClass = UITextField; frame = (10 0; 217 44); text = ''; clipsToBounds = YES; opaque = NO; gestureRecognizers = <NSArray: 0x170a5fdd0>; layer = <CALayer: 0x1708320e0>>
    
    • 闪烁一次控件,方便开发者定位控件。
    flicker 0x1378b2880
    
    • 动态查看控件相关信息.

    enter之后,输入相关的指令可查看对应的一些控件信息,并且会给控件更改backgroundColor来标注控件。

    (lldb) vs 0x1378b2880 
    Use the following and (q) to quit.
    (w) move to superview   找到父控件。
    (s) move to first subview   找到第一个subview
    (a) move to previous sibling  向前移动
    (d) move to next sibling  向后移动。
    (p) print the hierarchy  打印层级
    

    0x03 DerekSelander

    安装

    点击DerekSelander下载脚本文件。通过在.lldbinit中完成配置即可使用。

    常见命令

    • 查找UIImageView的对象。
    search UIImageView   
    <_UINavigationBarBackIndicatorView: 0x1703e0d00; frame = (8 11.5; 13 21); alpha = 0; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x170837c00>>
    <UIImageView: 0x1703e0900; frame = (0 0; 130 47); clipsToBounds = YES; hidden = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x17023e420>>
    <UIImageView: 0x1743ebf00; frame = (0 501.5; 320 2.5); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x17522a3a0>>
    <UIImageView: 0x1701fe500; frame = (0 64; 320 0); hidden = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x170635ba0>>
    
    • 列出某个类所有的方法和属性。(方法后面的地址为imp的地址。)
    (lldb) methods 0x174897200
    <WCAccountLoginControlLogic: 0x174897200>:
    in WCAccountLoginControlLogic:
        Properties:
            @property (readonly) unsigned long hash;
            @property (readonly) Class superclass;
            @property (readonly, copy) NSString* description;
            @property (readonly, copy) NSString* debugDescription;
        Instance Methods:
            - (void) startLogic; (0x102565bdc)
            - (void) stopLogic; (0x102566144)
            - (void) onOneClickLoginSwitchAccount; (0x1025669d4)
            - (void) onOneClickLoginProblem; (0x102566a08)
            - (void) onOneClickLoginGoToSecurityCenter; (0x102566a40)
            - (void) onOneClickLoginGoToHelpCenter; (0x102566a78)
    
    • 通过内存地址给方法下断点。
    (lldb) b -a 0x1025662c0
    Breakpoint 1: where = WeChat`___lldb_unnamed_symbol142407$$WeChat, address = 0x00000001025662c0
    
    • 通过sbt查看函数调用栈、并得到去符号后的信息。
    (lldb)sbt
    frame #0 : 0x1025662c0 WeChat`-[WCAccountLoginControlLogic onFirstViewLogin] 
    frame #1 : 0x187970d34 UIKit`-[UIApplication sendAction:to:from:forEvent:] + 96
    frame #2 : 0x1030de4e0 WeChat`___lldb_unnamed_symbol189001$$WeChat ... unresolved womp womp + 460
    frame #3 : 0x187959e48 UIKit`-[UIControl _sendActionsForEvents:withEvent:] + 612
    

    0x04 cycript

    cycript是一个允许开发者使用OCJS结合语法查看及修改运行时App内存信息的工具,通过它我们可以注入程序、查看程序界面、调用程序函数验证自己的想法等。同lldb不同、当开始使用cycript时它会常驻内存,所以也更方便我们去动态调试。

    配置安装

    1、在~/.zshrc文件中链接bash_profile.

    source .bash_profile
    

    2、在官网中下载SDK文件。在bash_profile中配置dycript

    3、安装完成,通过cycript命令即可进入cycript界面了。

    界面调试

    通过MonkeyDev运行重签应用,通过查看自动生成的动态库文件,我们可得到对应的端口号。

    查看手机IP,通过cycript -r 192.168.0.105:6666连接手机。当出现如下界面,便可以自由调试了。在这里你可以编写OCJS语言、达到对应用程序的调试。

    下面展示一些简单的调试命令:

    • 打印当前UIApplication的信息。
    cy# [UIApplication sharedApplication]
    #"<UIApplication: 0x10ba038e0>"
    
    cy# UIApp
    #"<UIApplication: 0x10ba038e0>"
    
    • 定义一个变量keywindow来保存当前的window,接着便可以通过变量keywindow直接打印有关window的属性。
    cy# var keyWindow = UIWindow.keyWindow()
    #"<iConsoleWindow: 0x10b856e70; baseClass = UIWindow; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x282910540>; layer = <UIWindowLayer: 0x282656340>>"
    
    cy# keyWindow.rootViewController
    #"<MMUINavigationController: 0x10c165e00>"
    
    • 通过#,查看内存地址的详细信息。
    cy# #0x10c165e00
    #"<MMUINavigationController: 0x10c165e00>"
    
    • 拿到某个对象的成员变量的key和value
    cy# *#0x10c165e00
    

    只获取key

    [i for(i in *#0x157f64480)]
    
    • 查看某个类的层级关系;
    #0x157f64480.recursiveDescription()
    

    格式化输出一波:

    #0x157f64480.recursiveDescription().toString()
    
    • 查看当前界面所有为某个类的对象
    cy# choose(UIButton)
    [#"<FixTitleColorButton: 0x157f64480; baseClass = UIButton; frame = (20 18; 130 47); clipsToBounds = YES; opaque = NO; autoresize = RM; layer = <CALayer: 0x170a2f100>>",#"<UIButton: 0x157f6b6d0; frame = (234 20; 86 49); opaque = NO; autoresize = LM; layer = <CALayer: 0x1748284e0>>",#"<FixTitleColorButton: 0x1590af6e0; baseClass = UIButton; frame = (170 18; 130 47); clipsToBounds = YES; opaque = NO; autoresize = LM; layer = <CALayer: 0x170e2ae80>>"]
    
    • 动态修改某个控件的值
    #0x10b1caa00.text="123123"
    "123123"
    

    高级用法:

    因为我们使用的monkeyDev自动链接了两个cy文件,在文件中实现了对某些方法的自定义函数名以方便我们快捷log。


    猴神配置的cy文件的链接:
    MS.cy
    md.cy
    下面简单列举以下文件提到的一些命令:
    • 打印视图层级和控制器层级。
    pviews() 
    pvcs
    
    • 打印对象所绑定的方法。
    cy# pactions(#0x1053163b0)
    "<CustomViewController: 0x1053133f0> showChangeLog:"
    
    • 打印响应链
    cy# rp(#0x1053163b0)
    `<UIButton: 0x1053163b0; frame = (127.5 175; 120 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x1c4039aa0>>
    <UIView: 0x1053205d0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x1c403bd80>>
    <CustomViewController: 0x1053133f0>
    <UIWindow: 0x105313b60; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x1c425bae0>; layer = <UIWindowLayer: 0x1c40394e0>>
    <UIApplication: 0x105406120>
    <AppDelegate: 0x1c002b1a0>`
    
    自定义cy文件,实现自定义命令

    通过借鉴猴神的自定义命令的实现,我们可以完成一些常规命令的自定义,方便使用。

    1、新建名为dyTest.cy文件。编写相关命令。

    更改文件的类型

    2、定义指令名和方法实现。

    //匿名函数自执行表达式
    (function(exports){
    
    
    //这种直接赋值的变量定义适用于不会发生值改变的情况。因为这样在程序加载的时候变量的值就固定了。
    APPID = [NSBundle mainBundle].bundleIdentifier,
    APPPATH = [NSBundle mainBundle].bundlePath,
    
    //如果值有变化,可借鉴于函数实现的方式。
    DyRootvc = function(){
    return UIApp.keyWindow.rootViewController;
    };
    
    
    DyKeyWindow = function(){
    return UIApp.keyWindow;
    };
    
    DyGetCurrentVCFromRootVc = function(rootVC){
    var currentVC;
    if([rootVC presentedViewController]){
    rootVC = [rootVC presentedViewController];
    }
    
    if([rootVC isKindOfClass:[UITabBarController class]]){
    currentVC = DyGetCurrentVCFromRootVc(rootVC.selectedViewController);
    }else if([rootVC isKindOfClass:[UINavigationController class]]){
    currentVC = DyGetCurrentVCFromRootVc(rootVC.visibleViewController);
    }else{
    currentVC = rootVC;
    }
    
    return currentVC;
    };
    
    
    DyCurrentVC = function(){
    return DyGetCurrentVCFromRootVc(DyRootvc());
    };
    
    })(exports);
    //匿名函数自执行表达式
    

    3、copy file 文件,保证其运行时能在Frameworks文件夹中。


    4、实践自定义命令。

    cy# @import dyTest
    {}
    cy# APPID
    @"com.WeChat.signXcode.dyTest"
    cy# APPPATH
    @"/private/var/mobile/Containers/Bundle/Application/D4AA77EB-FC58-4189-84CF-114A9EA2BB1E/dyTest.app"
    cy# DyRootvc()
    #"<MMUINavigationController: 0x14dfd9730>"
    cy# DyKeyWindow()
    #"<iConsoleWindow: 0x14f005a80; baseClass = UIWindow; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x170849f30>; layer = <UIWindowLayer: 0x174420aa0>>"
    cy# DyGetCurrentVCFromRootVc(#0x14dfd9730)
    #"<WCAccountLoginFirstViewController: 0x14ded9e00>"
    cy# DyCurrentVC()
    #"<WCAccountLoginFirstViewController: 0x14ded9e00>"
    

    参考链接

    The LLDB Debugger
    chisel-github
    MonkeyDev
    cycript
    DerekSelander

    相关文章

      网友评论

        本文标题:lldb调试和chisel、DerekSelander、cycr

        本文链接:https://www.haomeiwen.com/subject/akrykqtx.html