美文网首页
19-Cycript

19-Cycript

作者: 深圳_你要的昵称 | 来源:发表于2021-05-29 18:46 被阅读0次

    前言

    本篇文章将介绍逆向实战中经常使用的一门语言 👉 Cycript,它是由Cydia创始人Saurik推出的一款脚本语言Cycript混合了OC、JavaScript语法的解释器,这意味着我们能够在一个命令中使用OC或者JavaScript,甚至两者并用。它能够挂钩正在运行的进程,能够在运行时修改很多东西。

    一、Cycript安装

    Cycript官网,目前最新版本0.9.594。直接下载SDK解压放在/opt目录中👇

    接着在~/.bash_profile~/.zshrc中配置环境变量👇

    export PATH=/opt/cycript_0.9.594/cycript
    

    接着验证一下👇

    cycript
    

    进入cy#表示配置成功。

    ⚠️注意:如果已经安装了Monkey不需要配置和安装cycript了。因为monkey自带了cycript,并且配置环境变量应改为👇

    export CY=/opt/cycript_0.9.594/
    export PATH=/opt/MonkeyDev/bin:$PATH:$CY
    

    二、基本使用

    只要将cycript注入到应用中,我们就可以调用其中的命令了,Monkey重签名注入的时候帮我们注入了,例如我们之前文章15-Hook原理(二)反Hook防护 & MokeyDev
    中的例子MonKeyDemo👇

    app包里面就包含了libcycript.dylib,当Cycript注入到目标应用,应用进程就会调用Cycript的方法,开启相应的端口,以供第三方监听。第三方可通过端口链接进程,进入cy环境,HOOK当前进程中的内存数据

    2.1 进入Cycript环境

    cycript
    

    2.2 退出Cycript环境

    control + d
    

    2.3 附加进程

    连接进程进入Cycript环境,例如👇

    cycript -r 192.168.3.127:6666
    

    这里手机和电脑要在同一wifi,并且进入应用程序进程。ip为手机的ip。端口号默认为6666

    2.4 cycript调试命令

    以上附加进程链接好了后,就可以使用cycript调试命令查看信息了,例如👇

    • 获取keyWindow
    UIWindow.keyWindow()
    -------------------------
    #"<iConsoleWindow: 0x125f560b0; baseClass = UIWindow; frame = (0 0; 414 736); gestureRecognizers = <NSArray: 0x283f09680>; layer = <UIWindowLayer: 0x283179fc0>>"
    
    • 获取UIApplication单例对象
    UIApp
    -------------------------
    #"<UIApplication: 0x14aa16c80>"
    
    • 定义变量并赋值
    var keyWd = UIWindow.keyWindow()
    -------------------------
    #"<iConsoleWindow: 0x125f560b0; baseClass = UIWindow; frame = (0 0; 414 736); gestureRecognizers = <NSArray: 0x283f09680>; layer = <UIWindowLayer: 0x283179fc0>>"
    
    keyWd.rootViewController
    -------------------------
    #"<MMUINavigationController: 0x1270e9200> ChildViewControllers:(\n    \"<WCAccountLoginFirstViewController: 0x1270d7600>\"\n)"
    

    当程序的进程结束,定义的所有变量一起释放

    1. #对象地址 👉 拿到该对象,可用于调用方法
    #0x1270e9200
    -------------------------
    #"<MMUINavigationController: 0x1270e9200> ChildViewControllers:(\n    \"<WCAccountLoginFirstViewController: 0x1270d7600>\"\n)"
    
    1. *对象 👉 可以取出对象的成员变量
    *keyWd
    -------------------------
    {isa:iConsoleWindow,_responderFlags:@error,_constraintsExceptingSubviewAutoresizingConstraints:null,...
    
    • 查看视图结构
    keyWd.recursiveDescription()
    -------------------------
    @"<iConsoleWindow: 0x125f560b0; baseClass = UIWindow; frame = (0 0; 414 736); gestureRecognizers = <NSArray: 0x283f09680>; layer = <UIWindowLayer: 0x283179fc0>>\n   | <UITransitionView: 0x125f51960; frame = (0 0; 414 736); autoresize = W+H; layer = <CALayer: 0x28317a500>>\n...
    

    也可格式化打印,遇\n换行👇

    keyWd.recursiveDescription().toString()
    -------------------------
    `<iConsoleWindow: 0x125f560b0; baseClass = UIWindow; frame = (0 0; 414 736); gestureRecognizers = <NSArray: 0x283f09680>; layer = <UIWindowLayer: 0x283179fc0>>
      | <UITransitionView: 0x125f51960; frame = (0 0; 414 736); autoresize = W+H; layer = <CALayer: 0x28317a500>>
      |    | <UIDropShadowView: 0x125f59770; frame = (0 0; 414 736); autoresize = W+H; layer = <CALayer: 0x28317a680>>
      |    |    | <UILayoutContainerView: 0x125e71790; frame = (0 0; 414 736); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x283f0ff90>; layer = <CALayer: 0x283140140>>
      |    |    |    | <UINavigationTransitionView: 0x125e7a190; frame = (0 0; 414 736); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x283140360>>
      |    |    |    |    | <UIViewControllerWrapperView: 0x125f37540; frame = (0 0; 414 736); autoresize = W+H; layer = <CALayer: 0x28315abc0>>
    ...
    
    • 查询当前进程指定类型对象
    choose (UIButton)
    -------------------------
    [#"<FixTitleColorButton: 0x125e2b280; baseClass = UIButton; frame = (20 18; 177 47); clipsToBounds = YES; opaque = NO; autoresize = RM; layer = <CALayer: 0x2831463c0>>",#"<FixTitleColorButton: 0x125e55b20; baseClass = UIButton; frame = (217 18; 177 47); clipsToBounds = YES; opaque = NO; autoresize = LM; layer = <CALayer: 0x283138820>>",...
    

    这和LLDBsearch很像。

    三、进阶

    3.1 脚本自动连接

    1. 创建cyShell目录
    2. cyShell目录下,创建cyConnect.sh脚本
    3. 打开cyConnect.sh脚本,写入以下代码👇
    cycript -r 10.165.44.19:6666
    
    1. 增加可执行权限👇
    chmod +x cyConnect.sh
    
    1. 配置环境变量👇
    export cyShell=/Users/Aron/cyShell/
    export PATH=/opt/MonkeyDev/bin:$cyShell:$PATH
    

    这样能全局使用👇

    cyConnect.sh
    cy#
    

    直接就能自动连接了。

    3.2 Cycript 修改内存

    接下来通过几个案例,使用Cycript脚本,看看如何修改内存。

    案例一:修改应用图标的红点数
    1. 使用MonkeyDev安装并运行wx8.0.2.ipa
    2. 使用cyConnect.sh附加进程
    3. 修改BadgeString👇
    [UIApp setApplicationBadgeString: @"999"]
    

    ⚠️注意:修改当前内存中的数据,应用重复挂起唤醒,数据就会被刷新。

    案例二:修改红包金额

    例如:正常的红包内容如下👇

    1. 首先通过choose(UILabel)找到红包金额👇
    choose(UILabel).toString()
    

    搜索1.00得到地址0x149eaef00👇

    1. 修改红包的金额👇
    cy# #0x149eaef00.text = @"¥88888888.00"
    

    同样的方式,找到借款UILabel的地址 0x14c33b460,将text改为还款👇

    cy# #0x14c33b460.text = @"还款"
    
    1. 修改后的内容👇
    案例三:修改聊天内容

    有2种方式👇

    1. 通过cycript搜索控件进行修改
    2. 通过Xcodeview debug找到控件进行修改

    可以看到内容在accessibilitydescription中👇

    接着我们在logos文件夹下的.xm文件中,使用logos语法hook方法,代码如下👇

    %hook RichTextView
    
    - (_Bool)setPrefixContent:(id)arg1 TargetContent:(NSString *)arg2 TargetParserString:(id)arg3 SuffixContent:(id)arg4 {
    //    arg2 为文案
        if([arg2 isEqualToString:@"钱已经借给你了。"]) {
            arg2 = @"钱已经换给你了,请查收!";
        }
        return %orig;
    }
    
    %end
    

    至此整个内容就修改完成了👇

    3.3 高级用法

    • 获取bundle identifier
      使用APPID命令👇
    cy# APPID
    -------------------------
    @"com.xxxxxx.MonKeyDemo"
    
    • 获取视图层级
      使用pviews()命令👇
    pviews()
    -------------------------
    `<iConsoleWindow: 0x113790b60; baseClass = UIWindow; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x2811ce0d0>; layer = <UIWindowLayer: 0x281f12020>>
       | <UITransitionView: 0x113797170; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x281f13120>>
       |    | <UIDropShadowView: 0x113798100; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x281f13240>>
       |    |    | <UILayoutContainerView: 0x113793ba0; frame = (0 0; 375 667); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x2811cf060>; layer = <CALayer: 0x281f124c0>>
       |    |    |    | <UINavigationTransitionView: 0x1137950f0; frame = (0 0; 375 667); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x281f12760>>
       |    |    |    |    | <UIViewControllerWrapperView: 0x11378b1d0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x281fd9400>>
       |    |    |    |    |    | <UIView: 0x113794990; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x281fe8180>>
       |    |    |    |    |    |    | <UIView: 0x113793980; frame = (0 20; 375 732); autoresize = W; layer = <CALayer: 0x281fe8ac0>>
       |    |    |    |    |    |    |    | <UIImageView: 0x113316830; frame = (0 -20; 375 667); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x281fec780>>
       |    |    |    |    |    |    | <UIView: 0x113316140; frame = (0 582; 375 65); autoresize = W+TM; layer = <CALayer: 0x281fecc60>>
       |    |    |    |    |    |    |    | <FixTitleColorButton: 0x113306f70; baseClass = UIButton; frame = (20 18; 157.5 47); clipsToBounds = YES; opaque = NO; autoresize = RM; layer = <CALayer: 0x281fecea0>>
       |    |    |    |    |    |    |    |    | <UIButtonLabel: 0x113328f90; frame = (60.5 12.5; 37 22); text = '\u767b\u5f55'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x283c4acb0>>
       |    |    |    |    |    |    |    | <FixTitleColorButton: 0x1137562e0; baseClass = UIButton; frame = (197.5 18; 157.5 47); clipsToBounds = YES; opaque = NO; autoresize = LM; layer = <CALayer: 0x281fc70a0>>
       |    |    |    |    |    |    |    |    | <UIButtonLabel: 0x1137590e0; frame = (60.5 12.5; 37 22); text = '\u6ce8\u518c'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x283c46710>>
       |    |    |    |    |    |    | <UIButton: 0x11375a080; frame = (287 20; 88 49); opaque = NO; autoresize = LM; layer = <CALayer: 0x281fc72e0>>
       |    |    |    |    |    |    |    | <UIButtonLabel: 0x113762910; frame = (15 16; 58 17); text = '\u7b80\u4f53\u4e2d\u6587'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x283c46850>>
       |    |    |    | <MMUINavigationBar: 0x113793d20; baseClass = UINavigationBar; frame = (0 20; 375 44); opaque = NO; autoresize = W; layer = <CALayer: 0x281f124e0>>
       |    |    |    |    | <_UIBarBackground: 0x113794170; frame = (0 -20; 375 64); userInteractionEnabled = NO; layer = <CALayer: 0x281f12560>>
       |    |    |    |    |    | <UIImageView: 0x11378df60; frame = (0 0; 375 64); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x281fd9a80>>
       |    |    |    |    |    | <_UIBarBackgroundShadowView: 0x1137957a0; frame = (0 64; 375 0); layer = <CALayer: 0x281f129a0>> clientRequestedContentView effect=none
       |    |    |    |    |    |    | <_UIBarBackgroundShadowContentImageView: 0x113795b10; frame = (0 0; 375 0); opaque = NO; autoresize = W+H; userInteractionEnabled = NO; layer = <CALayer: 0x281f12a60>>
       |    |    |    |    | <_UINavigationBarContentView: 0x113794350; frame = (0 0; 375 44); layer = <CALayer: 0x281f12580>> layout=0x1137945d0
       |    |    |    |    |    | <_UITAMICAdaptorView: 0x11378e920; frame = (187 4; 1 36); autoresizesSubviews = NO; layer = <CALayer: 0x281fe81a0>>
       |    |    |    |    |    |    | <MMTitleView: 0x113338b90; frame = (0 0; 1 36); layer = <CALayer: 0x281f36fa0>>
       |    |    |    |    |    |    |    | <MMUILabel: 0x1133382f0; baseClass = UILabel; frame = (0 0; 0 36); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x283c48a00>>
       |    |    |    |    | <UIView: 0x11373a720; frame = (0 44; 375 0.5); hidden = YES; autoresize = W+TM; layer = <CALayer: 0x281f5a3a0>>
       |    |    |    |    | <UIView: 0x1137903d0; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <CALayer: 0x281f127a0>>`
    

    也可以查看pviews方法代码实现👇

    pviews
    -------------------------
    function (){return UIApp.keyWindow.recursiveDescription().toString()}
    
    • 获取视图控制器
      使用pvcs()命令👇
    cy# pvcs()
    -------------------------
    "<MMUINavigationController 0x11396f600>, state: appeared, view: <UILayoutContainerView 0x113793ba0>\n   | <WCAccountLoginFirstViewController 0x11400fa00>, state: appeared, view: <UIView 0x113794990>"
    

    pvcs方法的代码实现👇

    pvcs
    -------------------------
    function (){return UIWindow.keyWindow().rootViewController._printHierarchy().toString()}
    

    上面这些功能,Cycript脚本也有,但是这些命令却不是Cycript自带的,那么它们是哪里来的呢?

    在Monkey工程我们可以在Config->MDConfig.plist中发现Cycript下有msmd两个.cy文件👇

    这些命令就封装在这两个文件中(工程运行的时候自动从网络上下载)。
    ms.cy
    md.cy

    使用Cycript找到指定控制器某个控件,过程比较繁琐
    更好的方式 👉 在非越狱设备上,使用应用重签名,通过Debug View Hierarchy快速定位控件,找到对应的地址,然后使用Cycript对其进行修改

    四、cy文件的封装

    案例一:封装简单案例
    1. MokeyDemo项目中,创建test.cy文件
    2. 打开test.cy文件,写入以下代码👇
    sum = function(a,b){
       return a + b;
    }
    
    1. test.cy文件拖入项目,在MokeyDemo项目中,使用Copy Files添加test.cy👇

    ⚠️注意:test.cy是脚本文件,不是MachO不需要勾选签名

    1. 重新运行项目,使用cyConnect.sh附加进程

    2. 导入脚本👇

    @import test
    -------------------------
    {}
    

    调用sum方法👇

    sum(10,20)
    -------------------------
    30
    
    案例二:实现获取当前控制器
    1. 修改test.cy文件的代码👇
    (function(exports){
       APPID = [NSBundle mainBundle].bundleIdentifier,
       APPPATH = [NSBundle mainBundle].bundlePath,
       APPHOME = NSHomeDirectory(),
    
       rootVC = function(){
           return UIApp.keyWindow.rootViewController;
       };
    
       keyWindow = function(){
           return UIApp.keyWindow;
       };
    
       getCurrentVC = function(rootVC){
    
           var currentVC;
           if([rootVC presentedViewController]){
               rootVC = [rootVC presentedViewController];
           }
    
           if([rootVC isKindOfClass:[UITabBarController class]]){
               currentVC = getCurrentVC(rootVC.selectedViewController);
           }
           else if([rootVC isKindOfClass:[UINavigationController class]]){
               currentVC = getCurrentVC(rootVC.visibleViewController);
           }
           else{
               currentVC = rootVC;
           }
    
           return currentVC;
       };
    
       currentVC = function(){
           return getCurrentVC(rootVC());
       };
    
    })(exports);
    
    
    1. 重新运行项目,使用cyConnect.sh附加进程
    2. 同样导入脚本👇
    @import test
    -------------------------
    {}
    
    1. 调用方法👇
    • 获取APPID
    APPID
    -------------------------
    @"com.xxxxxx.MokeyDemo"
    
    • 获取APPPATH
    APPPATH
    -------------------------
    @"/private/var/containers/Bundle/Application/D620C178-5030-48E4-9276-981150FF7299/MokeyDemo.app"
    
    • 获取APPHOME
    APPHOME
    -------------------------
    @"/var/mobile/Containers/Data/Application/C2ED1E99-47C4-4C29-8AE6-9C5C136CEE04"
    
    • 调用currentVC()
    currentVC()
    -------------------------
    #"<WCAccountLoginFirstViewController: 0x14b0b4200>"
    

    总结

    • Cycipt
      • 是一种脚本语言,兼容了多种语法(支持多种语法的解释器
      • Cycipt可以附加到进程,用来动态调试
        • 也可自定义脚本配置环境变量中,方便执行
      • 将常用功能封装为.cy文件

    相关文章

      网友评论

          本文标题:19-Cycript

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